File specan_core.h¶
FileList > inc > specan > specan_core.h
Go to the source code of this file
Specan — natural-parameter spectrum analyzer (DDC + averaging PSD). More...
#include "ddc/ddc_core.h"#include "psd/psd_core.h"#include "dp_state.h"#include <complex.h>#include <stddef.h>#include "lo/lo_core.h"#include "RateConverter/RateConverter_core.h"#include "resamp/resamp_core.h"#include "hbdecim/hbdecim_core.h"#include "cic/cic_core.h"#include "fir/fir_core.h"#include "resample/resample_core.h"#include "acc_trace/acc_trace_core.h"#include "fft/fft_core.h"#include "spectral/spectral_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | specan_state_t Specan state. Allocate with specan_create() . |
Public Functions¶
| Type | Name |
|---|---|
| specan_state_t * | specan_create (double fs, double span, double rbw, double src_center, double center, double offset_db, double full_scale, size_t bits, int window, size_t navg) Create a natural-parameter spectrum analyzer. |
| void | specan_destroy (specan_state_t * state) Destroy a Specan instance and release all memory. |
| size_t | specan_execute (specan_state_t * state, const float complex * x, size_t x_len, float * out, size_t max_out) Mix, decimate, average and return one display spectrum, or nothing. |
| size_t | specan_execute_max_out (specan_state_t * state) Output capacity hint for specan_execute() ; equals disp_n. |
| void | specan_get_state (const specan_state_t * state, void * blob) |
| void | specan_reset (specan_state_t * state) Drop pending samples and the running average; LO/filter history zero. |
| void | specan_retune (specan_state_t * state, double center) Retune the display center without rebuilding the chain. |
| int | specan_set_state (specan_state_t * state, const void * blob) |
| size_t | specan_state_bytes (const specan_state_t * state) |
Macros¶
| Type | Name |
|---|---|
| define | SPECAN_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('S','P','A','N') |
| define | SPECAN_STATE_VERSION 1u |
Detailed Description¶
A streaming spectrum analyzer that speaks the instrument parameters an operator already knows — center frequency, span, resolution bandwidth (RBW), and reference level — instead of the DSP knobs (window length, Kaiser beta, zero-pad factor) underneath them. It is the C-first home for the mapping that doppler.specan's engine used to hand-roll in Python.
It composes the existing library, re-implementing nothing:
cf32 in (fs_in) → Ddc (mix center→DC, decimate to fs_out = span·1.28)
→ PSD (window → zero-pad FFT → cg²-normalised power,
averaged over `navg` segments)
→ crop to the central ±span/2 display band
→ dB + ref offset → float display spectrum
- ddc_state_t is the tuner/decimator (LO mix + RateConverter cascade); retuning the center is a cheap, seamless LO phase change.
- psd_state_t is the one averaging-PSD core shared with the measurement suite;
navg = 1gives a responsive single-periodogram frame, largernavgtrades update rate for a smoother, lower-variance trace.
The display band length and the bin→frequency map are fixed at create time: bin i of the returned spectrum maps to center + (i − disp_n/2)·fs_out/nfft Hz. Peaks are intentionally NOT computed here — compose find_peaks_f32 on the returned trace.
Lifecycle: create → (execute / retune / reset)* → destroy.
// 200 kHz span, 500 Hz RBW around DC of a 2.048 MHz cf32 stream
specan_state_t *sa = specan_create(2.048e6, 200e3, 500.0, 0.0, 0.0,
0.0, 1, 1);
float disp[8192];
size_t n = specan_execute(sa, iq, 65536, disp, 8192); // 0 until a frame
specan_destroy(sa);
Public Functions Documentation¶
function specan_create¶
Create a natural-parameter spectrum analyzer.
specan_state_t * specan_create (
double fs,
double span,
double rbw,
double src_center,
double center,
double offset_db,
double full_scale,
size_t bits,
int window,
size_t navg
)
Derives the DSP from the instrument parameters: fs_out = min(span·1.28, fs), n = next_pow2(ceil(fs_out/rbw)) (the coarse RBW knob), a Kaiser beta solved so the window ENBW realises rbw (the fine knob), nfft = next_pow2(2·n), and the central display crop covering ±span/2.
Parameters:
fsInput sample rate (Hz). Must be > 0.spanDisplay span (Hz). Must be > 0.rbwResolution bandwidth (Hz). Must be > 0.src_centerSource center frequency (Hz); the input band is centred here, so the analyzer mixes (center − src_center) to DC.centerDesired display center frequency (Hz).offset_dbAdditive dB offset on the display spectrum, applied on top of dBFS (e.g. a dBm calibration the application computes from a reference level).full_scaleAmplitude that reads 0 dBFS (> 0). Ignored if bits > 0.bitsADC depth: bits>0 sets the 0-dBFS reference to 2^(bits-1) in the shared PSD core (the single source of truth for the dBFS reference).windowWindow index: 0 = Hann, 1 = Kaiser (RBW-trimmable).navgSegments averaged per emitted frame (>= 1).
Returns:
Heap-allocated state, or NULL on invalid argument or OOM.
Note:
Caller must call specan_destroy() when done. Argument order keeps the required parameters (fs, span, rbw) first, matching the generated constructor's hoisting of jm required init params.
>>> from doppler.analyzer import Specan
>>> sa = Specan(fs=2.048e6, span=200e3, rbw=500.0)
>>> sa.fs_out
256000.0
>>> sa.nfft == 2 * sa.n
True
function specan_destroy¶
Destroy a Specan instance and release all memory.
Parameters:
stateMay be NULL (no-op).
function specan_execute¶
Mix, decimate, average and return one display spectrum, or nothing.
size_t specan_execute (
specan_state_t * state,
const float complex * x,
size_t x_len,
float * out,
size_t max_out
)
Feeds x through the Ddc, buffers the decimated output, and once n·navg decimated samples are available windows + FFTs + averages them into a fresh frame, crops the central ±span/2 band and writes it in dB (+ ref_db). Returns 0 (writing nothing) until a frame is ready — the binding maps that to Python None.
Parameters:
stateMust be non-NULL.xcf32 input block (C-only; the binding passes it).x_lenNumber of input samples (C-only).outDisplay-spectrum buffer, dB (C-only).max_outCapacity ofout(C-only); >= disp_n is sufficient.
Returns:
Display bins written (disp_n), or 0 if no frame is ready yet.
>>> from doppler.analyzer import Specan
>>> import numpy as np
>>> sa = Specan(fs=2.048e6, span=200e3, rbw=500.0, navg=1)
>>> sa.execute(np.zeros(64, dtype=np.complex64)) is None # too few samples
True
>>> frame = sa.execute(np.zeros(65536, dtype=np.complex64))
>>> frame.shape, frame.dtype
((801,), dtype('float32'))
function specan_execute_max_out¶
Output capacity hint for specan_execute() ; equals disp_n.
function specan_get_state¶
function specan_reset¶
Drop pending samples and the running average; LO/filter history zero.
Parameters:
stateMust be non-NULL.
function specan_retune¶
Retune the display center without rebuilding the chain.
Updates the Ddc LO phase increment (seamless across blocks — no resampler or window reset) and drops pending samples so the next frame reflects only the new tuning. Changing the span or RBW requires a destroy + create (the decimation rate and window length change).
Parameters:
stateMust be non-NULL.centerNew display center frequency (Hz).
function specan_set_state¶
function specan_state_bytes¶
Macro Definition Documentation¶
define SPECAN_STATE_MAGIC¶
define SPECAN_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/specan/specan_core.h