Calibration (calibration)#

Start with Supervised foreground calibration workflows for supervised foreground correction and Supervised ADC post-correction: meaning, mathematics and evidence for mathematical definitions and scope.

Foreground bit-weight identification#

These functions identify affine reconstruction weights from a dedicated sine capture. The full and lite variants belong to the same calibration family.

adctoolbox.calibrate_weight_sine(bits: ndarray | list[ndarray], freq: float | ndarray | None = None, force_search: bool | None = None, nominal_weights: ndarray | None = None, harmonic_order: int = 1, learning_rate: float = 0.5, reltol: float = 1e-12, max_iter: int = 100, verbose: int = 0, frequency_policy: str = 'python') → dict[source]#

FGCalSine — Foreground calibration using a sinewave input

This function estimates per-bit weights and a DC offset for an ADC by fitting the weighted sum of raw bit columns to a sine series at a given (or estimated) normalized frequency Fin/Fs. Harmonic terms above the fundamental are fitted reference/nuisance terms: they can prevent source or test-chain harmonics from contaminating weight estimation, but they do not remove those harmonics from calibrated_signal. It optionally performs a coarse and fine frequency search to refine the input tone frequency.

Implementation uses a unified pipeline where single-dataset calibration is treated as a special case of multi-dataset calibration (N=1).

Parameters:
  • bits (ndarray or list of ndarrays) – Binary data as matrix (N rows by M cols, N is data points, M is bitwidth). Each row is one sample; each column is a bit/segment. Can also be a list of arrays for multi-dataset calibration.

  • freq (float, array-like, or None, optional) – Normalized frequency Fin/Fs. Default is None (triggers auto frequency search). Use None for automatic frequency search, a float for one frequency shared by all datasets, or an array-like value for per-dataset frequencies in multi-dataset mode.

  • force_search (bool or None, optional) – Frequency fine-search policy. Default is None, which refines automatically estimated frequencies while keeping explicitly provided frequencies fixed. Set True to refine provided frequencies too, or False to disable fine search unless a zero frequency placeholder remains.

  • frequency_policy ({"python", "matlab"}, optional) – Coarse frequency estimator used when freq is None or zero. "python" preserves the historical Python estimator. "matlab" uses a MATLAB wcalsin(freq=0) compatible estimator based on nominally reconstructed rank-patched bit prefixes. Explicit nonzero frequencies are not changed by this option. Default is "python".

  • nominal_weights (array-like, optional) – Nominal bit weights (only effective when rank is deficient). Default is 2^(M-1) down to 2^0.

  • harmonic_order (int, optional) – Number of harmonic terms included in the fitted reference. Default is 1 (fundamental only). Values greater than 1 include H2/H3/… as nuisance terms in ideal and exclude them from error. This is useful for source/test-chain harmonic nuisance modeling; it should not be interpreted as proof that ADC harmonic distortion has been removed from calibrated_signal.

  • learning_rate (float, optional) – Adaptive learning rate for frequency updates (0..1), default is 0.5.

  • reltol (float, optional) – Relative error tolerance for convergence, default is 1e-12.

  • max_iter (int, optional) – Maximum iterations for fine frequency search, default is 100.

  • verbose (int, optional) – Print frequency search progress (1) or not (0), default is 0.

Returns:

Calibration result containing weight, offset, calibrated_signal, ideal, error, and refined_frequency. ideal includes fitted harmonics up to harmonic_order; error is the residual after subtracting that fitted reference. The returned snr_db and enob are calibration fitted-residual metrics, not FFT dynamic SNDR/ENOB when harmonic_order is greater than 1. Use spectrum analysis on calibrated_signal for ADC dynamic SNDR/THD/HDx. The rank_patch entry reports any dropped or merged rank-deficient bit columns. Array-valued entries are returned as a single array for single-dataset input or as a list of arrays for multi-dataset input. initial_frequency records the coarse frequency used before fine search, and frequency_policy records the coarse-estimator policy.

The calibrated waveform fields use scale_convention == "solver_unit_sine": the least-squares solve fixes the fitted fundamental sine magnitude to one. Before interpreting dBFS or NSD against a physical ADC full-scale, rescale the result with scale_calibration_output and pass an explicit full-scale range to the spectrum analyzer.

Return type:

dict

adctoolbox.calibration.calibrate_weight_sine_lite(bits: ndarray, freq: float) → ndarray[source]#

Minimal calibration at known frequency. Returns normalized weights. Expects well-conditioned binary data (N samples x M bits).

The returned weights are in the same solver-unit-sine convention as calibrate_weight_sine: the fitted fundamental sine magnitude is fixed to one for identifiability. Apply an explicit scale factor before using the reconstructed waveform for physical dBFS or NSD interpretation.

Scaling and identification diagnostics#

These helpers support calibration; they are not separate identification methods.

adctoolbox.scale_calibration_output(result: dict[str, Any], *, scale: float | None = None, target_weights: ndarray | list[float] | tuple[float, ...] | None = None, target_sine_peak: float | None = None, inplace: bool = False) → dict[str, Any][source]#

Scale calibrate_weight_sine output to a chosen ADC convention.

