File measure_core.h¶
File List > inc > measure > measure_core.h
Go to the documentation of this file
#ifndef MEASURE_CORE_H
#define MEASURE_CORE_H
#include "clib_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ── auto-window design policy ──────────────────────────────────────────────
* The measurement objects pick their Kaiser window automatically: the user
* states a target dynamic range (directly, or implied by the ADC bit depth)
* and the analyser chooses the *minimum* Kaiser beta whose sidelobes sit below
* that range — so window leakage never caps SFDR/SNR — while keeping the main
* lobe (hence resolution bandwidth) as narrow as the data allows. */
/* Internal zero-pad factor (nfft = next_pow2(n * MEASURE_PAD)). */
#define MEASURE_PAD 2u
/* Sidelobe headroom below the ideal converter SNR: a B-bit ADC's spur/noise
* floor sits at -(6.02*B+1.76) dBc, so target sidelobes this much deeper to be
* sure window leakage stays under the floor being measured. */
#define MEASURE_DR_MARGIN_DB 12.0
/* Dynamic-range target when neither `bits` nor an explicit override is given
* (general DUT): deep enough for ~19-bit measurements. */
#define MEASURE_DR_DEFAULT_DB 120.0
/* Extra main-lobe widths excluded past the first null when searching for spurs,
* so a component's near-in sidelobes are never mistaken for a spur. */
#define MEASURE_SPUR_SIDELOBES 1.0
static inline double
measure_dr_from_bits (size_t bits)
{
return 6.02 * (double)bits + 1.76 + MEASURE_DR_MARGIN_DB;
}
static inline double
measure_resolve_dr (double dynamic_range_db, size_t bits)
{
if (dynamic_range_db > 0.0)
return dynamic_range_db;
if (bits > 0)
return measure_dr_from_bits (bits);
return MEASURE_DR_DEFAULT_DB;
}
typedef struct {
double snr;
double sinad;
double thd;
double thd_pct;
double thd_n;
double sfdr_dbc;
double sfdr_dbfs;
double enob;
double enob_fs;
double noise_floor_dbfs;
double fund_freq;
double fund_dbfs;
double worst_spur_freq;
double worst_spur_dbc;
int worst_spur_is_harm;
double rbw_hz;
double enbw_hz;
double bin_hz;
size_t lobe_bins;
size_t n_noise_bins;
double proc_gain_db;
double amp_uncert_db;
double floor_uncert_db;
} tone_meas_t;
typedef struct {
double rms;
double peak;
double crest_db;
double papr_db;
double dc_offset;
double fs_util_pct;
} time_stats_t;
typedef struct {
double f1;
double f2;
double p1_dbfs;
double p2_dbfs;
double imd2_dbc;
double imd3_dbc;
double imd2_freq;
double imd3_lo_freq;
double imd3_hi_freq;
double toi_dbfs;
double soi_dbfs;
double rbw_hz;
} imd_meas_t;
typedef struct {
double npr_db;
double inband_psd_dbfs;
double notch_psd_dbfs;
size_t n_inband_bins;
size_t n_notch_bins;
double rbw_hz;
} npr_meas_t;
/* ── capture-planning helpers ──────────────────────────────────────────────
* Pure functions that answer "how much data, and at what frequency?" for an
* IEEE-1241 single-tone test. See docs/design/measurement-suite.md. */
size_t measure_min_samples(double fs, double target_rbw, size_t bits,
double dynamic_range_db, int complex_input);
size_t measure_rec_nfft(size_t n, size_t pad);
double measure_proc_gain(size_t nfft);
double dp_coherent_freq(double fs, double f_target, size_t N);
#ifdef __cplusplus
}
#endif
#endif /* MEASURE_CORE_H */