Skip to content

Commit

Permalink
Add threshold_factor()
Browse files Browse the repository at this point in the history
  • Loading branch information
mhostetter committed Jul 25, 2024
1 parent cc59939 commit 0ffce3b
Showing 1 changed file with 77 additions and 0 deletions.
77 changes: 77 additions & 0 deletions src/sdr/_detection/_theory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import scipy.stats
from typing_extensions import Literal

from .._conversion import db as to_db
from .._conversion import linear
from .._helper import (
convert_output,
Expand Down Expand Up @@ -915,6 +916,82 @@ def _calculate(p_fa, sigma2):
return convert_output(threshold)


@export
def threshold_factor(
p_fa: npt.ArrayLike,
detector: Literal["coherent", "linear", "square-law"] = "square-law",
complex: bool = True,
n_c: int = 1,
n_nc: int | None = None,
db: bool = False,
) -> npt.NDArray[np.float64]:
r"""
Computes the theoretical detection threshold factor $\alpha$.
Arguments:
p_fa: The desired probability of false alarm $P_{fa}$ in $(0, 1)$.
detector: The detector type.
- `"coherent"`: A coherent detector, $$T(x) = \mathrm{Re}\left\{\sum_{i=0}^{N_c-1} x[n-i]\right\} .$$
- `"linear"`: A linear detector, $$T(x) = \sum_{j=0}^{N_{nc}-1}\left|\sum_{i=0}^{N_c-1} x[n-i-jN_c]\right| .$$
- `"square-law"`: A square-law detector, $$T(x) = \sum_{j=0}^{N_{nc}-1}\left|\sum_{i=0}^{N_c-1} x[n-i-jN_c]\right|^2 .$$
complex: Indicates whether the input signal is real or complex. This affects how the SNR is converted
to noise variance.
n_c: The number of samples to coherently integrate $N_c$.
n_nc: The number of samples to non-coherently integrate $N_{nc}$. Non-coherent integration is only allowable
for linear and square-law detectors.
db: Indicates whether to return the detection threshold $\alpha$ in dB.
Returns:
The detection threshold factor $\alpha$.
Notes:
The detection threshold factor $\alpha$ is defined as the ratio of the detection threshold $\gamma$ to the
mean of the detector output under the null hypothesis. This is true for linear and square-law detectors.
$$\alpha = \frac{\gamma}{\frac{1}{N} \sum_{i=1}^{N}\{T(x[i]) \mid \mathcal{H}_0\}}$$
For coherent detectors, the detection threshold factor $\alpha$ is defined as the ratio of the detection
threshold $\gamma$ to the mean of the square of the detector output under the null hypothesis.
This is required because the mean of the coherent detector output is zero.
$$\alpha = \frac{\gamma}{\frac{1}{N} \sum_{i=1}^{N}\{T(x[i])^2 \mid \mathcal{H}_0\}}$$
Examples:
.. ipython:: python
p_fa = np.logspace(-16, -1, 101) # Probability of false alarm
@savefig sdr_threshold_factor_1.png
plt.figure(); \
plt.semilogx(p_fa, sdr.threshold_factor(p_fa, detector="coherent"), label="Coherent"); \
plt.semilogx(p_fa, sdr.threshold_factor(p_fa, detector="linear"), label="Linear"); \
plt.semilogx(p_fa, sdr.threshold_factor(p_fa, detector="square-law"), label="Square-Law"); \
plt.xlabel("Probability of false alarm, $P_{fa}$"); \
plt.ylabel(r"Detection threshold factor, $\alpha$"); \
plt.legend(title="Detector"); \
plt.title("Detection threshold factor across false alarm rate");
Group:
detection-theory
"""
sigma2 = 1
gamma = threshold(p_fa, sigma2, detector, complex, n_c, n_nc)
null_hypothesis = h0(sigma2, detector, complex, n_c, n_nc)

if detector == "coherent":
# Since mean is zero, the variance is equivalent to the mean of the square
alpha = gamma / null_hypothesis.var()
else:
alpha = gamma / null_hypothesis.mean()

if db:
alpha = to_db(alpha)

return alpha


@export
def min_snr(
p_d: npt.ArrayLike,
Expand Down

0 comments on commit 0ffce3b

Please sign in to comment.