Skip to content

File spectral_core.h

FileList > inc > spectral > spectral_core.h

Go to the source code of this file

Spectral module — public C API. More...

  • #include "clib_common.h"

Classes

Type Name
struct dp_peak_t
One spectral peak returned by find_peaks_f32() .

Public Functions

Type Name
void blackman_harris_window (float * w, size_t w_len)
Fill w with a 4-term Blackman-Harris window. Computes the minimum 4-term Blackman-Harris window: w(k) = 0.35875 - 0.48829*cos(2πk/(N-1))
size_t find_peaks_f32 (const float * db, size_t db_len, size_t n_peaks, float min_db, dp_peak_t * result)
Find up to n_peaks local maxima in a DC-centred F32 dB spectrum. Three-step algorithm: (1) local-max scan —db[k] >db[k-1] &&db[k] >=db[k+1] withdb[k] > min_db; (2) parabolic interpolation on each local maximum to produce sub-bin freq_norm accuracy; (3) sort descending and return the topn_peaks . freq_norm is DC-centred: bin i maps to freq_norm = (i - N/2) / N so DC (bin N/2) → 0.0 and the first negative frequency bin → −0.5. The spectrum must have at least 3 bins.
void hann_window (float * w, size_t w_len)
Fill w with a Hann (raised-cosine) window. Computes w(k) = 0.5*(1 - cos(2π k/(N-1))) for k = 0..N-1. The window tapers smoothly to zero at both endpoints, providing ~31 dB first-sidelobe rejection. Takes no shape parameter; use Kaiser for adjustable roll-off.
double kaiser_beta_for_sidelobe (double atten_db)
Kaiser beta achieving a target window peak-sidelobe attenuation.
float kaiser_enbw (const float * w, size_t w_len)
Compute the equivalent noise bandwidth of a window in bins. ENBW = N * sum(w²) / (sum(w))² quantifies how many noise bins the window smears into the main lobe. A rectangular window has ENBW = 1.0; tapered windows are > 1.0. Works with any window type, not just Kaiser.
void kaiser_window (float * w, size_t w_len, float beta)
Fill w with a Kaiser window of shape parameterbeta . I0 is computed via the converging power-series expansion. Increasingbeta raises sidelobe attenuation at the cost of a wider main lobe (beta=0 → rectangular, beta≈6 → ~60 dB sidelobe rejection). The output is normalised so thatw[0] =w[N-1] = I0(0)/I0(beta).
void magnitude_db_cf32 (const float complex * x, size_t x_len, float * out, float lin_floor, float offset_db)
Convert a CF32 complex spectrum to F32 dB magnitudes. Computes out(k) = 20*log10(max(|x(k)|, lin_floor)) + offset_db for each bin. The lin_floor guard prevents log10(0); a value of 1e-12 corresponds to a -240 dB noise floor.offset_db shifts the entire output for calibration (e.g., normalise to 0 dBFS).
void magnitude_db_cf64 (const double complex * x, size_t x_len, float * out, double lin_floor, float offset_db)
Convert a CF64 complex spectrum to F32 dB magnitudes. Double-precision variant of magnitude_db_cf32() . Accepts a CF64 input array and a doublelin_floor ; output is still F32 because downstream display code typically works in single precision. The formula andoffset_db semantics are identical.
double noise_floor_db (const float * db, size_t db_len)
double obw_from_power (const double * pwr, size_t pwr_len, double fs, double frac)

Detailed Description

Provides windowing (Kaiser, Hann, Blackman-Harris), ENBW computation, magnitude conversion, and peak finding. These are pure functions with no persistent state.

Public Functions Documentation

function blackman_harris_window

Fill w with a 4-term Blackman-Harris window. Computes the minimum 4-term Blackman-Harris window: w(k) = 0.35875 - 0.48829*cos(2πk/(N-1))

void blackman_harris_window (
    float * w,
    size_t w_len
) 

  • 0.14128*cos(4πk/(N-1))
  • 0.01168*cos(6πk/(N-1)) for k = 0..N-1. Provides approximately 92 dB first-sidelobe rejection, far deeper than Hann (~31 dB) or Kaiser at β=8 (~80 dB). Use for quantization and decimation spectra where you need to see low-level artefacts below the noise floor.

