Skip to content

File imdmeas_core.h

FileList > imdmeas > imdmeas_core.h

Go to the source code of this file

IMDMeasure — two-tone intermodulation (IMD2/IMD3) and intercept. More...

  • #include "clib_common.h"
  • #include "jm_perf.h"
  • #include "measure/measure_core.h"
  • #include "psd/psd_core.h"
  • #include <complex.h>

Classes

Type Name
struct imdmeas_state_t
IMDMeasure state: owned window, FFT plan and one-sided power scratch.

Public Functions

Type Name
imd_meas_t imdmeas_analyze (imdmeas_state_t * state, const float * x, size_t n_in)
Two-tone IMD/TOI of a real capture (finds the two strongest tones).
imdmeas_state_t * imdmeas_create (size_t n, double fs, double full_scale, size_t bits, double dynamic_range_db)
Create an IMDMeasure analyser (auto Kaiser window).
void imdmeas_destroy (imdmeas_state_t * state)
Destroy an IMDMeasure analyser.
void imdmeas_reset (imdmeas_state_t * state)
Reset the analyser (a no-op: each analyze() call is independent).
size_t imdmeas_spectrum_dbfs (imdmeas_state_t * state, const float * x, size_t x_len, float * out, size_t max_out)
DC-centred dBFS magnitude spectrum of a capture (length nfft).
size_t imdmeas_spectrum_dbfs_max_out (imdmeas_state_t * state)
Capacity (== nfft) of the spectrum_dbfs output buffer.

Detailed Description

Drive two equal-amplitude tones f1<f2; the analyser finds them as the two strongest lobes, integrates each fundamental and the intermodulation products (2f1-f2, 2f2-f1 for IMD3; f2-f1 for IMD2) over their window main lobes (folded into the analysed band), and reports the third/second-order intercepts.

Lifecycle: create -> [analyze]* -> destroy

Public Functions Documentation

function imdmeas_analyze

Two-tone IMD/TOI of a real capture (finds the two strongest tones).

imd_meas_t imdmeas_analyze (
    imdmeas_state_t * state,
    const float * x,
    size_t n_in
) 

Returns:

the IMD metric record (by value; zeroed if no two tones are found).

>>> from doppler.measure import IMDMeasure
>>> import numpy as np
>>> t = np.arange(4096)
>>> # two equal tones at 200 & 250 cycles, plus 3rd-order
>>> # products 40 dB down
>>> x = (np.cos(2*np.pi*200*t/4096) + np.cos(2*np.pi*250*t/4096)
...      + 0.01*np.cos(2*np.pi*150*t/4096)
...      + 0.01*np.cos(2*np.pi*300*t/4096)).astype(np.float32)
>>> r = IMDMeasure(n=4096, fs=1.0).analyze(x)
>>> round(r.f1, 4), round(r.f2, 4), round(r.imd3_dbc, 0)
(0.0488, 0.061, -40.0)

function imdmeas_create

Create an IMDMeasure analyser (auto Kaiser window).

imdmeas_state_t * imdmeas_create (
    size_t n,
    double fs,
    double full_scale,
    size_t bits,
    double dynamic_range_db
) 

The window is always Kaiser; its shape is auto-selected so the sidelobes sit below the requested dynamic range (see measure_resolve_dr()), keeping the resolution bandwidth as fine as n allows.

Parameters:

  • n Capture/frame length (>= 2).
  • fs Sample rate (Hz, > 0).
  • 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.
  • dynamic_range_db Explicit sidelobe/dynamic-range target (dB); used when > 0, else derived from bits.

Returns:

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


function imdmeas_destroy

Destroy an IMDMeasure analyser.

void imdmeas_destroy (
    imdmeas_state_t * state
) 

Parameters:

  • state May be NULL.

function imdmeas_reset

Reset the analyser (a no-op: each analyze() call is independent).

void imdmeas_reset (
    imdmeas_state_t * state
) 

Every analyze() / spectrum_dbfs() call re-windows and re-transforms its own capture from scratch, so nothing is carried between calls to clear. The method exists only so IMDMeasure honours the same reset() contract as every other doppler object, letting a generic pipeline reset each stage uniformly.

Parameters:

  • state The analyser (left unchanged).
>>> from doppler.measure import IMDMeasure
>>> m = IMDMeasure(n=4096, fs=1.0)
>>> m.reset()            # stateless: provided only for API uniformity
>>> m.reset() is None    # returns nothing; safe to call anytime
True

function imdmeas_spectrum_dbfs

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

size_t imdmeas_spectrum_dbfs (
    imdmeas_state_t * state,
    const float * x,
    size_t x_len,
    float * out,
    size_t max_out
) 

The same windowed, zero-padded PSD the IMD metrics are read off, laid out DC-centred (fftshifted) and normalised to dBFS for an analyzer-display backdrop. Use it to see the two fundamentals and the intermodulation products that analyze() integrates.

Parameters:

  • state The analyser.
  • x Real time-domain capture (length x_len).
  • x_len Number of input samples.
  • out Destination buffer (length >= max_out).
  • max_out Capacity of out (== nfft).

Returns:

DC-centred dBFS magnitude spectrum, one value per FFT bin (nfft).

>>> from doppler.measure import IMDMeasure
>>> import numpy as np
>>> t = np.arange(4096)
>>> x = (0.5*np.cos(2*np.pi*200*t/4096)
...      + 0.5*np.cos(2*np.pi*250*t/4096)).astype(np.float32)
>>> s = IMDMeasure(n=4096, fs=1.0).spectrum_dbfs(x)  # DC-centred dBFS
>>> s.shape
(8192,)
>>> round(float(s.max()), 1)   # each tone splits into two images
-12.0

function imdmeas_spectrum_dbfs_max_out

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

size_t imdmeas_spectrum_dbfs_max_out (
    imdmeas_state_t * state
) 



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