ADC Behavioral Models (models)#

The models module provides ADC forward models that convert analog input samples into digital decision streams and reconstruct analog output values.

SAR Models#

adctoolbox.sar_convert(vin: ndarray, weights: ndarray, quant_range: tuple[float, float] = (0.0, 1.0), sampling_noise_rms: float = 0.0, comparator_noise_rms: float = 0.0, rng: Generator | None = None) ndarray[source]#

Batch SAR conversion.

Per-sample algorithm:

vin_sampled = vin + sampling_noise
v_dac = 0
for j in range(B):
    v_test = v_dac + weights[j]
    bit[j] = 1 if (vin_sampled + comparator_noise > v_test) else 0
    if bit[j]: v_dac = v_test

Vectorized over samples so the whole batch runs in one Python loop of length B (typically 4-20 iterations), not N (typically 10⁴-10⁶). Multi-channel or multi-run inputs are supported by preserving the input shape and appending one bit axis to the returned codes.

Parameters:
  • vin (array-like of shape (...,)) – Input voltage trace or batch of traces. Interpreted relative to quant_range.

  • weights (array-like of shape (B,)) – Actual analog CDAC weights (MSB first). Resolution and redundancy are inferred from this vector. Use sar_ideal_weights() for an ideal binary or redundant array, sar_apply_cap_mismatch() for unit-cap/Pelgrom-style capacitor mismatch.

  • quant_range (tuple(float, float), default (0.0, 1.0)) – ADC input and output range (v_min, v_max). This mirrors ADC_Signal_Generator.apply_quantization_noise(..., quant_range=...).

  • sampling_noise_rms (float, default 0.0) – Sampled input noise RMS, in the same unit as vin. One random value is added per sample before the SAR bit trials.

  • comparator_noise_rms (float, default 0.0) – Comparator input-referred thermal noise RMS, in the same unit as vin. A fresh random value is used for each bit decision.

  • rng (np.random.Generator, optional) – RNG for sampling and comparator noise.

Returns:

codes – Raw bit decisions, MSB at column 0. Pass to sar_reconstruct() for the analog estimate, or to a calibration routine (e.g. adctoolbox.calibration.calibrate_weight_sine()) for weight estimation.

Return type:

ndarray of shape vin.shape + (B,), dtype int8

Notes

The model does NOT include DAC settling errors, metastability delay, charge-injection artifacts, or PVT drift. For those, supplement with a Spectre / Verilog-A simulation.

adctoolbox.sar_reconstruct(codes: ndarray, weights: ndarray, quant_range: tuple[float, float] = (0.0, 1.0)) ndarray[source]#

Linear weighted-sum reconstruction: codes @ digital_weights.

weights are the digital reconstruction weights, which usually match the analog CDAC weights in an ideal model. With mismatch, keep the two roles explicit: encode with actual analog weights, then reconstruct with the nominal, calibrated, or actual digital weights you want to evaluate. Subtract the sample mean before spectrum analysis to remove the DC offset introduced by the unipolar encoding.

Parameters:
  • codes (ndarray of shape (..., B)) – Raw bit decisions from sar_convert().

  • weights (ndarray of shape (B,)) – Digital reconstruction weights. Use the nominal weights for an “uncalibrated” output; use cal-estimated or actual weights to assess calibration quality.

  • quant_range (tuple(float, float), default (0.0, 1.0)) – Output voltage range (v_min, v_max). The default preserves the normalized reconstruction convention.

Returns:

aout – Reconstructed analog estimate, range [v_min, v_min + (v_max - v_min) * sum(weights)].

Return type:

ndarray of shape codes.shape[:-1]

adctoolbox.sar_ideal_weights(num_bits: int, redundant_bit: int | None = None) ndarray[source]#

Generate ideal binary CDAC weights, optionally with one duplicated bit.

The normalization base is the sum of all bit weights plus one LSB: denom = sum(raw_bit_weights) + raw_lsb. In other words, a 4-bit ideal ADC uses [8, 4, 2, 1] / (8+4+2+1+1) = /16, not endpoint-normalized / 15 weights. With one duplicated redundant bit, [8, 4, 4, 2, 1] normalizes by 20.

Parameters:
  • num_bits (int) – Architectural resolution (number of distinct decision steps).

  • redundant_bit (int, optional) – If given, the cap at index redundant_bit is duplicated, yielding an output array of length num_bits + 1. Use to model sub-radix-2 SAR with one bit of redundancy. Architectural resolution stays at num_bits — the redundancy adds error-correction margin, not bits.

Returns:

weights – Cap weights, MSB at index 0. The denominator is sum(raw_bit_weights) + raw_lsb. If redundant_bit is used, the duplicated cap participates in both the sum and the resulting overrange / correction margin.

Return type:

ndarray of shape (B,)

Examples

>>> import numpy as np
>>> w = sar_ideal_weights(4)
>>> np.allclose(w, [8/16, 4/16, 2/16, 1/16])
True
>>> w = sar_ideal_weights(4, redundant_bit=1)
>>> len(w) == 5 and np.allclose(w, [8/20, 4/20, 4/20, 2/20, 1/20])
True
adctoolbox.sar_apply_cap_mismatch(weights: ndarray, sigma: float, rng: Generator | None = None, cap_units: ndarray | None = None) ndarray[source]#

Realize unit-cap/Pelgrom-style CDAC mismatch.

sigma is the RMS relative mismatch of a single unit capacitor. A bit made from n unit capacitors gets relative RMS mismatch sigma / sqrt(n). This captures the usual sigma(C) / C 1/sqrt(C) trend: MSB capacitors are larger and therefore have smaller relative mismatch than LSB capacitors.

By default, unit counts are inferred from the normalized weights by dividing by the smallest positive weight. For ideal binary weights this gives [8, 4, 2, 1] for a 4-bit ADC and [8, 4, 4, 2, 1] for a redundant array. Pass cap_units explicitly for custom capacitor arrays.

Parameters:
  • weights (ndarray of shape (B,)) – Nominal analog CDAC weights, typically from sar_ideal_weights().

  • sigma (float) – RMS relative mismatch of one unit capacitor. For example, 0.01 is 1% RMS for a 1-Cu element; an 8-Cu MSB then has 0.01/sqrt(8) relative RMS.

  • rng (np.random.Generator, optional) – Numpy random generator. Use a deterministic seed to lock one chip.

  • cap_units (ndarray of shape (B,), optional) – Unit capacitor counts or relative capacitor sizes for each weight. Values must be positive. If omitted, they are inferred from weights / min(weights).

Returns:

perturbed_weights – Cap weights with unit-cap-scaled gaussian mismatch applied. The result is NOT re-normalized.

Return type:

ndarray of shape (B,)

adctoolbox.sar_apply_mismatch(weights: ndarray, sigma: float, rng: Generator | None = None) ndarray[source]#

Legacy per-weight gaussian mismatch helper.

This preserves the pre-0.8.2 behavior where each supplied weight receives the same relative RMS perturbation. For Pelgrom/unit-cap-scaled mismatch, use sar_apply_cap_mismatch().