Parameters:

  • w Output buffer modified in-place; must be length >= 1.
  • w_len Number of elements in w.
    >>> from doppler.spectral import blackman_harris_window
    >>> import numpy as np
    >>> w = np.zeros(8, dtype=np.float32)
    >>> blackman_harris_window(w)
    >>> [round(v, 4) for v in w.tolist()]
    [0.0001, 0.0334, 0.3328, 0.8894, 0.8894, 0.3328, 0.0334, 0.0001]
    

function find_peaks_f32

Find up to n_peaks local maxima in a DC-centred F32 dB spectrum. Three-step algorithm: (1) local-max scan —db[k] >db[k-1] &&db[k] >=db[k+1] withdb[k] > min_db; (2) parabolic interpolation on each local maximum to produce sub-bin freq_norm accuracy; (3) sort descending and return the topn_peaks . freq_norm is DC-centred: bin i maps to freq_norm = (i - N/2) / N so DC (bin N/2) → 0.0 and the first negative frequency bin → −0.5. The spectrum must have at least 3 bins.

size_t find_peaks_f32 (
    const float * db,
    size_t db_len,
    size_t n_peaks,
    float min_db,
    dp_peak_t * result
) 

Parameters:

  • db F32 dB spectrum, DC-centred, length >= 3.
  • db_len Number of elements in db.
  • n_peaks Maximum number of peaks to return.
  • min_db Amplitude gate; local maxima below this are discarded.
  • result Caller-supplied dp_peak_t array of length >= n_peaks; filled with up to n_peaks results sorted descending.

Returns:

Number of dp_peak_t entries written to result.

>>> from doppler.spectral import find_peaks_f32
>>> import numpy as np
>>> db = np.full(32, -60.0, dtype=np.float32)
>>> db[7] = -15.0; db[8] = -10.0; db[9] = -15.0
>>> peaks = find_peaks_f32(db, 2, -30.0)
>>> peaks
[(-0.25, -10.0)]


function hann_window

Fill w with a Hann (raised-cosine) window. Computes w(k) = 0.5*(1 - cos(2π k/(N-1))) for k = 0..N-1. The window tapers smoothly to zero at both endpoints, providing ~31 dB first-sidelobe rejection. Takes no shape parameter; use Kaiser for adjustable roll-off.

void hann_window (
    float * w,
    size_t w_len
) 

Parameters:

  • w Output buffer modified in-place; must be length >= 1.
  • w_len Number of elements in w.
    >>> from doppler.spectral import hann_window
    >>> import numpy as np
    >>> w = np.zeros(8, dtype=np.float32)
    >>> hann_window(w)
    >>> [round(v, 4) for v in w.tolist()]
    [0.0, 0.1883, 0.6113, 0.9505, 0.9505, 0.6113, 0.1883, 0.0]
    

function kaiser_beta_for_sidelobe

Kaiser beta achieving a target window peak-sidelobe attenuation.

double kaiser_beta_for_sidelobe (
    double atten_db
) 

Inverts the Kaiser window-design formula (Kaiser 1974) so the window's own peak sidelobe sits at -atten_db: A > 60 dB : beta = 0.12438 * (A + 6.3) 13.26 < A <= 60 dB : beta = 0.76609*(A-13.26)^0.4 + 0.09834*(A-13.26) A <= 13.26 dB : beta = 0.0 (rectangular, sidelobes ~ -13.3 dB) Picking the smallest beta meeting a dynamic-range target keeps the main lobe (hence ENBW / resolution bandwidth) as narrow as the requirement allows — the basis of the measurement suite's auto-window selection.

This differs from doppler.resample.kaiser_beta(), which uses the Kaiser FIR-filter formula (A there is a filter stopband ripple, not a window sidelobe — about 13 dB lower for the same beta).

Parameters:

  • atten_db Desired window peak-sidelobe attenuation in dB (positive).

Returns:

Kaiser beta (>= 0.0).

>>> from doppler.spectral import kaiser_beta_for_sidelobe
>>> round(kaiser_beta_for_sidelobe(90.0), 4)
11.9778
>>> kaiser_beta_for_sidelobe(10.0)
0.0


