analyze_error_spectrum#

Overview#

analyze_error_spectrum computes the FFT spectrum of the ADC error signal (data - fitted sine) to reveal frequency components in the error. This is distinct from analyzing the signal spectrum itself—here we analyze only the residual error after removing the ideal sine wave.

Syntax#

from adctoolbox import analyze_error_spectrum

# Basic usage
result = analyze_error_spectrum(signal, fs=100e6, create_plot=True)

# With known frequency
result = analyze_error_spectrum(signal, fs=800e6, frequency=0.123,
                                create_plot=True)

# Custom title
result = analyze_error_spectrum(signal, fs=100e6, create_plot=True,
                                title="Error Spectrum: 25°C")

# Engineering dBFS view relative to ADC full scale
result = analyze_error_spectrum(signal, fs=100e6,
                                max_scale_range=(0, 1),
                                create_plot=True)

Parameters#

  • signal (array_like) — Input ADC signal (sine wave excitation)

  • fs (float, default=1) — Sampling frequency in Hz

  • frequency (float, optional) — Normalized frequency (0-0.5)

    • If None: auto-detected via FFT

  • create_plot (bool, default=True) — Display error spectrum plot

  • ax (matplotlib axis, optional) — Axis to plot on

  • title (str, optional) — Title for the plot

  • max_scale_range (float or tuple/list, optional) — Full-scale reference for the residual spectrum

    • If None: normalize the residual by its own peak-to-peak range (fingerprint view)

    • If tuple/list: use the ADC full-scale range, such as (0, 1), for dBFS engineering interpretation

Returns#

Dictionary containing:

Metrics (of error signal):

  • enob — Effective Number of Bits

  • sndr_db — Signal-to-Noise and Distortion Ratio (dB)

  • sfdr_db — Spurious-Free Dynamic Range (dB)

  • snr_db — Signal-to-Noise Ratio (dB)

  • thd_db — Total Harmonic Distortion (dB)

  • sig_pwr_dbfs — Signal power (dBFS)

  • noise_floor_dbfs — Noise floor (dBFS)

  • nsd_dbfs_hz — Noise spectral density (dBFS/Hz)

Error Data:

  • error_signal — Error signal (data - fitted sine)

  • error_spectrum_scale"residual" for self-normalized residual view, "adc_full_scale" when max_scale_range is provided

  • error_spectrum_max_scale_range — Full-scale reference used for the residual spectrum

Algorithm#

# 1. Fit ideal sine wave
if frequency is None:
    result = fit_sine_4param(signal)
else:
    result = fit_sine_4param(signal, frequency_estimate=frequency)

fitted_sine = result['fitted_signal']

# 2. Compute error
error_signal = signal - fitted_sine

# 3. Analyze spectrum of error (not signal!)
spectrum_result = analyze_spectrum(error_signal, fs=fs,
                                   max_scale_range=max_scale_range)

Scale Reference#

By default, analyze_error_spectrum preserves the historical behavior:

analyze_error_spectrum(signal, fs=fs, max_scale_range=None)

This normalizes the residual by the residual’s own peak-to-peak range. It is useful for shape or fingerprint diagnosis because small errors are visually expanded.

For engineering dBFS, noise-floor, or NSD interpretation, pass the ADC full-scale range:

analyze_error_spectrum(signal, fs=fs, max_scale_range=(0, 1))

In that mode, residual spurs and noise are reported relative to ADC full scale instead of the residual’s own amplitude. This makes different captures and non-ideality cases comparable in physical severity.

Key Difference from analyze_spectrum#

Function

What it Analyzes

Use Case

analyze_spectrum

Original signal spectrum

Overall ADC performance (ENOB, SNR, harmonics)

analyze_error_spectrum

Error signal spectrum

Error characteristics, frequency-dependent errors

Examples#

Example 1: Error Spectrum Analysis#

import numpy as np
from adctoolbox import analyze_error_spectrum

# Analyze error spectrum relative to ADC full scale
result = analyze_error_spectrum(adc_signal, fs=800e6,
                                max_scale_range=(0, 1),
                                create_plot=True)

print(f"Error SNDR: {result['sndr_db']:.2f} dB")
print(f"Error SFDR: {result['sfdr_db']:.2f} dB")
print(f"Noise floor: {result['noise_floor_dbfs']:.2f} dBFS")

Example 2: Compare Signal vs. Error Spectra#

import matplotlib.pyplot as plt
from adctoolbox import analyze_spectrum, analyze_error_spectrum

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# Signal spectrum (shows fundamental + harmonics + noise)
plt.sca(ax1)
sig_result = analyze_spectrum(signal, fs=fs, create_plot=True)
ax1.set_title('Signal Spectrum')

# Error spectrum (shows harmonics + noise, NO fundamental)
plt.sca(ax2)
err_result = analyze_error_spectrum(signal, fs=fs,
                                    max_scale_range=(0, 1),
                                    create_plot=True)
ax2.set_title('Error Spectrum')

plt.tight_layout()
plt.show()

Example 3: Identify Frequency-Dependent Errors#

# Look for spurs in error spectrum
result = analyze_error_spectrum(signal, fs=800e6, create_plot=True)

# Error spectrum should be relatively flat (white noise)
# Peaks indicate frequency-dependent errors:
# - Power supply coupling
# - Clock feedthrough
# - Sampling artifacts

Example 4: Batch Analysis#

# Analyze multiple conditions
conditions = ['Room Temp', 'High Temp', 'Low Voltage']
signals = [sig_25c, sig_85c, sig_low_vdd]

for cond, sig in zip(conditions, signals):
    result = analyze_error_spectrum(sig, fs=fs, create_plot=False,
                                     title=cond)
    print(f"{cond:15s}: Error SNDR = {result['sndr_db']:.2f} dB")

Interpretation#

Error Spectrum Shape#

Spectrum Shape

Interpretation

Flat (white)

Random noise (thermal, quantization)

1/f shape

Flicker noise, drift

Peaks at harmonics

Nonlinearity (HD2, HD3, etc.)

Peaks at non-harmonics

Spurs (power supply, clock coupling)

High at low freq

Offset drift, 1/f noise

Common Error Signatures#

Peak Location

Likely Cause

DC (0 Hz)

Offset drift (should be minimal)

f_clock

Clock feedthrough

f_supply

Power supply ripple

2×f_in, 3×f_in

Harmonic distortion

f_in ± f_clock

Sampling artifacts

SFDR of Error#

  • Error SFDR > 80 dB: Excellent, noise-limited

  • 60 < Error SFDR < 80 dB: Good, some distortion

  • Error SFDR < 60 dB: Significant spurious content

Use Cases#

  • Distinguish noise from distortion in error

  • Identify interference sources (spurs in error spectrum)

  • Validate fitting quality (DC component should be near zero)

  • Debug frequency-dependent errors

  • Measure noise floor excluding signal energy

Comparison with Other Error Analysis#

Function

Domain

Shows

analyze_error_spectrum

Frequency

Error frequency components

analyze_error_pdf

Statistical

Error distribution

analyze_error_autocorr

Time

Temporal correlation

analyze_error_envelope_spectrum

Frequency

AM modulation in error

analyze_error_by_phase

Phase

AM/PM decomposition

See Also#

References#

  1. IEEE Std 1241-2010, “IEEE Standard for Terminology and Test Methods for ADCs”

  2. B. Razavi, “Principles of Data Conversion System Design,” IEEE Press, 1995