analyze_spectrum

Overview

analyze_spectrum performs FFT-based spectrum analysis for ADC characterization, computing key metrics including ENOB, SNR, SNDR, SFDR, THD, and harmonic content. This is the primary tool for frequency-domain ADC performance evaluation.

Syntax

from adctoolbox import analyze_spectrum

# Simplest usage
result = analyze_spectrum(signal, fs=100e6)

# With harmonic analysis
result = analyze_spectrum(signal, fs=100e6, harmonic=5)

# With custom windowing
result = analyze_spectrum(signal, fs=100e6, window='blackman', nfft=8192)

# With averaging
result = analyze_spectrum(signal, fs=100e6, num_avg=4, mode='coherent')

# With interactive plotting
result = analyze_spectrum(signal, fs=100e6, show_plot=True)

Parameters

  • signal (array_like) — Input ADC signal (1D array)

  • fs (float) — Sampling frequency in Hz

  • harmonic (int, default=9) — Number of harmonics to analyze (2-20)

  • window (str, default='blackman') — Window function: 'rect', 'hann', 'hamming', 'blackman', 'flattop'

  • nfft (int, optional) — FFT length. If None, uses len(signal)

  • num_avg (int, default=1) — Number of segments for averaging

  • mode (str, default='coherent') — Averaging mode: 'coherent' or 'power'

  • show_plot (bool, default=False) — Display interactive spectrum plot

  • ax (matplotlib axis, optional) — Axis for plotting

Returns

Dictionary containing:

Metrics:

  • enob — Effective Number of Bits

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

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

  • sfdr_db — Spurious-Free Dynamic Range (dB)

  • thd_db — Total Harmonic Distortion (dB)

  • sinad_db — Signal-to-Noise-and-Distortion (alternative name for SNDR)

  • nsd_dbfs_hz — Noise Spectral Density (dBFS/Hz)

Spectrum Data:

  • freq — Frequency bins (Hz)

  • magnitude_db — Spectrum magnitude (dBFS)

  • fundamental_bin — FFT bin of fundamental frequency

  • fundamental_freq — Fundamental frequency (Hz)

  • harmonic_bins — FFT bins of harmonics (list)

  • harmonic_powers — Power of each harmonic (dB, list)

Algorithm

1. Signal Preprocessing

# Apply window
windowed_signal = signal * window_function

# Zero-pad if nfft > len(signal)
if nfft > len(signal):
    windowed_signal = np.pad(windowed_signal, (0, nfft - len(signal)))

2. FFT Computation

spectrum = np.fft.fft(windowed_signal, n=nfft)
magnitude = np.abs(spectrum[:nfft//2])
magnitude_db = 20 * np.log10(magnitude / nfft * 2)  # Convert to dBFS

3. Fundamental Detection

# Find peak in first Nyquist zone (excluding DC)
fundamental_bin = np.argmax(magnitude[1:nfft//2]) + 1
fundamental_freq = fundamental_bin * fs / nfft

4. Harmonic Identification

harmonic_bins = [fundamental_bin * k for k in range(2, harmonic + 1)]
# Fold harmonics above Nyquist back into spectrum
harmonic_bins_folded = [fold_bin_to_nyquist(h, nfft) for h in harmonic_bins]

5. Metric Calculation

# Signal power (fundamental)
P_signal = magnitude[fundamental_bin]**2

# Harmonic power
P_harmonics = sum([magnitude[h]**2 for h in harmonic_bins_folded])

# Noise power (excluding signal, harmonics, DC)
P_noise = sum(magnitude**2) - P_signal - P_harmonics - magnitude[0]**2

# Metrics
SNR = 10 * log10(P_signal / P_noise)
THD = 10 * log10(P_harmonics / P_signal)
SNDR = 10 * log10(P_signal / (P_noise + P_harmonics))
ENOB = (SNDR - 1.76) / 6.02
SFDR = fundamental_mag_db - max_spur_mag_db

Examples

Example 1: Basic Spectrum Analysis

import numpy as np
from adctoolbox import analyze_spectrum

# Generate test signal
N = 2**13
fs = 100e6
fin = 123/N * fs  # Coherent frequency
t = np.arange(N) / fs
signal = 0.5 * np.sin(2*np.pi*fin*t) + np.random.randn(N) * 10e-6

# Analyze
result = analyze_spectrum(signal, fs=fs)

print(f"ENOB: {result['enob']:.2f} bits")
print(f"SNDR: {result['sndr_db']:.2f} dB")
print(f"SFDR: {result['sfdr_db']:.2f} dB")
print(f"THD: {result['thd_db']:.2f} dB")

Example 2: With Interactive Plotting

result = analyze_spectrum(signal, fs=800e6, show_plot=True)
# Opens interactive plot showing spectrum, harmonics, and metrics

Example 3: Windowing Comparison

windows = ['rect', 'hann', 'blackman', 'flattop']

for win in windows:
    result = analyze_spectrum(signal, fs=fs, window=win)
    print(f"{win:10s}: SFDR={result['sfdr_db']:6.2f} dB, "
          f"SNDR={result['sndr_db']:6.2f} dB")

Example 4: Coherent Averaging

# Average 4 segments coherently
result = analyze_spectrum(signal, fs=fs, num_avg=4, mode='coherent')
# Reduces noise floor by ~6 dB (factor of 4)

Window Function Selection

Window

ENBW*

Peak Side Lobe

Use Case

rect

1.0

-13 dB

Coherent signals only

hann

1.5

-32 dB

General purpose

hamming

1.36

-43 dB

Better side lobe rejection

blackman

1.73

-58 dB

High dynamic range (default)

flattop

3.77

-93 dB

Accurate amplitude measurement

*ENBW = Equivalent Noise Bandwidth (bins)

Interpretation

ENOB (Effective Number of Bits)

  • ENOB ≈ N-bit ADC: Ideal performance

  • ENOB < N - 2: Poor performance, investigate noise/distortion

  • ENOB > N: Oversampling or dithering improving effective resolution

SFDR (Spurious-Free Dynamic Range)

  • SFDR > 80 dB: Excellent linearity

  • 60 dB < SFDR < 80 dB: Good for most applications

  • SFDR < 60 dB: Significant spurs, check for:

    • Power supply coupling

    • Clock feedthrough

    • Intermodulation products

THD (Total Harmonic Distortion)

  • THD < -80 dB: Very linear

  • -60 dB < THD < -80 dB: Acceptable for most uses

  • THD > -60 dB: Nonlinearity issues

Common Issues

Non-Coherent Sampling

# BAD: Arbitrary frequency causes spectral leakage
signal = np.sin(2*np.pi*10.1234e6*t)  # Non-coherent

# GOOD: Use coherent frequency
from adctoolbox import find_coherent_frequency
fin_coh, bin_num = find_coherent_frequency(fs, 10e6, N)
signal = np.sin(2*np.pi*fin_coh*t)

Insufficient FFT Length

# BAD: Low resolution
result = analyze_spectrum(signal[:512], fs=fs)  # Only 512 points

# GOOD: More frequency resolution
result = analyze_spectrum(signal, fs=fs, nfft=8192)

See Also

References

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

  2. F. J. Harris, "On the Use of Windows for Harmonic Analysis with the DFT," Proc. IEEE, 1978

  3. Application Note AN-9675, "Coherent Sampling Calculator," Analog Devices