analyze_error_by_phase#
Overview#
analyze_error_by_phase performs AM/PM (Amplitude Modulation / Phase Modulation) decomposition of ADC errors as a function of the input signal phase. This reveals whether errors are signal-dependent and whether they modulate the amplitude (AM) or timing/phase (PM) of the signal.
Syntax#
from adctoolbox import analyze_error_by_phase
# Basic usage with auto-detected frequency
result = analyze_error_by_phase(signal, show_plot=True)
# With specified frequency
result = analyze_error_by_phase(signal, norm_freq=0.123, n_bins=100,
show_plot=True)
# Exclude base noise term
result = analyze_error_by_phase(signal, include_base_noise=False,
show_plot=True)
Parameters#
signal(array_like) — Input ADC signal (sine wave excitation)norm_freq(float, optional) — Normalized frequency (f/fs), range (0, 0.5)If None: auto-detected via FFT
n_bins(int, default=100) — Number of phase bins for visualizationinclude_base_noise(bool, default=True) — Include base noise term in fittingshow_plot(bool, default=True) — Display error vs. phase plotaxes(tuple, optional) — Tuple of (ax1, ax2) for top and bottom panelsax(matplotlib axis, optional) — Single axis to split into 2 panelstitle(str, optional) — Test setup description for title
Returns#
Dictionary containing:
Numerical Results:
am_noise_rms_v— AM noise RMS (amplitude modulation)pm_noise_rms_v— PM noise RMS in voltage unitspm_noise_rms_rad— PM noise RMS in radiansbase_noise_rms_v— Base noise RMS (signal-independent)total_rms_v— Total error RMS
Validation Metrics:
r_squared_raw— R² for raw data fit (energy ratio)r_squared_binned— R² for binned data (model confidence)
Visualization Data:
bin_error_rms_v— RMS error per phase binbin_error_mean_v— Mean error per phase binphase_bin_centers_rad— Phase bin centers (radians)
Metadata:
amplitude,dc_offset,norm_freq— Fitted signal parametersfitted_signal,error,phase— Signal decomposition
Algorithm#
AM/PM Model#
Error is decomposed as:
error(φ) = AM·sin(φ) + PM·cos(φ) + base_noise
where:
AM: Amplitude modulation error (gain variation with signal level)
PM: Phase modulation error (timing jitter, settling errors)
base_noise: Signal-independent noise
φ: Signal phase
Dual-Track Analysis#
Path A (Raw): Fit all N samples → highest precision AM/PM values Path B (Binned): Compute binned statistics → visualization
Cross-validation: Path A coefficients predict Path B trend → R² metric
Examples#
Example 1: AM/PM Decomposition#
import numpy as np
from adctoolbox import analyze_error_by_phase
# Analyze ADC signal
result = analyze_error_by_phase(adc_signal, show_plot=True)
print(f"AM noise: {result['am_noise_rms_v']*1e6:.2f} µV RMS")
print(f"PM noise: {result['pm_noise_rms_rad']*1e12:.2f} pico-radians RMS")
print(f"Base noise: {result['base_noise_rms_v']*1e6:.2f} µV RMS")
print(f"Total RMS: {result['total_rms_v']*1e6:.2f} µV RMS")
print(f"R² (model fit): {result['r_squared_raw']:.4f}")
Example 2: Identify Dominant Error Mechanism#
result = analyze_error_by_phase(signal, show_plot=False)
am = result['am_noise_rms_v']
pm = result['pm_noise_rms_v']
base = result['base_noise_rms_v']
# Determine dominant error source
errors = {'AM': am, 'PM': pm, 'Base': base}
dominant = max(errors, key=errors.get)
print(f"Dominant error: {dominant}")
print(f" AM: {am*1e6:.2f} µV ({am/result['total_rms_v']*100:.1f}%)")
print(f" PM: {pm*1e6:.2f} µV ({pm/result['total_rms_v']*100:.1f}%)")
print(f" Base: {base*1e6:.2f} µV ({base/result['total_rms_v']*100:.1f}%)")
Example 3: Compare Multiple Conditions#
import matplotlib.pyplot as plt
conditions = {
'Ideal': signal_ideal,
'With Jitter': signal_jitter,
'With Gain Error': signal_gain_error,
}
fig, axes = plt.subplots(len(conditions), 2, figsize=(12, 4*len(conditions)))
for i, (name, sig) in enumerate(conditions.items()):
result = analyze_error_by_phase(sig, axes=axes[i], title=name,
show_plot=True)
print(f"{name}: AM={result['am_noise_rms_v']*1e6:.1f}µV, "
f"PM={result['pm_noise_rms_rad']*1e12:.1f}pRad")
plt.tight_layout()
plt.show()
Interpretation#
Error Type Classification#
Dominant Component |
Likely Cause |
|---|---|
AM dominant |
Gain error, amplitude-dependent distortion, residue amplifier gain variation |
PM dominant |
Clock jitter, timing errors, settling time issues |
Base noise dominant |
Thermal noise, quantization noise (signal-independent) |
AM ≈ PM |
Mixed analog impairments |
Phase Pattern Analysis#
Error vs. Phase Pattern |
Interpretation |
|---|---|
Sinusoidal (AM-like) |
Amplitude-dependent error |
Cosinusoidal (PM-like) |
Timing/phase-dependent error |
Flat (uniform) |
Signal-independent noise |
Complex shape |
Multiple error mechanisms |
R² Interpretation#
R² > 0.9: Model fits well, errors are signal-dependent
0.5 < R² < 0.9: Moderate signal dependence
R² < 0.5: Errors mostly signal-independent (random noise)
Use Cases#
Distinguish jitter from amplitude errors
Identify memory effects in pipelined ADCs
Validate settling time in SAR ADCs
Characterize residue amplifier gain variations
Debug clock quality (PM noise indicates jitter)
Common Patterns#
Pipelined ADC#
High AM → Residue amplifier gain error
High PM → Inadequate settling time
SAR ADC#
High AM → DAC mismatch, reference variation
High PM → Comparator metastability
Flash ADC#
Low AM, low PM → Good performance
High base noise → Comparator noise
See Also#
analyze_error_by_value— Error vs. ADC codeanalyze_error_pdf— Error distributionanalyze_error_autocorr— Temporal correlation
References#
IEEE Std 1241-2010, “IEEE Standard for Terminology and Test Methods for ADCs”
M. Soudan et al., “A Novel AM-PM-Jitter Decomposition Method for Characterizing ADC Nonidealities,” IEEE Trans. IM, 2008