File detection_core.h¶
FileList > detection > detection_core.h
Go to the source code of this file
Detection-theory utilities for the amplitude-ratio test statistic. More...
Public Functions¶
| Type | Name |
|---|---|
| int | det_dwell (double snr, double pd_min, double pfa, int max_dwell) Minimum dwell such that Pd >= pd_min for the given SNR and Pfa. |
| int | det_dwell_power (double snr_power, double pd_min, double pfa, int max_dwell) Minimum dwell such that Pd >= pd_min for the power detector. |
| int | det_n_noncoh (double snr, int n_coh, double pd_min, double pfa, int max_n_noncoh) Minimum non-coherent looks achieving Pd >= pd_min at fixed n_coh. |
| double | det_pd (double snr, int dwell, double threshold) Detection probability for given per-sample amplitude SNR and dwell. |
| double | det_pd_noncoherent (double snr, int n_coh, int n_noncoh, double threshold) Detection probability for n_noncoh non-coherent looks. |
| double | det_pd_power (double snr_power, int dwell, double power_threshold) Detection probability for the power detector. |
| double | det_snr (int dwell, double pd_min, double pfa) Minimum per-sample amplitude SNR achieving Pd >= pd_min. |
| double | det_snr_power (int dwell, double pd_min, double pfa) Minimum per-sample power SNR achieving Pd >= pd_min. |
| double | det_threshold (double pfa) Threshold eta for a given false-alarm probability. |
| double | det_threshold_noncoherent (double pfa, int n_noncoh) CFAR threshold eta_nc for a non-coherent detector of n_noncoh looks. |
| double | det_threshold_power (double pfa) Power threshold p from Pfa for the power detector. |
| double | marcum_q (int m, double a, double b) Marcum Q function Q_M(a, b) for integer M >= 1. |
Detailed Description¶
The doppler detector forms the test statistic:
test_stat = peak_mag / noise_est
With M-point coherent integration (dwell = M) and per-sample amplitude SNR snr (signal amplitude / noise amplitude, linear):
Under H0 (noise only): test_stat ~ Rayleigh(1) Under H1 (signal+noise): test_stat ~ Rice(a, 1), a = sqrt(2*M) * snr
False-alarm probability (threshold-only, M-independent):
Pfa = exp(-eta^2/2) => eta = sqrt(-2 ln Pfa) (exact)
Detection probability:
Pd = Q_1(a, eta) (Marcum Q function, order 1)
All functions are stateless and thread-safe.
Public Functions Documentation¶
function det_dwell¶
Minimum dwell such that Pd >= pd_min for the given SNR and Pfa.
Iterates dwell = 1, 2, ..., max_dwell, computing det_pd() at each step. Returns the first dwell that satisfies the Pd requirement, or -1 if none is found within max_dwell iterations.
Parameters:
snrPer-sample amplitude SNR (linear).pd_minRequired detection probability, e.g. 0.9.pfaFalse-alarm probability; used to derive eta.max_dwellSearch upper bound; prevents infinite loops for low SNR.
Returns:
Minimum dwell >= 1, or -1 if not achievable.
>>> from doppler.detection import det_dwell
>>> det_dwell(snr=0.5, pd_min=0.9, pfa=1e-6, max_dwell=256)
84
function det_dwell_power¶
Minimum dwell such that Pd >= pd_min for the power detector.
Parameters:
snr_powerPer-sample power SNR (linear).pd_minRequired detection probability.pfaFalse-alarm probability; used to derive p.max_dwellSearch upper bound.
Returns:
Minimum dwell >= 1, or -1 if not achievable.
>>> from doppler.detection import det_dwell_power
>>> det_dwell_power(snr_power=0.25, pd_min=0.9, pfa=1e-6, max_dwell=256)
84
function det_n_noncoh¶
Minimum non-coherent looks achieving Pd >= pd_min at fixed n_coh.
Iterates n_noncoh = 1, 2, ..., max_n_noncoh, recomputing the threshold (det_threshold_noncoherent, which grows with the look count) at each step. Returns the first look count that meets the Pd requirement, or -1 if none does within max_n_noncoh. Used by the acquisition engine's (M, N_nc) split.
Parameters:
snrPer-sample amplitude SNR (linear).n_cohCoherent integration length in samples (dwell * N).pd_minRequired detection probability, e.g. 0.9.pfaPer-test false-alarm probability.max_n_noncohSearch upper bound on the look count.
Returns:
Minimum n_noncoh >= 1, or -1 if not achievable.
>>> from doppler.detection import det_n_noncoh
>>> det_n_noncoh(snr=2.0, n_coh=16, pd_min=0.9, pfa=1e-3, max_n_noncoh=64)
1
function det_pd¶
Detection probability for given per-sample amplitude SNR and dwell.
Computes Pd = Q_1(a, eta) where a = sqrt(2 * dwell) * snr.
At snr = 0, det_pd returns Pfa (the false-alarm rate, as expected for a noise-only input). As snr or dwell increase, Pd approaches 1.
Parameters:
snrPer-sample amplitude SNR (signal / noise amplitude, linear). snr = 0 gives Pd = Pfa.dwellCoherent integration depth; must be >= 1.thresholdTest-stat threshold eta, e.g. from det_threshold().
Returns:
Detection probability in [0, 1].
>>> from doppler.detection import det_pd, det_threshold
>>> thr = det_threshold(pfa=1e-6)
>>> round(det_pd(snr=1.613, dwell=8, threshold=thr), 2) # 8-dwell -> Pd~0.9
0.9
>>> round(det_pd(snr=0.0, dwell=8, threshold=thr), 6) # snr=0 -> Pd=Pfa
1e-06
function det_pd_noncoherent¶
Detection probability for n_noncoh non-coherent looks.
Computes Pd = Q_{n_noncoh}(a, threshold) with the non-centrality a = sqrt(2 * n_coh * n_noncoh) * snr. At n_noncoh = 1 this is exactly det_pd(snr, n_coh, threshold); at snr = 0 it returns the per-test Pfa.
Parameters:
snrPer-sample amplitude SNR (signal / noise amplitude).n_cohCoherent integration length in samples (dwell * N).n_noncohNumber of non-coherent looks; must be >= 1.thresholdThreshold eta_nc, e.g. from det_threshold_noncoherent().
Returns:
Detection probability in [0, 1].
>>> from doppler.detection import det_pd_noncoherent, det_pd, det_threshold
>>> from doppler.detection import det_threshold_noncoherent
>>> eta = det_threshold(pfa=1e-6)
>>> det_pd_noncoherent(snr=0.5, n_coh=8, n_noncoh=1, threshold=eta) \
... == det_pd(snr=0.5, dwell=8, threshold=eta) # reduces to coherent
True
>>> eta4 = det_threshold_noncoherent(pfa=1e-3, n_noncoh=4)
>>> round(det_pd_noncoherent(snr=0.3, n_coh=16, n_noncoh=4, threshold=eta4), 2)
0.19
function det_pd_power¶
Detection probability for the power detector.
Pd = Q_1(sqrt(2·dwell·snr_power), sqrt(2·power_threshold))
Parameters:
snr_powerPer-sample power SNR (signal power / noise power at the correlator output, linear). 0 gives Pd = Pfa.dwellCoherent integration depth; must be >= 1.power_thresholdThreshold p, e.g. from det_threshold_power().
Returns:
Detection probability in [0, 1].
>>> from doppler.detection import det_pd_power, det_threshold_power
>>> thr = det_threshold_power(pfa=1e-6)
>>> round(det_pd_power(snr_power=2.6017, dwell=8, power_threshold=thr), 2)
0.9
s corresponds to amplitude SNR sqrt(s), and the Q_1 arguments match.
function det_snr¶
Minimum per-sample amplitude SNR achieving Pd >= pd_min.
Binary search over SNR in [0, hi] where hi is doubled from 1.0 until det_pd(hi, dwell, threshold) >= pd_min. 64 bisection iterations yield ~1e-19 relative precision on the final interval.
Parameters:
dwellCoherent integration depth; must be >= 1.pd_minRequired detection probability.pfaFalse-alarm probability; used to derive eta.
Returns:
Minimum amplitude SNR >= 0.
>>> from doppler.detection import det_snr, det_pd, det_threshold
>>> snr = det_snr(dwell=8, pd_min=0.9, pfa=1e-6)
>>> round(snr, 3)
1.613
>>> det_pd(snr=snr, dwell=8, threshold=det_threshold(pfa=1e-6)) >= 0.9
True
function det_snr_power¶
Minimum per-sample power SNR achieving Pd >= pd_min.
Parameters:
dwellCoherent integration depth; must be >= 1.pd_minRequired detection probability.pfaFalse-alarm probability.
Returns:
Minimum power SNR >= 0.
>>> from doppler.detection import (det_snr_power, det_pd_power,
... det_threshold_power)
>>> sp = det_snr_power(dwell=8, pd_min=0.9, pfa=1e-6)
>>> round(sp, 4)
2.6017
>>> det_pd_power(snr_power=sp, dwell=8,
... power_threshold=det_threshold_power(pfa=1e-6)) >= 0.9
True
function det_threshold¶
Threshold eta for a given false-alarm probability.
Exact closed-form inversion of Pfa = exp(-eta^2/2):
eta = sqrt(-2 * ln(pfa))
The threshold is independent of dwell and SNR; it depends only on the desired Pfa.
Parameters:
pfaDesired false-alarm probability; must be in (0, 1).
Returns:
Threshold eta > 0.
function det_threshold_noncoherent¶
CFAR threshold eta_nc for a non-coherent detector of n_noncoh looks.
Solves marcum_q(n_noncoh, 0, eta_nc) = pfa (the order-M central tail, monotone decreasing in eta_nc) by bisection. For n_noncoh = 1 this is the exact closed form sqrt(-2 ln pfa) (== det_threshold).
Parameters:
pfaPer-test false-alarm probability in (0, 1).n_noncohNumber of non-coherent looks; must be >= 1.
Returns:
Threshold eta_nc on the normalized statistic R.
>>> from doppler.detection import det_threshold_noncoherent, det_threshold
>>> round(det_threshold_noncoherent(pfa=1e-3, n_noncoh=4), 3)
5.111
>>> det_threshold_noncoherent(pfa=1e-6, n_noncoh=1) == det_threshold(pfa=1e-6)
True
function det_threshold_power¶
Power threshold p from Pfa for the power detector.
Exact closed-form: P(Exponential(1) > p) = exp(-p) = Pfa, so
p = -ln(Pfa)
Parameters:
pfaDesired false-alarm probability; must be in (0, 1).
Returns:
Threshold p > 0.
>>> from doppler.detection import det_threshold_power
>>> round(det_threshold_power(pfa=1e-6), 3) # -ln(1e-6) = 6*ln(10)
13.816
function marcum_q¶
Marcum Q function Q_M(a, b) for integer M >= 1.
Probability that a Rice(a, sigma=1) random variable exceeds b. For M=1: Q_1(a, b) = P(Rice(a,1) > b). General integer M relates to the noncentral chi-squared CDF with 2M degrees of freedom.
Computed via the Poisson-weighted chi-squared series (exact for M=1, converges in ~60 terms for practical a, b <= 15):
Q_M(a, b) = sum_{k=0}^inf w_k * Q_{M+k}(0, b)
where: w_k = exp(-u) * u^k/k! (u = a^2/2) Q_n(0,b) = exp(-v) * sum_{j=0}^{n-1} v^j/j! (v = b^2/2)
Each iteration advances both the Poisson weight and the chi-sum in O(1) using the recurrences w_{k+1} = w_k * u/(k+1) and Q_{n+1}(0,b) = Q_n(0,b) + exp(-v)*v^n/n!. Total cost: O(K) where K ~ max(u, M) + safety margin.
Special cases: * a = 0: Q_M(0, b) = exp(-b^2/2) * sum_{j=0}^{M-1} (b^2/2)^j/j! * b <= 0: Q_M(a, b) = 1.0
Parameters:
mIntegration order; must be >= 1.aNon-centrality parameter (signal strength). a = 0 for H0.bThreshold (same units as test_stat).
Returns:
Q_M(a, b) in [0, 1].
>>> from doppler.detection import marcum_q
>>> round(marcum_q(m=1, a=0.0, b=1.0), 5) # P(Rayleigh > 1) = exp(-0.5)
0.60653
>>> round(marcum_q(m=1, a=0.0, b=2.0), 5) # exp(-2)
0.13534
>>> round(marcum_q(m=2, a=0.0, b=2.0), 5) # 3*exp(-2)
0.40601
>>> round(marcum_q(m=1, a=2.0, b=1.0), 5) # signal present (a=2)
0.91811
The documentation for this class was generated from the following file native/inc/detection/detection_core.h