File psd_core.h¶
FileList > doppler > psd > psd_core.h
Go to the source code of this file
PSD — averaging power-spectral-density estimator (Welch's method), its per-frame kernel, and spectral measurement suite. More...
#include "doppler/clib_common.h"#include "doppler/dp_state.h"#include "doppler/jm_perf.h"#include "doppler/fft/fft_core.h"#include "doppler/acc_trace/acc_trace_core.h"#include "doppler/f32_buffer/f32_buffer_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | dp_psd_kernel_t PSD's per-frame kernel: one frame of n samples in, nfft DC-centred power bins out, and their reading against the full-scale reference. |
| struct | dp_psd_state_t PSD state. Allocate with dp_psd_create() . |
Public Types¶
| Type | Name |
|---|---|
| enum | psd__core_8h_1adc29c2ff13d900c2f185ee95427fb06c The window of dp_psd_create() anddp_psd_kernel_init() , and of the objects built on them: all four for the Spectrogram (which holds a kernel), a subset for carrier acquisition (dp_carrier_acq_create() says which). |
Public Functions¶
| Type | Name |
|---|---|
| void | dp_psd_accumulate (dp_psd_state_t * state, const float _Complex * x, size_t x_len) Window, FFT and fold complex baseband frames into the average. Folds every frame the stream completes: frame k covers stream samples k*hop through k*hop + n - 1 (hop = n unless dp_psd_create_hop() said otherwise). A trailing partial frame is carried to the next call, not dropped: the framer holds it. A single call of whole frames at hop = n averages what dp_psd_accumulate always has. |
| void | dp_psd_accumulate_real (dp_psd_state_t * state, const float * x, size_t x_len) Window, zero-pad, FFT and fold real frames into the average. The real-input counterpart to dp_psd_accumulate() : each length-n frame is windowed, zero-padded to nfft, transformed and folded as a DC-centred two-sided power spectrum (a real frame is Hermitian, so the +k and -k bins carry equal power). Read the one-sided fold withdp_psd_power_onesided() . |
| size_t | dp_psd_band_power (dp_psd_state_t * state, const double * bands, size_t bands_len, float * out, size_t max_out) Integrated power per band in dB. bands is a flat array of[lo0, hi0, lo1, hi1, ...] band edges in Hz; the output holds one dB value per band (n_bands = bands_len / 2). Edges are clamped to the analysed span; a band fully outside the span integrates to the dB floor. Returns 0 (Python None) when there is nothing to report: before any frame is accumulated, or whenbands holds no complete lo/hi pair. |
| size_t | dp_psd_band_power_max_out (dp_psd_state_t * state) Output capacity hint for band_power(); 0 (binding sizes from bands). |
| dp_psd_state_t * | dp_psd_create (size_t n, double fs, int window, float beta, size_t pad, double full_scale, size_t bits, int mode, double alpha) Create an averaging PSD estimator. |
| dp_psd_state_t * | dp_psd_create_hop (size_t n, double fs, int window, float beta, size_t pad, double full_scale, size_t bits, int mode, double alpha, size_t hop) Create an averaging PSD estimator whose frames are spaced by a hop. |
| void | dp_psd_destroy (dp_psd_state_t * state) Destroy a PSD instance and release all memory. |
| void | dp_psd_frame_db (dp_psd_kernel_t * k, const float _Complex * x, float * out) One frame in dBFS, against the estimator's own reference. |
| void | dp_psd_frame_linear (dp_psd_kernel_t * k, const float _Complex * x, float * out) One frame in linear full-scale^2 units, against the estimator's own reference. |
| void | dp_psd_frame_power (dp_psd_kernel_t * k, const float _Complex * x, float * pwr) One frame's DC-centred two-sided power: window, zero-pad, FFT, |X|^2. |
| void | dp_psd_get_state (const dp_psd_state_t * state, void * blob) |
| void | dp_psd_kernel_free (dp_psd_kernel_t * k) Release what dp_psd_kernel_init() allocated, and zero the kernel. |
| int | dp_psd_kernel_init (dp_psd_kernel_t * k, size_t n, int window, float beta, size_t pad, double full_scale) Fill a kernel: the window, its gains, the scratch and the plan. |
| double | dp_psd_noise_floor (dp_psd_state_t * state) Noise-floor estimate: median of the averaged dB spectrum. |
| double | dp_psd_occupied_bw (dp_psd_state_t * state, double fraction) Occupied bandwidth in Hz holding fraction of the total power. |
| size_t | dp_psd_power_onesided (dp_psd_state_t * state, float * out, size_t max_out) Averaged linear power, one-sided (length nfft/2 + 1). Folds the DC-centred two-sided estimate onto [0, fs/2] : the DC and Nyquist bins are kept as-is, every interior bin is the sum of its +k and -k halves (so a real-input tone reads 2*avg|X[k] |^2 / cg^2 there). Coherent-gain normalised; full_scale is NOT applied. Returns 0 before any accumulate. |
| size_t | dp_psd_power_onesided_max_out (dp_psd_state_t * state) Output capacity hint for dp_psd_power_onesided() ; equals nfft/2+1. |
| size_t | dp_psd_power_twosided (dp_psd_state_t * state, float * out, size_t max_out) Averaged linear power, DC-centred two-sided (length nfft). Coherent-gain normalised ( out[k] = avg|X[k] |^2 / cg^2); full_scale is NOT applied (callers that want a dBFS reference divide by full_scale^2). This is the raw spectral estimate the measurement kernels integrate over. Returns 0 (and writes nothing) before any frame is accumulated. |
| size_t | dp_psd_power_twosided_max_out (dp_psd_state_t * state) Output capacity hint for dp_psd_power_twosided() ; equals nfft. |
| size_t | dp_psd_psd_db (dp_psd_state_t * state, float * out, size_t max_out) Averaged power spectrum in dB, DC-centred. Normalised by window coherent gain so a full-scale tone reads its true power (a unit-amplitude tone peaks near 0 dB). Returns 0 (Python None) before any frame is accumulated. |
| size_t | dp_psd_psd_db_max_out (dp_psd_state_t * state) Output capacity hint for psd_db(); equals nfft. |
| size_t | dp_psd_psd_dbhz (dp_psd_state_t * state, float * out, size_t max_out) Averaged power spectral density in dB/Hz, DC-centred. Normalised by fs * sum(w^2) (ENBW-aware), the standard one-sided-free PSD scaling. Differs from psd_db() by the constant10*log10(cg^2/(fs*s2)) . Returns 0 (Python None) before any frame is accumulated. |
| size_t | dp_psd_psd_dbhz_max_out (dp_psd_state_t * state) Output capacity hint for psd_dbhz(); equals nfft. |
| void | dp_psd_reset (dp_psd_state_t * state) Discard the running average and any carried partial frame; the next accumulate re-seeds the average and starts the stream again. |
| int | dp_psd_set_state (dp_psd_state_t * state, const void * blob) |
| double | dp_psd_sfdr (dp_psd_state_t * state, float min_db) Spurious-free dynamic range in dB from the two strongest peaks. |
| double | dp_psd_snr (dp_psd_state_t * state, double lo_hz, double hi_hz) In-band SNR in dB: peak level in [lo_hz, hi_hz] minus the noise floor. |
| size_t | dp_psd_state_bytes (const dp_psd_state_t * state) |
| double | dp_psd_total_band_power (dp_psd_state_t * state, const double * bands, size_t bands_len) Total integrated power across all bands in dB. |
Macros¶
| Type | Name |
|---|---|
| define | PSD_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('P','S','D',' ') |
| define | PSD_STATE_VERSION 2u |
Detailed Description¶
Two objects live here. dp_psd_kernel_t turns ONE frame into nfft DC-centred power bins and reads them against full scale, with no averaging: the window, the transform and the dBFS reference. PSD holds one by value and folds each frame it makes into a running average; the Spectrogram holds one and emits each frame as a row. A caller that wants single-frame spectra holds a kernel, not a PSD.
A stateful, C-first periodogram averager (Welch's method). It composes the existing pieces of the library rather than re-implementing them: an dp_fft_state_t forward plan, a spectral window (Hann, Kaiser, Blackman-Harris or rectangular) with its coherent gain and ENBW, an dp_acc_trace_state_t per-bin power averager (mean / EMA / max-hold / min-hold), and the spectral free functions (dp_magnitude_db_cf32, dp_find_peaks_f32, dp_obw_from_power, dp_noise_floor_db) for the derived measurements.
Feed complex baseband frames with dp_psd_accumulate(); each length-n frame is windowed, FFT'd, converted to power, fftshifted to DC-centred order and folded into the running average. Then read: * dp_psd_psd_db() : averaged power spectrum, dB (peak reads tone power) * dp_psd_psd_dbhz() : averaged PSD, dB/Hz (ENBW / fs normalised) * dp_psd_band_power() / dp_psd_total_band_power() : integrated band power, dB * dp_psd_occupied_bw() : occupied bandwidth, Hz * dp_psd_noise_floor() / dp_psd_snr() / dp_psd_sfdr() : level statistics, dB
All spectra are DC-centred (fftshift), matching find_peaks_f32's bin -> frequency convention (bin i maps to (i - nfft/2)/nfft in normalised frequency, so spectral peaks are obtained idiomatically with find_peaks_f32(w.psd_db(), n_peaks, min_db)).
Lifecycle: create -> (accumulate / reset)* -> (measurement getters)* -> destroy
The kernel's: dp_psd_kernel_init() -> (dp_psd_frame_power / _linear / _db)* -> dp_psd_kernel_free().
Public Types Documentation¶
enum psd__core_8h_1adc29c2ff13d900c2f185ee95427fb06c¶
The window of dp_psd_create() anddp_psd_kernel_init() , and of the objects built on them: all four for the Spectrogram (which holds a kernel), a subset for carrier acquisition (dp_carrier_acq_create() says which).
enum psd__core_8h_1adc29c2ff13d900c2f185ee95427fb06c {
DP_PSD_WINDOW_HANN = 0,
DP_PSD_WINDOW_KAISER = 1,
DP_PSD_WINDOW_BLACKMAN_HARRIS = 2,
DP_PSD_WINDOW_RECT = 3
};
HANN is 0, so a zeroed configuration is Hann. The Python faces name the same windows "hann", "kaiser", "blackman-harris" and "rect", bound to these constants by name (just-makeit.toml, [[enum]] psd_window); carrier acquisition's face names its subset (carrier_acq_window).
Public Functions Documentation¶
function dp_psd_accumulate¶
Window, FFT and fold complex baseband frames into the average. Folds every frame the stream completes: frame k covers stream samples k*hop through k*hop + n - 1 (hop = n unless dp_psd_create_hop() said otherwise). A trailing partial frame is carried to the next call, not dropped: the framer holds it. A single call of whole frames at hop = n averages what dp_psd_accumulate always has.
Parameters:
stateMust be non-NULL.xComplex baseband samples (cf32).x_lenNumber of samples inx.
>>> import numpy as np
>>> from doppler.spectral import PSD
>>> n = 64
>>> w = PSD(n=n, fs=1.0, window="hann", mode="mean")
>>> k = 8
>>> x = np.exp(2j*np.pi*k*np.arange(n)/n).astype(np.complex64)
>>> for _ in range(4):
... w.accumulate(x)
>>> psd = w.psd_db()
>>> psd.shape
(64,)
>>> int(np.argmax(psd)) == n // 2 + k
True
>>> w.count
4
function dp_psd_accumulate_real¶
Window, zero-pad, FFT and fold real frames into the average. The real-input counterpart to dp_psd_accumulate() : each length-n frame is windowed, zero-padded to nfft, transformed and folded as a DC-centred two-sided power spectrum (a real frame is Hermitian, so the +k and -k bins carry equal power). Read the one-sided fold withdp_psd_power_onesided() .
This call stays on whole frames at hop = n: it folds floor(n_in / n) frames and drops a trailing partial frame. It neither reads nor writes the carry of the complex accumulate call, so mixing the two on one object mixes two streams, and a hop below n is not used by this call.
Parameters:
stateMust be non-NULL.xReal samples (f32).x_lenNumber of samples inx.
function dp_psd_band_power¶
Integrated power per band in dB. bands is a flat array of[lo0, hi0, lo1, hi1, ...] band edges in Hz; the output holds one dB value per band (n_bands = bands_len / 2). Edges are clamped to the analysed span; a band fully outside the span integrates to the dB floor. Returns 0 (Python None) when there is nothing to report: before any frame is accumulated, or whenbands holds no complete lo/hi pair.
size_t dp_psd_band_power (
dp_psd_state_t * state,
const double * bands,
size_t bands_len,
float * out,
size_t max_out
)
Parameters:
stateMust be non-NULL.bandsFlat[lo,hi,...]band edges, Hz.bands_lenNumber of edge values (2 * n_bands).outDestination, at least n_bands float32 elements.max_outCapacity ofoutin elements. Emission stops there, so the return value is the number actually written.
Returns:
The number of bands written, min(n_bands, max_out); 0 (Python None) when there is nothing to report.
>>> import numpy as np
>>> from doppler.spectral import PSD
>>> w = PSD(n=64, fs=1.0, window="hann", mode="mean")
>>> w.accumulate(np.ones(64, dtype=np.complex64))
>>> pb = w.band_power(np.array([-0.5, 0.0, 0.0, 0.5]))
>>> pb.shape
(2,)
function dp_psd_band_power_max_out¶
Output capacity hint for band_power(); 0 (binding sizes from bands).
function dp_psd_create¶
Create an averaging PSD estimator.
dp_psd_state_t * dp_psd_create (
size_t n,
double fs,
int window,
float beta,
size_t pad,
double full_scale,
size_t bits,
int mode,
double alpha
)
Parameters:
nWindow / frame length in samples. Must be >= 2.fsSample rate in Hz (used for dB/Hz and band frequencies); finite and > 0.windowThe window: "hann" (the default), "kaiser", "blackman-harris" or "rect" (no taper: best resolution, worst leakage).betaKaiser beta (ignored by every other window). One that makes the window non-finite NaN, or large enough to overflow it is refused.padZero-pad factor (>= 1; 0 is refused); nfft = next_pow_two(n * pad).full_scaleAmplitude that reads 0 dBFS in the dB getters; finite and > 0. Ignored whenbits> 0.bitsADC depth: when > 0, sets full_scale = 2^(bits-1) (the single definition of the dBFS reference); 0 = usefull_scaledirectly. At most 64.modeAveraging mode: "mean", "exp", "maxhold" or "minhold".alphaEMA smoothing factor, exp mode only, where it must lie in (0, 1]: the rule is the AccTrace averager's, whose create refuses anything else, so this does too. Ignored, and so not checked, in the other modes.
Returns:
Heap-allocated state, or NULL on invalid argument or OOM. A window whose coherent gain sum(w) is 0 Hann at n = 2, whose symmetric form is all zeros is refused too: every reading divides by it. So is an n or n * pad too large for its buffers to be sized, rather than wrapped to a small one.
Note:
Caller must call dp_psd_destroy() when done.
>>> from doppler.spectral import PSD
>>> w = PSD(n=1024, fs=1.0e6, window="kaiser", beta=8.0, mode="mean")
>>> w.n, w.fs
(1024, 1000000.0)
>>> round(w.rbw / (w.fs / w.n), 3) == round(w.enbw, 3)
True
function dp_psd_create_hop¶
Create an averaging PSD estimator whose frames are spaced by a hop.
dp_psd_state_t * dp_psd_create_hop (
size_t n,
double fs,
int window,
float beta,
size_t pad,
double full_scale,
size_t bits,
int mode,
double alpha,
size_t hop
)
Frame k covers stream samples k*hop through k*hop + n - 1. A hop equal to n gives non-overlapping frames. A trailing partial frame is carried to the next accumulate call, not dropped.
Parameters:
nWindow / frame length in samples. Must be >= 2.fsSample rate in Hz (used for dB/Hz and band frequencies); finite and > 0.windowThe window: "hann" (the default), "kaiser", "blackman-harris" or "rect" (no taper: best resolution, worst leakage).betaKaiser beta (ignored by every other window). One that makes the window non-finite NaN, or large enough to overflow it is refused.padZero-pad factor (>= 1; 0 is refused); nfft = next_pow_two(n * pad).full_scaleAmplitude that reads 0 dBFS in the dB getters; finite and > 0. Ignored whenbits> 0.bitsADC depth: when > 0, sets full_scale = 2^(bits-1) (the single definition of the dBFS reference); 0 = usefull_scaledirectly. At most 64.modeAveraging mode: "mean", "exp", "maxhold" or "minhold".alphaEMA smoothing factor, exp mode only, where it must lie in (0, 1]: the rule is the AccTrace averager's, whose create refuses anything else, so this does too. Ignored, and so not checked, in the other modes.hopSamples between frame starts, 1..n. 0 means n, which gives non-overlapping frames; the default. A hop above n would leave samples between frames that are never kept, so it is refused.
Returns:
Heap-allocated state, or NULL on invalid argument or OOM. A window whose coherent gain sum(w) is 0 Hann at n = 2, whose symmetric form is all zeros is refused too: every reading divides by it. So is an n or n * pad too large for its buffers to be sized, rather than wrapped to a small one.
Note:
Caller must call dp_psd_destroy() when done.
>>> from doppler.spectral import PSD
>>> w = PSD(n=1024, fs=1.0e6, window="kaiser", beta=8.0, mode="mean", hop=512)
>>> w.n, w.fs
(1024, 1000000.0)
>>> round(w.rbw / (w.fs / w.n), 3) == round(w.enbw, 3)
True
function dp_psd_destroy¶
Destroy a PSD instance and release all memory.
Parameters:
stateMay be NULL (no-op).
function dp_psd_frame_db¶
One frame in dBFS, against the estimator's own reference.
dp_psd_frame_power() divided by the window coherent gain squared and the full-scale reference, as 10*log10 with the -200 dB floor, so a full-scale tone on a bin reads 0 dB whatever the window. The result equals dp_psd_psd_db() after accumulating that one frame, bit for bit (pinned by test_psd_core.c). Does not touch a PSD's running average.
Parameters:
kA kernel dp_psd_kernel_init() filled.xExactlyk->ncomplex samples (cf32).outOutput,k->nfftfloats, DC-centred.
dp_psd_kernel_t k;
if (dp_psd_kernel_init (&k, 8, DP_PSD_WINDOW_RECT, 0.0f, 1, 1.0) != DP_OK)
return 1;
float _Complex x[8];
float db[8];
for (int i = 0; i < 8; i++)
x[i] = cexpf (I * 2.0f * 3.14159265f * 2.0f * (float)i / 8.0f);
dp_psd_frame_db (&k, x, db); // unit tone on bin 2, rectangular
const int bad = fabsf (db[4 + 2]) > 1e-4f; // bin 2 is at nfft/2 + 2
dp_psd_kernel_free (&k); // freed on either path
if (bad)
return 1;
function dp_psd_frame_linear¶
One frame in linear full-scale^2 units, against the estimator's own reference.
dp_psd_frame_power() divided by the window coherent gain squared and the full-scale reference squared, cg^2 * full_scale^2: a full-scale tone on a bin reads 1.0 whatever the window. dp_psd_frame_db() is 10*log10 of the same quotient, with the -200 dB floor the two are read from one double, so they cannot disagree about the reference. This is the frame a consumer that averages for itself should take: the raw dp_psd_frame_power() sits 20*log10(sum(w)) above it, 54.18 dB for Hann at 1024 points (docs/design/spectrogram-measurements.md section 5.3). Does not touch a PSD's running average; not thread-safe on one kernel.
Parameters:
kA kernel dp_psd_kernel_init() filled.xExactlyk->ncomplex samples (cf32).outOutput,k->nfftfloats, DC-centred.
dp_psd_kernel_t k;
if (dp_psd_kernel_init (&k, 8, DP_PSD_WINDOW_HANN, 0.0f, 1, 1.0) != DP_OK)
return 1;
float _Complex x[8];
float lin[8];
for (int i = 0; i < 8; i++)
x[i] = cexpf (I * 2.0f * 3.14159265f * 2.0f * (float)i / 8.0f);
dp_psd_frame_linear (&k, x, lin); // unit tone on bin 2, Hann
const int bad = fabsf (lin[4 + 2] - 1.0f) > 1e-4f; // bin 2 at nfft/2 + 2
dp_psd_kernel_free (&k); // freed on either path
if (bad)
return 1;
function dp_psd_frame_power¶
One frame's DC-centred two-sided power: window, zero-pad, FFT, |X|^2.
The per-frame kernel dp_psd_accumulate() folds into its average, exposed without the average. The result is the UN-NORMALISED power the averager folds: no division by the window coherent gain squared, so a tone does not read at its true level (dp_psd_frame_db() applies that division). Do not compare this raw output with dp_psd_power_twosided(), which divides by cg^2 on the double path. It stays the raw |X|^2 because that is what the averager folds; a consumer that wants a frame against the dBFS reference in linear units to average itself, or in dB takes dp_psd_frame_linear() or dp_psd_frame_db(). Uses the kernel's scratch, so it is not thread-safe on one kernel; a PSD's kernel is &psd->k, and this does not touch that PSD's running average.
Parameters:
kA kernel dp_psd_kernel_init() filled.xExactlyk->ncomplex samples (cf32).pwrOutput,k->nfftfloats, bin k (centred) at index nfft/2 + k.
function dp_psd_get_state¶
function dp_psd_kernel_free¶
Release what dp_psd_kernel_init() allocated, and zero the kernel.
Parameters:
kA kernel dp_psd_kernel_init() was called on (any outcome), a zeroed one, or NULL, which does nothing (as every destroy).
function dp_psd_kernel_init¶
Fill a kernel: the window, its gains, the scratch and the plan.
int dp_psd_kernel_init (
dp_psd_kernel_t * k,
size_t n,
int window,
float beta,
size_t pad,
double full_scale
)
k is zeroed first, so it is safe to call dp_psd_kernel_free() on it whatever this returns. On a refusal or an allocation failure nothing is left allocated.
Parameters:
kThe kernel to fill (caller-owned storage).nFrame length in samples; at least 2.windowDP_PSD_WINDOW_HANN, _KAISER, _BLACKMAN_HARRIS or _RECT.betaKaiser beta (ignored by every other window). One that makes the window non-finite is refused.padZero-pad factor (>= 1); nfft = next_pow_two(n * pad).full_scaleAmplitude that reads 0 dBFS; finite and > 0.
Returns:
DP_OK; DP_ERR_INVALID for an argument out of range, a window with no gain at n (Hann at 2) or an n * pad too large to size; DP_ERR_MEMORY when an allocation fails.
function dp_psd_noise_floor¶
Noise-floor estimate: median of the averaged dB spectrum.
Returns:
Median dB level (0 if empty).
function dp_psd_occupied_bw¶
Occupied bandwidth in Hz holding fraction of the total power.
Calls obw_from_power on the averaged spectrum, so the search and its domain are that function's and the two cannot disagree.
Parameters:
stateMust be non-NULL.fractionPower fraction in the OPEN interval (0, 1), e.g. 0.99. 1 is excluded: all of the power in float is every bin that rounding residue reached, which has no stable answer.
Returns:
Occupied bandwidth in Hz (0 if empty or no power); NaN when fraction is outside (0, 1), before any frame too, rather than a silently clamped answer.
>>> import numpy as np
>>> from doppler.spectral import PSD
>>> w = PSD(n=64, fs=64.0, window="rect")
>>> w.accumulate(np.ones(64, dtype=np.complex64)) # all power at DC
>>> w.occupied_bw(0.99) # one bin, fs / 64
1.0
>>> w.occupied_bw(1.0) # outside (0, 1)
nan
function dp_psd_power_onesided¶
Averaged linear power, one-sided (length nfft/2 + 1). Folds the DC-centred two-sided estimate onto [0, fs/2] : the DC and Nyquist bins are kept as-is, every interior bin is the sum of its +k and -k halves (so a real-input tone reads 2*avg|X[k] |^2 / cg^2 there). Coherent-gain normalised; full_scale is NOT applied. Returns 0 before any accumulate.
Parameters:
stateMust be non-NULL.outDestination, at least nfft/2 + 1 float32 elements.max_outCapacity ofoutin elements. Emission stops there, so the return value is the number actually written.
Returns:
min(nfft/2 + 1, max_out), or 0 if empty.
function dp_psd_power_onesided_max_out¶
Output capacity hint for dp_psd_power_onesided() ; equals nfft/2+1.
function dp_psd_power_twosided¶
Averaged linear power, DC-centred two-sided (length nfft). Coherent-gain normalised ( out[k] = avg|X[k] |^2 / cg^2); full_scale is NOT applied (callers that want a dBFS reference divide by full_scale^2). This is the raw spectral estimate the measurement kernels integrate over. Returns 0 (and writes nothing) before any frame is accumulated.
Parameters:
stateMust be non-NULL.outDestination, at least nfft float32 elements.max_outCapacity ofoutin elements. Emission stops there, so the return value is the number actually written.
Returns:
min(nfft, max_out), or 0 if empty.
function dp_psd_power_twosided_max_out¶
Output capacity hint for dp_psd_power_twosided() ; equals nfft.
function dp_psd_psd_db¶
Averaged power spectrum in dB, DC-centred. Normalised by window coherent gain so a full-scale tone reads its true power (a unit-amplitude tone peaks near 0 dB). Returns 0 (Python None) before any frame is accumulated.
Parameters:
stateMust be non-NULL.outDestination, at least nfft float32 elements.max_outCapacity ofoutin elements. Emission stops there, so the return value is the number actually written.
Returns:
min(nfft, max_out), or 0 if empty.
function dp_psd_psd_db_max_out¶
Output capacity hint for psd_db(); equals nfft.
function dp_psd_psd_dbhz¶
Averaged power spectral density in dB/Hz, DC-centred. Normalised by fs * sum(w^2) (ENBW-aware), the standard one-sided-free PSD scaling. Differs from psd_db() by the constant10*log10(cg^2/(fs*s2)) . Returns 0 (Python None) before any frame is accumulated.
>>> import numpy as np
>>> from doppler.spectral import PSD
>>> w = PSD(n=32, fs=2.0, window="hann", mode="mean")
>>> w.accumulate(np.ones(32, dtype=np.complex64))
>>> a = w.psd_db(); b = w.psd_dbhz()
>>> bool(np.allclose(a - b, (a - b)[0])) # offset is a constant
True
function dp_psd_psd_dbhz_max_out¶
Output capacity hint for psd_dbhz(); equals nfft.
function dp_psd_reset¶
Discard the running average and any carried partial frame; the next accumulate re-seeds the average and starts the stream again.
Parameters:
stateMust be non-NULL.
function dp_psd_set_state¶
function dp_psd_sfdr¶
Spurious-free dynamic range in dB from the two strongest peaks.
Parameters:
stateMust be non-NULL.min_dbMinimum peak level considered, dB.
Returns:
Carrier-minus-highest-spur level in dB (0 if fewer than two peaks).
function dp_psd_snr¶
In-band SNR in dB: peak level in [lo_hz, hi_hz] minus the noise floor.
Parameters:
stateMust be non-NULL.lo_hzBand lower edge, Hz.hi_hzBand upper edge, Hz.
Returns:
SNR in dB (0 if empty).
function dp_psd_state_bytes¶
function dp_psd_total_band_power¶
Total integrated power across all bands in dB.
Parameters:
stateMust be non-NULL.bandsFlat[lo,hi,...]band edges, Hz.bands_lenNumber of edge values (2 * n_bands).
Returns:
Total band power in dB (dB floor if empty).
Macro Definition Documentation¶
define PSD_STATE_MAGIC¶
define PSD_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/doppler/psd/psd_core.h