calibrate_weight_sine fixes the fitted fundamental sine magnitude to one so that the least-squares problem is identifiable. The returned weight, calibrated_signal, ideal, and error are therefore in solver-unit-sine scale by default, not automatically in an ADC voltage or code full-scale convention.

This helper applies a single linear scale factor after calibration. Ratio metrics such as snr_db and enob are intentionally left unchanged.

Exactly one scale source must be supplied:

  • scale: direct linear factor.

  • target_weights: use sum(target_weights) / sum(result["weight"]).

  • target_sine_peak: map the solver unit sine peak to this peak value.

adctoolbox.diagnose_calibration_matrix(bits, nominal_weights=None, weights=None, *, binary_tol: float = 1e-12, constant_tol: float = 1e-12, rank_tol: float | None = None, weight_tol: float = 1e-12) → dict[source]#

Summarize rank, conditioning, binary-ness, and weight-shape diagnostics.

This helper is intentionally diagnostic-only: it does not reject inputs and does not change calibration behavior. It is useful before or after sine-based weight calibration when checking whether the design matrix has enough observable information, whether a matrix still looks like a physical 0/1 bit-code matrix, and whether solved weights look physically plausible.

Parameters:
  • bits – Calibration design matrix, or a list of matrices to stack vertically. Matrices are interpreted as (samples, columns); wide matrices are transposed to match the calibration helpers’ orientation convention.

  • nominal_weights – Optional nominal weights used for scale-invariant shape comparison.

  • weights – Optional recovered weights to diagnose.

  • binary_tol – Tolerance for considering an entry close to 0 or 1.

  • constant_tol – Column range at or below this value is treated as near-constant.

  • rank_tol – Optional absolute SVD/rank tolerance. If omitted, NumPy-style default tolerance max(shape) * eps * s_max is used.

  • weight_tol – Tolerance for treating weights as negative.

Returns:

Diagnostic fields for the stacked matrix and optional weights.

Return type:

dict

Other calibration workflows#

TI sine mismatch extraction and correction are documented in Time-Interleaved ADC Analysis (timeinterleave). See Supervised foreground calibration workflows for foreground benchmarks.

Supervised foreground correction#

References must be supplied explicitly. These functions fit a direct correction mapping, distinct from forward distortion characterization with fit_static_nonlin. Models are JSON-compatible dictionaries. Learned weights describe a digital correction, not individual ADC component parameters. Normal operation evaluates a frozen model without a reference or adaptation. See Supervised ADC post-correction: meaning, mathematics and evidence for equations and applicability.

adctoolbox.build_calibration_features(samples, *, history=0, state=None)[source]#

Build current-first delayed features without fabricating startup samples.

Parameters:
  • samples (array_like) – Shape (N,) or (N, C), in a fixed channel order and scale.

  • history (int) – Number of preceding samples required in each feature row.

  • state (array_like or None) – Previous returned state for a contiguous stream. Pass None at the start of every independent record; never connect unrelated waveforms.

Returns:

features has columns [current channels, lag-1 channels, …]. sample_indices selects matching labels from this input block. state contains at most history final input rows, oldest first. A short startup block may return zero feature rows.

Return type:

dict

adctoolbox.fit_calibration_polynomial(features, reference, *, degree=3, ridge=1e-08)[source]#

Fit a direct inverse correction to an aligned, supplied reference.

All monomials of total degree <= degree are included. Features are scaled using training data only. ridge penalizes coefficients in that scaled basis: mean squared reference error + ridge * sum(non-intercept weights**2). The mapping is nonlinear in inputs for degree > 1, although fitting is linear in coefficients. More than 4096 terms is rejected to bound memory.

Returns a dict with a JSON-compatible model and fitting diagnostics. Apply the model to independent data using apply_calibration(). No extrapolation accuracy, monotonicity or reference correctness is implied. design_condition_number diagnoses the standardized, unregularized design; it is None when numerically rank deficient, including underdetermined fits. Full rank and a finite condition number do not establish joint coverage.

adctoolbox.fit_calibration_mlp(features, reference, *, validation_features, validation_reference, hidden_units=16, max_iterations=200, l2=1e-06, seed=1)[source]#

Fit a small tanh residual MLP, selecting an iterate on held-out data.

A training-only affine baseline is frozen; the fully trained one-hidden-layer network learns its residual. L-BFGS uses full-batch squared error and L2 weight regularization. Normalization and residual scale are fixed from training data. The selected model minimizes validation reference MSE over the initial state and optimizer iterates. Validation must be separate records, not test data. Returns model, diagnostics and per-iterate history. NumPy and SciPy suffice; no neural-network dependency is required. This is foreground fitting, not online adaptation. max_iterations is an optimizer budget, not epochs. The network estimates a residual correction to the affine baseline; its weights are not physical ADC parameters. See the packaged FOREGROUND_THEORY.md for equations, reference requirements and measured-hardware literature.

adctoolbox.apply_calibration(features, model)[source]#

Apply a frozen polynomial/MLP model without refitting or changing state.

Returns calibrated_signal and a per-row outside_training_range mask. The mask checks marginal feature ranges, not joint coverage or reliability. Extrapolated values are returned without clipping. Models are ordinary JSON-compatible dictionaries produced by the fit functions.