Digital Output Analysis (dout)#

The dout module provides tools for analyzing digital ADC outputs and bit-weighted architectures.

Weight Calibration#

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[源代码]#

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).

参数:
  • 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.

返回:

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.

返回类型:

dict

adctoolbox.calibration.calibrate_weight_sine_lite(bits: ndarray, freq: float) ndarray[源代码]#

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.

Bit And Weight Analysis#

analyze_weight_radix returns radix, wgtsca, and effres. effres is computed from the significant absolute weights as log2(sum(abs_w_sig) / min(abs_w_sig) + 1). It is a theoretical weight-list span, not a missing-code, DNL, INL, or SAR reachability proof.

adctoolbox.analyze_bit_activity(bits: ndarray, create_plot: bool = True, ax=None, title: str | None = None) ndarray[源代码]#

Analyze and plot the percentage of 1's in each bit.

Ideal SAR ADC should have 50% activity for all bits. Deviations indicate input signal DC offset or amplitude clipping.

参数:
  • bits (np.ndarray) -- Binary matrix (N x B), N=samples, B=bits (MSB to LSB)

  • create_plot (bool, default=True) -- If True, create bar chart visualization

  • ax (plt.Axes, optional) -- Axes to plot on. If None, uses current axes (plt.gca())

  • title (str, optional) -- Title for the plot. If None, uses default title

返回:

Percentage of 1's for each bit (1D array of length B)

返回类型:

np.ndarray

adctoolbox.analyze_overflow(raw_code: ndarray, weight: ndarray, ofb: int | None = None, create_plot: bool = True, ax=None, title: str | None = None) tuple[ndarray, ndarray, ndarray, ndarray][源代码]#

Analyze residue distribution at each bit position for overflow detection.

Calculates normalized residue (remaining bits weighted sum) and detects overflow conditions where residue exceeds [0, 1] range.

参数:
  • raw_code (np.ndarray) -- Digital codes array, shape (N, M) where N=samples, M=bits (MSB first)

  • weight (np.ndarray) -- Weight array for each bit, shape (M,)

  • ofb (int, optional) -- Overflow bit position for overflow detection. Default is M (check at MSB, MATLAB convention: 1=LSB, M=MSB)

  • create_plot (bool, default=True) -- If True, generate residue distribution visualization

  • ax (plt.Axes, optional) -- Axes to plot on. If None, uses current axes (plt.gca())

  • title (str, optional) -- Title for the plot. If None, no title is set

返回:

  • range_min: Minimum normalized residue per bit (shape M,)

  • range_max: Maximum normalized residue per bit (shape M,)

  • ovf_percent_zero: Underflow percentage per bit (shape M,)

  • ovf_percent_one: Overflow percentage per bit (shape M,)

返回类型:

tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]

备注

  • A bit segment is the sub-code formed from one bit to the LSB

  • Residue is normalized by dividing by the sum of weights in the segment

  • Matches MATLAB ovfchk.m behavior exactly

adctoolbox.analyze_weight_radix(weights: ndarray, create_plot: bool = True, ax=None, title: str | None = None) dict[源代码]#

Analyze absolute bit weights, radix ratios, and weight-list resolution.

Pure binary: radix = 2.00. Sub-radix/redundancy: radix < 2.00. effres is a theoretical resolution estimate from the supplied weight dynamic range, not a missing-code/DNL proof.

参数:
  • weights (np.ndarray) -- Bit weights (1D array), nominally from MSB to LSB for radix plotting. Effective-resolution analysis uses sorted absolute magnitudes, so negative trim weights count by magnitude.

  • create_plot (bool, default=True) -- If True, create line plot with radix annotations

  • ax (plt.Axes, optional) -- Axes to plot on. If None, uses current axes (plt.gca())

  • title (str, optional) -- Title for the plot. If None, uses default title

返回:

radix:

Radix between consecutive input-order weights, abs(weight[i-1]) / abs(weight[i]). The first entry is NaN.

wgtsca:

Scale factor that maps the significant absolute weights closest to integer LSB units.

effres:

Effective resolution in bits, log2(sum(abs_w_sig) / min(abs_w_sig) + 1).

返回类型:

dict

备注

The significant set abs_w_sig is formed by sorting abs(weights) in descending order, then dropping the tail after the first adjacent ratio >= 3. This excludes very small trim/noise weights from effres.

