calibrate_weight_sine_lite
Overview
calibrate_weight_sine_lite provides a minimal, fast implementation of ADC foreground calibration using a known-frequency sinewave input. This is a simplified version of the full calibrate_weight_sine algorithm, optimized for speed and code simplicity.
Key Characteristics:
Single known-frequency calibration only (no frequency search)
Cosine-basis assumption (no dual-basis optimization)
No rank deficiency handling (binary weights only)
No harmonic rejection
Returns normalized weights only
Minimal dependencies (NumPy + SciPy only)
Syntax
from adctoolbox.calibration import calibrate_weight_sine_lite
# Basic usage
weights = calibrate_weight_sine_lite(bits, freq=0.001587)
Parameters
bits(ndarray) — Binary data matrix (N samples × M bits)Each row is one sample
Each column is a bit (MSB first)
Values must be 0 or 1
freq(float) — Normalized frequency (f_in / f_s)Must be known precisely
Range: 0 < freq < 0.5
Returns
weights (ndarray) — Calibrated bit weights normalized to [0, 1]
Length M (bit width)
Normalized by sinewave magnitude
Largest weight = 1.0
To get actual ADC weights:
true_weights = 2.0 ** np.arange(bit_width - 1, -1, -1)
recovered_weights_scaled = weights * np.max(true_weights)
Algorithm
Mathematical Model
The ADC output can be modeled as:
y(n) = Σ w_i · b_i(n) = A·cos(2πfn) + B·sin(2πfn) + C
where:
y(n)= reconstructed analog signalw_i= weight of bit i (unknown)b_i(n) ∈ {0, 1}= binary value of bit i at sample nf= normalized frequency (f_in/f_s)A, B= sinewave amplitude coefficientsC= DC offset
Least Squares Formulation
With the cosine-basis assumption (A = 1):
[B | 1 | sin(2πfn)] × [w; C; B] = -cos(2πfn)
In matrix form:
┌ ┐ ┌ ┐ ┌ ┐
│ b_0(0) b_1(0) ··· b_M-1(0) 1 sin(2πf·0) │ │ w_0 │ │ -cos(2πf·0) │
│ b_0(1) b_1(1) ··· b_M-1(1) 1 sin(2πf·1) │ × │ w_1 │ = │ -cos(2πf·1) │
│ ⋮ ⋮ ⋱ ⋮ ⋮ ⋮ │ │ ⋮ │ │ ⋮ │
│ b_0(N-1) ··· b_M-1(N-1) 1 sin(2πf·(N-1)) │ │w_M-1│ │-cos(2πf·N-1)│
└ ┘ │ C │ └ ┘
│ B │
└ ┘
Algorithm Steps
Build Basis Functions
t = np.arange(n_samples) phase = 2.0 * np.pi * freq * t cos_basis = np.cos(phase) sin_basis = np.sin(phase)
Construct Design Matrix
offset_col = np.ones((n_samples, 1)) A = np.column_stack([bits, offset_col, sin_basis]) b = -cos_basis
Solve Least Squares
coeffs, _, _, _ = scipy.linalg.lstsq(A, b)
Extract and Normalize Weights
weights_raw = coeffs[:bit_width] sin_coeff = coeffs[-1] norm_factor = np.sqrt(1.0 + sin_coeff**2) weights = weights_raw / norm_factor
The normalization accounts for actual sinewave amplitude:
Amplitude = sqrt(A² + B²) = sqrt(1 + B²)
Polarity Correction
if np.sum(weights) < 0: weights = -weights
Examples
Example 1: Basic Calibration
import numpy as np
from adctoolbox.calibration import calibrate_weight_sine_lite
# Generate test data (12-bit ADC, 8192 samples, freq = 13/8192)
n_samples = 8192
bit_width = 12
freq_true = 13 / n_samples
# Create ideal sinewave and quantize
t = np.arange(n_samples)
signal = 0.5 * np.sin(2 * np.pi * freq_true * t + np.pi/4) + 0.5
quantized = np.clip(np.floor(signal * (2**bit_width)), 0, 2**bit_width - 1).astype(int)
# Extract bits (MSB first)
bits = (quantized[:, None] >> np.arange(bit_width - 1, -1, -1)) & 1
# Run calibration
recovered_weights = calibrate_weight_sine_lite(bits, freq=freq_true)
# Scale to actual ADC weights
true_weights = 2.0 ** np.arange(bit_width - 1, -1, -1)
recovered_weights_scaled = recovered_weights * np.max(true_weights)
print(f"True weights: {true_weights}")
print(f"Recovered weights: {recovered_weights_scaled}")
Expected Output:
True weights: [2048. 1024. 512. 256. 128. 64. 32. 16. 8. 4. 2. 1.]
Recovered weights: [2048.0 1024.0 512.0 256.0 128.0 64.0 32.0 16.0 8.0 4.0 2.0 1.0]
Example 2: With SNDR Calculation
from adctoolbox import analyze_spectrum
# Compute calibrated signal
calibrated_signal = bits @ recovered_weights_scaled
# Compute ideal signal
adc_amplitude = 2**bit_width / 2.0
ideal_signal = adc_amplitude * np.sin(2 * np.pi * freq_true * t + np.pi/4) + adc_amplitude
error_signal = calibrated_signal - ideal_signal
# Calculate SNDR
sndr_before = analyze_spectrum(quantized)['sndr_db']
sndr_calc = 10 * np.log10(np.mean(ideal_signal**2) / np.mean(error_signal**2))
print(f"SNDR before: {sndr_before:.2f} dB")
print(f"SNDR after: {sndr_calc:.2f} dB")
print(f"ENOB: {(sndr_calc - 1.76) / 6.02:.2f} bits")
Limitations
1. Known Frequency Required
The function requires the input frequency to be precisely known. Unlike the full calibrate_weight_sine, it does not perform frequency search or refinement.
Workaround: Use calibrate_weight_sine with force_search=True if frequency is unknown.
2. Binary Weights Only (No Redundancy)
The algorithm does not handle rank deficiency or redundant weights. For ADCs with:
Redundant bits (e.g.,
[128, 128, 64, 32, ...])Identical weights
Linear dependencies between bits
The least squares solution may:
Collapse redundant weights to zero
Produce numerically unstable results
Fail to recover the full code range
Example Failure:
# Redundant weights: two bits with weight 128
true_weights = np.array([2048, 1024, 512, 256, 128, 128, 64, 32, 16, 8, 4, 2])
# Calibration may recover:
recovered = np.array([2048, 1024, 512, 256, 128, 0, 64, 32, 16, 8, 4, 2])
# ^
# Redundant bit collapsed!
Why this is wrong:
Original sum: 4222 (can represent 0-4095 with redundancy)
Collapsed sum: 4094 (cannot represent code 4095!)
Lost error correction capability
Workaround: Use the full calibrate_weight_sine which includes _patch_rank_deficiency handling.
3. Low Signal Amplitude
At very low input amplitudes (< -6 dBFS), MSB bits may have limited activity, leading to:
Ill-conditioned least squares matrix
Numerically unstable weights (values in trillions)
Poor SNDR estimates
Example:
At -12 dBFS:
Recovered weights: [1472874591589.4, 1472874590565.5, 511.9, 256.0, ...]
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
Numerically unstable MSB weights
Recommendation: Use input signals at or near full scale (0 dBFS to -3 dBFS) for best results.
4. No Harmonic Rejection
The algorithm fits only the fundamental frequency, without excluding harmonics from the error term. This can lead to:
Harmonic distortion biasing the weight estimates
Reduced accuracy for ADCs with significant INL/DNL
Workaround: Use calibrate_weight_sine with harmonic_order > 1 to exclude harmonics.
Performance
Computational Complexity
Time Complexity: O(N·M² + M³)
N = number of samples
M = bit width
Dominated by least squares solve (SVD decomposition)
Space Complexity: O(N·M)
Storage for design matrix
Typical Performance (12-bit ADC, Intel i7):
N = 2¹² (4096 samples): ~3 ms
N = 2¹³ (8192 samples): ~5 ms
N = 2¹⁶ (65536 samples): ~40 ms
Accuracy
Weight Recovery (ideal conditions):
Error < 10⁻⁵ LSB (normalized)
Phase-independent performance
ENOB: ~11-12 bits (for 12-bit ADC at 0 dBFS)
Amplitude Requirements:
Amplitude (dBFS) Weight Error ENOB
----------------- ------------- ------
0 to -3 < 1e-5 LSB 11-12 bits
-6 to -3 < 1e-4 LSB 10-11 bits
-12 to -6 > 1e+9 LSB Unstable
< -12 > 1e+12 LSB Failed
Comparison with Full Version
Feature |
Lite Version |
Full Version |
|---|---|---|
Frequency search |
❌ No (requires known freq) |
✅ Yes (coarse + fine search) |
Rank deficiency handling |
❌ No |
✅ Yes (via nominal weights) |
Redundant weights |
❌ Not supported |
✅ Fully supported |
Harmonic rejection |
❌ No |
✅ Yes (configurable order) |
Multi-dataset calibration |
❌ No |
✅ Yes |
Numerical conditioning |
❌ Basic |
✅ Column scaling + patching |
Return type |
ndarray (weights only) |
dict (weights + diagnostics) |
Code size |
~40 lines |
~600+ lines (with helpers) |
Typical runtime (N=8192) |
~5 ms |
~20-50 ms |
When to Use Lite Version
✅ Use lite version when:
Frequency is precisely known
Binary weighted ADC (no redundancy)
Speed is critical
Simple embedded deployment
Minimal code footprint needed
❌ Use full version when:
Unknown or imprecise frequency
Redundant ADC architecture
Need harmonic rejection
Multi-dataset calibration
Production calibration requiring robustness
References
IEEE Standard 1057-2017: “IEEE Standard for Digitizing Waveform Recorders”
Vogel, C., & Johansson, H. (2006). “Time-interleaved analog-to-digital converters: Status and future directions.” IEEE Transactions on Circuits and Systems I, 53(11), 2386-2394.
Jin, H., & Lee, E. K. F. (1992). “A digital-background calibration technique for minimizing timing-error effects in time-interleaved ADCs.” IEEE Transactions on Circuits and Systems II, 47(7), 603-613.
MATLAB Signal Processing Toolbox:
sinefitweightsdocumentation
See Also
calibrate_weight_sine - Full version with frequency search and rank handling
analyze_spectrum - Spectral analysis for SNDR/ENOB calculation
fit_sine_4param - IEEE 1057 sinewave fitting