Skip to content

File tonemeas_core.h

FileList > inc > tonemeas > tonemeas_core.h

Go to the source code of this file

ToneMeasure — single-tone ADC/converter spectral measurement. More...

  • #include "clib_common.h"
  • #include "jm_perf.h"
  • #include "measure/measure_core.h"
  • #include "psd/psd_core.h"
  • #include <complex.h>
  • #include "fft/fft_core.h"
  • #include "spectral/spectral_core.h"
  • #include "acc_trace/acc_trace_core.h"

Classes

Type Name
struct tonemeas_state_t
ToneMeasure state: owned window, FFT plan and analysis scratch.

Public Functions

Type Name
tone_meas_t tonemeas_analyze (tonemeas_state_t * state, const float * x, size_t n_in)
Analyse a real capture into the single-tone metric bag.
tone_meas_t tonemeas_analyze_complex (tonemeas_state_t * state, const float complex * x, size_t n_in)
Analyse a complex baseband capture (two-sided spectrum).
tonemeas_state_t * tonemeas_create (size_t n, double fs, size_t n_harmonics, double full_scale, size_t bits, double dynamic_range_db, size_t dc_guard)
Create a ToneMeasure analyser (auto Kaiser window).
void tonemeas_destroy (tonemeas_state_t * state)
Destroy a ToneMeasure analyser.
void tonemeas_reset (tonemeas_state_t * state)
Reset (no-op: the analyser is stateless between calls).
size_t tonemeas_spectrum_dbfs (tonemeas_state_t * state, const float * x, size_t x_len, float * out)
DC-centred dBFS magnitude spectrum of a real capture (length nfft).
size_t tonemeas_spectrum_dbfs_max_out (tonemeas_state_t * state)
Capacity (== nfft) of the spectrum_dbfs output buffer.
time_stats_t tonemeas_time_stats (tonemeas_state_t * state, const float * x, size_t n_in)
Time-domain statistics of a real capture.

Detailed Description

Owns a window + zero-padded FFT and analyses one time-domain capture (real or complex) into the full single-tone metric bag (tone_meas_t). Each component's power is integrated over its window MAIN LOBE and the noise sum excludes the leakage bins around DC, the fundamental and each harmonic — the IEEE Std 1241 method — so a full-scale tone reads ~0 dBFS regardless of where it lands between FFT bins.

Lifecycle: create -> [analyze / analyze_complex / time_stats]* -> destroy

// 16-bit ADC: window auto-picked for ~100 dB dynamic range.
tonemeas_state_t *m = tonemeas_create(8192, 1.0, 8, 1.0, 16, 0.0, 0);
tone_meas_t r = tonemeas_analyze(m, capture, 8192);  // r.enob, r.sfdr_dbc...
tonemeas_destroy(m);

Public Functions Documentation

function tonemeas_analyze

Analyse a real capture into the single-tone metric bag.

tone_meas_t tonemeas_analyze (
    tonemeas_state_t * state,
    const float * x,
    size_t n_in
) 

Returns:

the metric record (by value).

>>> from doppler.measure import ToneMeasure
>>> import numpy as np
>>> n, t = 4096, np.arange(4096)
>>> # full-scale tone at 300 cycles + a 2nd harmonic 40 dB down
>>> x = (np.cos(2*np.pi*300*t/n)
...      + 0.01*np.cos(2*np.pi*600*t/n)).astype(np.float32)
>>> r = ToneMeasure(n=n, fs=1.0).analyze(x)
>>> type(r).__name__
'ToneMetrics'
>>> abs(r.fund_dbfs) < 0.1, round(r.thd, 1)   # 0 dBFS tone, THD -40 dBc
(True, -40.0)

function tonemeas_analyze_complex

Analyse a complex baseband capture (two-sided spectrum).

tone_meas_t tonemeas_analyze_complex (
    tonemeas_state_t * state,
    const float complex * x,
    size_t n_in
) 

>>> from doppler.measure import ToneMeasure
>>> import numpy as np
>>> i = np.arange(4096)
>>> x = np.exp(2j*np.pi*137*i/4096).astype(np.complex64)
>>> r = ToneMeasure(n=4096, fs=1.0).analyze_complex(x)
>>> round(r.fund_freq, 4), abs(r.fund_dbfs) < 0.2
(0.0334, True)

function tonemeas_create

Create a ToneMeasure analyser (auto Kaiser window).

tonemeas_state_t * tonemeas_create (
    size_t n,
    double fs,
    size_t n_harmonics,
    double full_scale,
    size_t bits,
    double dynamic_range_db,
    size_t dc_guard
) 

The window is always Kaiser; its shape is chosen automatically so the sidelobes sit below the requested dynamic range (see measure_resolve_dr()), keeping the resolution bandwidth as fine as n allows. The realised RBW is reported back in every result (tone_meas_t::rbw_hz).

Parameters:

  • n Capture/frame length (>= 2).
  • fs Sample rate (Hz, > 0).
  • n_harmonics Harmonics to track (k = 2..n_harmonics).
  • full_scale Amplitude that equals 0 dBFS (> 0). Ignored if bits > 0.
  • bits ADC depth: bits>0 sets the 0-dBFS reference to 2^(bits-1) and, unless overridden, the dynamic-range target (6.02*bits + 1.76 + headroom).
  • dynamic_range_db Explicit sidelobe/dynamic-range target (dB); used when > 0, else derived from bits (or a deep default when both are 0).
  • dc_guard Extra bins excluded beyond L around DC.

Returns:

Heap state, or NULL on bad args / allocation failure.

Note:

Caller must tonemeas_destroy() when done.


function tonemeas_destroy

Destroy a ToneMeasure analyser.

void tonemeas_destroy (
    tonemeas_state_t * state
) 

Parameters:

  • state May be NULL.

function tonemeas_reset

Reset (no-op: the analyser is stateless between calls).

void tonemeas_reset (
    tonemeas_state_t * state
) 


function tonemeas_spectrum_dbfs

DC-centred dBFS magnitude spectrum of a real capture (length nfft).

size_t tonemeas_spectrum_dbfs (
    tonemeas_state_t * state,
    const float * x,
    size_t x_len,
    float * out
) 

Returns:

Number of samples written (nfft).


function tonemeas_spectrum_dbfs_max_out

Capacity (== nfft) of the spectrum_dbfs output buffer.

size_t tonemeas_spectrum_dbfs_max_out (
    tonemeas_state_t * state
) 


function tonemeas_time_stats

Time-domain statistics of a real capture.

time_stats_t tonemeas_time_stats (
    tonemeas_state_t * state,
    const float * x,
    size_t n_in
) 

>>> from doppler.measure import ToneMeasure
>>> import numpy as np
>>> t = np.arange(4096)
>>> x = (0.8*np.cos(2*np.pi*50*t/4096)).astype(np.float32)
>>> ts = ToneMeasure(n=4096, fs=1.0).time_stats(x)
>>> round(ts.crest_db, 2), round(ts.fs_util_pct, 0)   # sine crest ~3.01 dB
(3.01, 80.0)


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