function kaiser_enbw

Compute the equivalent noise bandwidth of a window in bins. ENBW = N * sum(w²) / (sum(w))² quantifies how many noise bins the window smears into the main lobe. A rectangular window has ENBW = 1.0; tapered windows are > 1.0. Works with any window type, not just Kaiser.

float kaiser_enbw (
    const float * w,
    size_t w_len
) 

Parameters:

  • w Float32 window coefficients array; any length >= 1.
  • w_len Number of elements in w.

Returns:

ENBW in bins (dimensionless).

>>> from doppler.spectral import kaiser_enbw, hann_window
>>> import numpy as np
>>> w = np.zeros(8, dtype=np.float32)
>>> hann_window(w)
>>> round(kaiser_enbw(w), 4)
1.7143


function kaiser_window

Fill w with a Kaiser window of shape parameterbeta . I0 is computed via the converging power-series expansion. Increasingbeta raises sidelobe attenuation at the cost of a wider main lobe (beta=0 → rectangular, beta≈6 → ~60 dB sidelobe rejection). The output is normalised so thatw[0] =w[N-1] = I0(0)/I0(beta).

void kaiser_window (
    float * w,
    size_t w_len,
    float beta
) 

Parameters:

  • w Output buffer modified in-place; must be length >= 1.
  • w_len Number of elements in w.
  • beta Window shape parameter (float, >= 0).
    >>> from doppler.spectral import kaiser_window
    >>> import numpy as np
    >>> w = np.zeros(8, dtype=np.float32)
    >>> kaiser_window(w, 6.0)
    >>> [round(v, 4) for v in w.tolist()]
    [0.0149, 0.1998, 0.5913, 0.9454, 0.9454, 0.5913, 0.1998, 0.0149]
    

function magnitude_db_cf32

Convert a CF32 complex spectrum to F32 dB magnitudes. Computes out(k) = 20*log10(max(|x(k)|, lin_floor)) + offset_db for each bin. The lin_floor guard prevents log10(0); a value of 1e-12 corresponds to a -240 dB noise floor.offset_db shifts the entire output for calibration (e.g., normalise to 0 dBFS).

void magnitude_db_cf32 (
    const float complex * x,
    size_t x_len,
    float * out,
    float lin_floor,
    float offset_db
) 

Parameters:

  • x CF32 complex spectrum array, length x_len.
  • x_len Number of elements in x.
  • out Output F32 buffer, length >= x_len; caller-allocated.
  • lin_floor Linear amplitude floor (must be > 0, e.g. 1e-12).
  • offset_db Calibration offset added to every output bin.
    >>> from doppler.spectral import magnitude_db_cf32
    >>> import numpy as np
    >>> x = np.array([1+0j, 0.1+0j, 0+0j], dtype=np.complex64)
    >>> magnitude_db_cf32(x, 1e-12, 0.0).tolist()
    [0.0, -20.0, -240.0]
    

function magnitude_db_cf64

Convert a CF64 complex spectrum to F32 dB magnitudes. Double-precision variant of magnitude_db_cf32() . Accepts a CF64 input array and a doublelin_floor ; output is still F32 because downstream display code typically works in single precision. The formula andoffset_db semantics are identical.

void magnitude_db_cf64 (
    const double complex * x,
    size_t x_len,
    float * out,
    double lin_floor,
    float offset_db
) 

Parameters:

  • x CF64 complex spectrum array, length x_len.
  • x_len Number of elements in x.
  • out Output F32 buffer, length >= x_len; caller-allocated.
  • lin_floor Linear amplitude floor (double, must be > 0).
  • offset_db Calibration offset added to every output bin.
    >>> from doppler.spectral import magnitude_db_cf64
    >>> import numpy as np
    >>> x = np.array([1+0j, 10+0j], dtype=np.complex128)
    >>> magnitude_db_cf64(x, 1e-12, 0.0).tolist()
    [0.0, 20.0]
    

function noise_floor_db

double noise_floor_db (
    const float * db,
    size_t db_len
) 

function obw_from_power

double obw_from_power (
    const double * pwr,
    size_t pwr_len,
    double fs,
    double frac
) 


The documentation for this class was generated from the following file native/inc/spectral/spectral_core.h