effres is useful for questions like "how many bits does this SAR weight list span?" It does not verify SAR decision reachability, code monotonicity, missing codes, DNL/INL, comparator noise, or sampling noise.

What to look for in radix values: - Radix = 2.00: Binary scaling (SAR, pure binary) - Radix < 2.00: Redundancy or sub-radix (e.g., 1.5-bit/stage → ~1.90) - Radix > 2.00: Unusual, may indicate calibration error - Consistent pattern: Expected architecture behavior - Random jumps: Calibration errors or bit mismatch

ENOB Analysis#

adctoolbox.analyze_enob_sweep(bits: ndarray, freq: float | None = None, harmonic_order: int = 1, osr: int = 1, win_type: str = 'hamming', calibration_mode: str = 'prefix_of_full_calibration', frequency_policy: str = 'python', create_plot: bool = True, ax=None, title: str | None = None, verbose: bool = False) tuple[ndarray, ndarray][源代码]#

Sweep ENOB vs number of bits used for calibration.

Incrementally adds bits (MSB to LSB) and measures ENOB after calibration to understand diminishing returns and optimal bit count.

参数:
  • bits (np.ndarray) -- Binary matrix (N samples x M bits, MSB to LSB order)

  • freq (float, optional) -- Normalized frequency (0-0.5). If None, auto-detect from data

  • harmonic_order (int, default=1) -- Harmonic order for calibrate_weight_sine

  • osr (int, default=1) -- Oversampling ratio for spectrum analysis

  • win_type (str, default='hamming') -- Window function: 'boxcar', 'hann', 'hamming'

  • calibration_mode ({'prefix_of_full_calibration',) -- 'recalibrate_each_subset'}, default='prefix_of_full_calibration' ENOB sweep calibration policy. 'prefix_of_full_calibration' calibrates all bits once and sweeps prefixes of the full-weight solution. 'recalibrate_each_subset' estimates the frequency once when needed, then recalibrates each bit-prefix subset independently.

  • frequency_policy ({'python', 'matlab'}, default='python') -- Coarse frequency estimator passed to calibrate_weight_sine when automatic frequency search is requested.

  • create_plot (bool, default=True) -- If True, plot ENOB sweep curve

  • ax (plt.Axes, optional) -- Axes to plot on. If None, uses current axes (plt.gca())

  • title (str, optional) -- Title for the plot. If None, uses default title

  • verbose (bool, default=False) -- If True, print progress messages

返回:

  • enob_sweep: ENOB for each bit count (length M)

  • n_bits_vec: Bit counts from 1 to M

返回类型:

tuple[np.ndarray, np.ndarray]

备注

The default 'prefix_of_full_calibration' mode answers the calibration ablation question: "after a full-bit calibration, how much performance remains if lower-bit terms are removed?" Use 'recalibrate_each_subset' only when intentionally asking: "if only the first n bits are available, how well can that n-bit subsystem be calibrated?"

What to look for in the plot: - Increasing trend: More bits improve resolution - Plateau: Additional bits don't help (noise/distortion limited) - Decrease: Extra bits add noise/calibration errors

Visualization#

adctoolbox.plot_residual_scatter(signal: ndarray, bits: ndarray, weights: ndarray | None = None, pairs: list[tuple[int, int]] | None = None, alpha: float | str = 'auto', create_plot: bool = True) dict[源代码]#

Plot partial-sum residuals of an ADC bit matrix.

For each pair (x_bit, y_bit), computes the residual after subtracting the first x_bit (or y_bit) weighted bits from the input signal, then plots y-residual vs x-residual as a scatter plot.

参数:
  • signal (np.ndarray) -- Ideal input signal to the ADC (1D, length N).

  • bits (np.ndarray) -- Raw ADC output bit matrix (N x M), MSB-first columns.

  • weights (np.ndarray, optional) -- Bit weights (length M). Default: binary [2^(M-1), ..., 1].

  • pairs (list of (int, int), optional) -- Pairs of bit indices whose residuals are plotted. Range: 0 (raw signal) to M (residual after all bits). Default: [(0, M), (1, M), ..., (M-1, M)].

  • alpha (float or 'auto', default='auto') -- Marker transparency. 'auto' scales as clamp(1000/N, 0.1, 1.0).

  • create_plot (bool, default=True) -- If True, create scatter subplots.

返回:

'pairs': list of (x_bit, y_bit) tuples used 'residuals_x': list of 1D arrays, one per pair 'residuals_y': list of 1D arrays, one per pair

返回类型:

dict