Python SNR API¶
The doppler.snr module provides stateless SNR / Es-N0 estimators over a
block of complex baseband samples, shared across any receiver that needs
one rather than each object growing its own ad hoc formula. Two
independent algorithms, each with a sliding-window _series sibling for
visualizing drift vs time/index instead of reading one block-average
scalar:
snr_data_aided_db— known-symbol estimator. Strip the known transmitted sign, thenEs/N0 = (mean signal amplitude)^2 / (mean residual power). Needs ground truth (or trusted decisions), but is simple, unbiased, scale-invariant, and polarity-invariant (a global sign flip changes nothing, since the amplitude is squared).snr_m2m4_db— non-data-aided (blind), moment-based estimator (Pauluzzi & Beaulieu, "A comparison of SNR estimation techniques for the AWGN channel", IEEE Trans. Commun. 48(10), 2000) for a constant-modulus signal (BPSK/QPSK/M-PSK) in circular complex AWGN. No known symbols needed at all.
Source:
src/doppler/snr/__init__.py
See the
5-Burst DSSS Link gallery page
for both estimators used against a real despread burst, including the
_series sliding-window plot.
>>> import numpy as np
>>> from doppler.snr import snr_data_aided_db, snr_m2m4_db
>>> rng = np.random.default_rng(0)
>>> bits = (rng.random(5000) > 0.5).astype(np.uint8)
>>> sign = np.where(bits, -1.0, 1.0).astype(np.complex64)
>>> noise = (0.3 * (rng.standard_normal(5000)
... + 1j * rng.standard_normal(5000))).astype(np.complex64)
>>> soft = (sign + noise).astype(np.complex64)
>>> round(float(snr_data_aided_db(soft, bits)), 1) # known symbols
7.5
>>> round(float(snr_m2m4_db(soft)), 1) # blind -- agrees, no `bits` needed
7.4
snr_data_aided_db — known-symbol Es/N0¶
snr_data_aided_db
¶
Data-aided Es/N0 (dB): strip the known sign, Es/N0 = a^2 / mean(|z-a|^2).
Strips the known transmitted sign (soft[i] * (sign_bits[i] ? -1 :
1)), then Es/N0 = (mean signal amplitude)^2 / (mean residual power).
Scale-invariant (works regardless of the caller's symbol normalization)
and polarity-invariant (a global sign flip in soft changes nothing,
since the amplitude is squared) -- so it needs no resolution of an
absolute-phase ambiguity a tracking loop may carry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
soft
|
NDArray[complex64]
|
Despread complex symbols. |
required |
sign_bits
|
NDArray[uint8]
|
Known transmitted bits (0/1; 0 -> +1, 1 -> -1). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Es/N0 in dB over |
Examples:
>>> import numpy as np
>>> from doppler.snr import snr_data_aided_db
>>> rng = np.random.default_rng(0)
>>> bits = (rng.random(2000) > 0.5).astype(np.uint8)
>>> sign = np.where(bits, -1.0, 1.0).astype(np.complex64)
>>> noise = (0.1 * (rng.standard_normal(2000)
... + 1j * rng.standard_normal(2000))).astype(np.complex64)
>>> soft = (sign + noise).astype(np.complex64)
>>> round(float(snr_data_aided_db(soft, bits)), 1)
17.1
snr_m2m4_db — blind (M2M4) Es/N0¶
snr_m2m4_db
¶
Non-data-aided moment-based (M2M4) Es/N0 (dB) for a constant-modulus signal in AWGN.
M2M4 estimator (Pauluzzi & Beaulieu 2000) for a constant-modulus signal (BPSK/QPSK/M-PSK) in circular complex AWGN: no known symbols required.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
NDArray[complex64]
|
Complex baseband samples (post-carrier-lock; residual phase does not bias the moment-based estimate). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Es/N0 in dB, 0-linear for pure noise, +inf for a noiseless constant-modulus signal, or NaN if x_len is 0 or the block has zero power. |
Examples:
>>> import numpy as np
>>> from doppler.snr import snr_m2m4_db
>>> rng = np.random.default_rng(0)
>>> bits = (rng.random(2000) > 0.5).astype(np.uint8)
>>> sign = np.where(bits, -1.0, 1.0).astype(np.complex64)
>>> noise = (0.1 * (rng.standard_normal(2000)
... + 1j * rng.standard_normal(2000))).astype(np.complex64)
>>> x = (sign + noise).astype(np.complex64)
>>> round(float(snr_m2m4_db(x)), 1)
17.1
snr_data_aided_db_series — sliding-window known-symbol Es/N0¶
snr_data_aided_db_series
¶
snr_data_aided_db_series(
soft: NDArray[complex64],
sign_bits: NDArray[uint8],
window: int,
) -> NDArray[np.float64]
Sliding-window data-aided Es/N0 (dB) vs index, for visualizing drift.
Same estimator as snr_data_aided_db(), applied to a [i - window/2, i
+ window/2] window centered (clamped at the edges) on each output
index -- for visualizing SNR drift vs time/index rather than reading
one block-average scalar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
soft
|
NDArray[complex64]
|
Despread complex symbols. |
required |
sign_bits
|
NDArray[uint8]
|
Known transmitted bits (0/1). |
required |
window
|
int
|
Window width in samples. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Output. |
snr_m2m4_db_series — sliding-window blind Es/N0¶
snr_m2m4_db_series
¶
Sliding-window blind (M2M4) Es/N0 (dB) vs index, for visualizing drift.
Same estimator as snr_m2m4_db(), applied to a [i - window/2, i +
window/2] window centered (clamped at the edges) on each output
index.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
NDArray[complex64]
|
Complex baseband samples. |
required |
window
|
int
|
Window width in samples. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Output. |
Related pages¶
Gallery — Async DSSS Receiver: the SPEC waveform through coupled Doppler, A 5-Burst DSSS Link — wfmgen's Three Faces, the Full Receiver Chain, M-PSK Receiver — Pull-in, Lock, and BER