Expected Output: 02_spectrum

This document shows the expected console output and example figures from all examples in python/src/adctoolbox/examples/02_spectrum/.

Summary

All examples in 02_spectrum demonstrate spectrum analysis capabilities:

  1. exp_s01-s03: Basic spectrum analysis (simplest, interactive, save figure)

  2. exp_s04: Dynamic range sweep

  3. exp_s05: Harmonic spur annotation

  4. exp_s06: FFT length and OSR sweep

  5. exp_s07: Power vs coherent averaging

  6. exp_s08: Windowing functions comparison (Kaiser, Blackman-Harris, Hann, Hamming)

  7. exp_s10: Polar spectrum - thermal noise vs harmonic distortion

  8. exp_s11: Polar spectrum - static nonlinearity vs memory effect

  9. exp_s12: Polar spectrum - coherent averaging improvement

  10. exp_s21: Two-tone spectrum analysis with IMD products

  11. exp_s22: Two-tone IMD comparison (weak vs strong nonlinearity)

  12. exp_s23: Two-tone coherent averaging

Total Examples: 14

exp_s01_analyze_spectrum_simplest.py

Description: Simplest example - analyze spectrum with minimal code.

[Nonideal] Noise RMS=[10.00 uVrms], Theoretical SNR=[90.97 dB], Theoretical NSD=[-167.96 dBFS/Hz]

[analyze_spectrum] ENoB=[14.80 b], SNDR=[90.89 dB], SFDR=[115.33 dB], SNR=[90.90 dB], NSD=[-167.89 dBFS/Hz]

exp_s02_analyze_spectrum_interactive.py

Description: Interactive example - displays plot window.

[Sinewave] Fs=[100.00 MHz], Fin=[12.00 MHz], Bin/N=[983/8192], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[50.00 uVrms], Theoretical SNR=[76.99 dB], Theoretical NSD=[-153.98 dBFS/Hz]

[analyze_spectrum] ENoB=[12.51 b], SNDR=[77.08 dB], SFDR=[100.37 dB], SNR=[77.10 dB], NSD=[-154.09 dBFS/Hz]

[Figure displayed - close the window to exit]

exp_s03_analyze_spectrum_savefig.py

Description: Save figure to file instead of displaying.

[Sinewave] Fs=[100.00 MHz], Fin=[12.00 MHz], Bin/N=[983/8192], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[200.00 uVrms], Theoretical SNR=[64.95 dB], Theoretical NSD=[-141.94 dBFS/Hz]

[analyze_spectrum] ENoB=[10.50 b], SNDR=[ 64.97 dB], SFDR=[ 88.02 dB], SNR=[ 64.98 dB], NSD=[-141.97 dBFS/Hz]
[analyze_spectrum] Noise Floor=[ -64.98 dBFS], Signal Power=[  0.00 dBFS] (expected: 0.00 dB for 1.000V in 1.0V FSR),

[Sinewave] Fs=[100.00 MHz], Fin=[12.00 MHz], Bin/N=[983/8192], A=[0.250 Vpeak]
[Nonideal] Noise RMS=[200.00 uVrms], Theoretical SNR=[58.93 dB], Theoretical NSD=[-135.92 dBFS/Hz]

[analyze_spectrum] ENoB=[ 9.50 b], SNDR=[ 58.95 dB], SFDR=[ 82.51 dB], SNR=[ 58.96 dB], NSD=[-141.97 dBFS/Hz]
[analyze_spectrum] Noise Floor=[ -64.98 dBFS], Signal Power=[ -6.02 dBFS] (expected: -6.02 dB for 0.500V in 1.0V FSR),


[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s03_analyze_spectrum_savefig.png]
Basic spectrum analysis

Basic FFT spectrum analysis with all key metrics

exp_s04_sweep_dynamic_range.py

Description: Sweep signal amplitude to characterize dynamic range.

[Sinewave] Fs=[100.00 MHz], Fin=[11.999512 MHz] (coherent, Bin 983), N=[8192]
[Nonideal] Noise RMS=[100.00 uVrms] (fixed)
[Sweep] Amplitude: -80.0 to 0.0 dBFS (50 steps)

================================================================================
DYNAMIC RANGE SWEEP
================================================================================
[A= -80.0 dBFS] SNR=[ -8.84 dB] (Theory: -9.0 dB), Noise Floor=[ -70.97 dBFS]
[A= -78.4 dBFS] SNR=[ -7.24 dB] (Theory: -7.4 dB), Noise Floor=[ -70.83 dBFS]
[A= -76.7 dBFS] SNR=[ -5.47 dB] (Theory: -5.8 dB), Noise Floor=[ -70.94 dBFS]
... (50 total steps)
[A=  -3.3 dBFS] SNR=[ 67.67 dB] (Theory: 67.7 dB), Noise Floor=[ -70.94 dBFS]
[A=  -1.6 dBFS] SNR=[ 69.30 dB] (Theory: 69.3 dB), Noise Floor=[ -70.94 dBFS]
[A=   0.0 dBFS] SNR=[ 70.86 dB] (Theory: 71.0 dB), Noise Floor=[ -70.86 dBFS]

[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s04_sweep_dynamic_range.png]



================================================================================
SUMMARY: Dynamic Range Analysis
================================================================================
Dynamic Range: -71.1 dBFS (SNR=0dB) to 0.0 dBFS (max) = 71.1 dB
Dynamic range sweep

FFT metrics across input signal amplitudes (dynamic range sweep)

exp_s05_annotating_spur.py

Description: Annotate spur frequencies and demonstrate harmonic aliasing.

[Sinewave] Fs=[100.00 MHz], A=[0.500 Vpeak]
[Nonideal] HD2=[-100 dB], HD3=[-80 dB], Noise RMS=[50.00 uVrms], Theoretical SNR=[76.99 dB], Theoretical NSD=[-153.98 dBFS/Hz]

[Frequency 1] Fs/17.6 (No Collision): Fin=[5.68 MHz], Bin/N=[29789/524288], Harmonics spread
  [n_thd=11] ENoB=[12.20 b], SNDR=[ 75.20 dB], THD=[ -79.94 dB]

[Frequency 2] Fs/3: Fin=[33.33 MHz], Bin/N=[174763/524288], Collide at Nyquist!
[Warning from analyze_spectrum]: Harmonics [2, 4, 5, 7] alias to fundamental (excluded from THD)
  [n_thd=11] ENoB=[12.25 b], SNDR=[ 75.48 dB], THD=[ -80.79 dB]


[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s05_annotating_spur.png]
Spur annotation

Spectrum with annotated fundamental, harmonics, and spurs

exp_s06_sweeping_fft_and_osr.py

Description: Compare FFT length vs OSR for improving spectrum quality.

[Sinewave] Fs=[100.00 MHz], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[150.00 uVrms], Theoretical SNR=[67.45 dB], Theoretical NSD=[-144.44 dBFS/Hz]

================================================================================
SCENARIO 1: FFT LENGTH SWEEP (N = 2^7 to 2^16)
================================================================================
[N=     128 (2^ 7)] [Bin =  781.250 kHz] ENoB=[10.92 b], SNDR=[ 67.49 dB], SNR=[ 68.43 dB], NSD=[-145.42 dBFS/Hz]
[N=    1024 (2^10)] [Bin =   97.656 kHz] ENoB=[10.86 b], SNDR=[ 67.15 dB], SNR=[ 67.20 dB], NSD=[-144.19 dBFS/Hz]
[N=    8192 (2^13)] [Bin =   12.207 kHz] ENoB=[10.93 b], SNDR=[ 67.53 dB], SNR=[ 67.54 dB], NSD=[-144.54 dBFS/Hz]
[N=   65536 (2^16)] [Bin =    1.526 kHz] ENoB=[10.92 b], SNDR=[ 67.47 dB], SNR=[ 67.48 dB], NSD=[-144.47 dBFS/Hz]

================================================================================
SCENARIO 2: OVERSAMPLING RATIO SWEEP (OSR = 1, 2, 4, 10)
================================================================================
[Sinewave] Fin=[0.099182 MHz] (coherent, Bin 65), N=[65536]
[OSR=  1] ENoB=[10.91 b], SNDR=[ 67.45 dB], SNR=[ 67.45 dB], NSD=[-144.45 dBFS/Hz], Gain=[+0.0 dB] (Theory: +0.0 dB)
[OSR=  2] ENoB=[11.42 b], SNDR=[ 70.49 dB], SNR=[ 70.49 dB], NSD=[-144.47 dBFS/Hz], Gain=[+3.0 dB] (Theory: +3.0 dB)
[OSR=  4] ENoB=[11.91 b], SNDR=[ 73.48 dB], SNR=[ 73.48 dB], NSD=[-144.46 dBFS/Hz], Gain=[+6.0 dB] (Theory: +6.0 dB)
[OSR= 10] ENoB=[12.56 b], SNDR=[ 77.38 dB], SNR=[ 77.39 dB], NSD=[-144.39 dBFS/Hz], Gain=[+9.9 dB] (Theory: +10.0 dB)

[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s06_sweeping_fft_and_osr.png]

================================================================================
SUMMARY: FFT Length vs OSR
================================================================================
1. FFT Length (N):
   - Increases frequency resolution (bin width = Fs/N)
   - Lowers noise floor per bin (NSD improves)
   - Does NOT improve SNR (noise bandwidth unchanged)
   - Use case: Resolve closely spaced frequency components

2. Oversampling Ratio (OSR):
   - Directly improves SNR: Measured gain = +9.9 dB for OSR=10
   - Theoretical gain: +10.0 dB (10*log10(10))
   - Narrows analysis bandwidth to Fs/(2*OSR)
   - Use case: Delta-Sigma ADCs, narrowband signal analysis

3. Practical Guidelines:
   - For resolving harmonics: Increase FFT length
   - For improving SNR: Increase OSR (if signal is narrowband)
   - For best results: Combine both (large N + appropriate OSR)

exp_s07_spectrum_averaging.py

Description: Compare power averaging vs coherent averaging.

[Sinewave] Fs=[100.00 MHz], Fin=[4.992676 MHz] (coherent, Bin 409), N=[8192], A=[0.499 Vpeak]
[Nonideal] HD2=[-100 dB], HD3=[-90 dB], Noise RMS=[100.00 uVrms], Theoretical SNR=[70.95 dB], Theoretical NSD=[-147.94 dBFS/Hz]

[Generated] 100 runs with random phase

================================================================================
POWER SPECTRUM AVERAGING vs COHERENT SPECTRUM AVERAGING
================================================================================
[  1 Run(s)] Power Avg: ENoB=[11.49 b], SNR=[ 71.02 dB] | Coherent Avg: ENoB=[11.49 b], SNR=[ 71.02 dB]
[ 10 Run(s)] Power Avg: ENoB=[11.49 b], SNR=[ 71.01 dB] | Coherent Avg: ENoB=[12.84 b], SNR=[ 79.41 dB]
[100 Run(s)] Power Avg: ENoB=[11.49 b], SNR=[ 70.97 dB] | Coherent Avg: ENoB=[14.05 b], SNR=[ 89.21 dB]

[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s07_spectrum_averaging.png]



================================================================================
PERFORMANCE ANALYSIS: Statistical Gain
================================================================================
Method               |  Runs | SNR (dB) |  Gain (dB) | Theory (dB) | Status
-----------------------------------------------------------------------------------------------
Theoretical (1 run)  |     1 |    70.95 |        --- |         --- | Reference
Power Average        |     1 |    71.02 |       0.00 |         --- | Baseline
Power Average        |    10 |    71.01 |      -0.01 |         --- | Noise floor smoother
Coherent Average     |    10 |    79.41 |       8.40 |       10.00 | True processing gain
Power Average        |   100 |    70.97 |      -0.05 |         --- | Noise floor smoother
Coherent Average     |   100 |    89.21 |      18.19 |       20.00 | True processing gain
===============================================================================================

================================================================================
SUMMARY: Key Insights from Results
================================================================================
1. Power Averaging (Magnitude-only):
   - SNR remains constant (~71 dB) regardless of number of runs
   - Only smoothens the noise floor visually (reduces variance)
   - Does NOT provide true processing gain

2. Coherent Averaging (Phase-aligned):
   - SNR improves by ~18.2 dB for 100 runs
   - Theoretical gain: 20.0 dB (10*log10(100))
   - Achieves 90.9% of theoretical maximum
   - Provides true processing gain through phase coherence

3. Practical Implications:
   - To achieve 89 dB SNR with Power Averaging alone:
     Would need to increase FFT length by ~66x (impractical!)
   - With Coherent Averaging: Only need 100 runs (100x more efficient)
Spectrum averaging comparison

Power averaging vs coherent averaging for noise reduction

exp_s08_windowing_deep_dive.py

Description: Deep dive into window functions for different scenarios.

================================================================================
SCENARIO 1: NON-COHERENT SAMPLING (SPECTRAL LEAKAGE)
================================================================================
[Sinewave] Fs=[100.00 MHz], Fin=[10.00 MHz] (non-coherent), N=[8192], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[50.00 uVrms], Theoretical SNR=[76.99 dB], Theoretical NSD=[-153.98 dBFS/Hz]

Window                     ENoB (b)  SNDR (dB)  SFDR (dB)  SNR (dB)  NSD (dBFS/Hz)
------------------------------------------------------------------------------
Kaiser (beta=38)              12.50      77.03      80.99     77.07        -153.62
Blackman-Harris               12.47      76.84      82.56     76.87        -153.43
Chebyshev (100 dB)            12.38      76.31      82.71     76.33        -152.89
Flat-top                      12.09      74.54       3.76     74.55        -151.11
Blackman                      10.12      62.68       5.01     62.68        -139.23
Hann (raised cosine)           7.55      47.21       5.48     47.21        -123.77
Hamming                        5.74      36.33      12.43     36.33        -112.89
Rectangular (no window)        2.27      15.43      11.18     15.43         -92.11

[Save fig 1/3] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s08_windowing_1_leakage.png]



================================================================================
SCENARIO 2: COHERENT SAMPLING (NO LEAKAGE)
================================================================================
[Sinewave] Fs=[100.00 MHz], Fin=[9.997559 MHz] (coherent, Bin 819), N=[8192], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[50.00 uVrms], Theoretical SNR=[76.99 dB], Theoretical NSD=[-153.98 dBFS/Hz]

Window                     ENoB (b)  SNDR (dB)  SFDR (dB)  SNR (dB)  NSD (dBFS/Hz)
------------------------------------------------------------------------------
Kaiser (beta=38)              12.51      77.05      96.96     77.13        -154.12
Rectangular (no window)       12.51      77.04     103.51     77.06        -154.05
Flat-top                      12.50      77.01      97.48     77.06        -154.05
Blackman-Harris               12.50      76.99      97.70     77.04        -154.03
Blackman                      12.50      76.99      98.01     77.03        -154.03
Hamming                       12.50      76.99      99.67     77.03        -154.02
Hann (raised cosine)          12.50      76.98      99.56     77.02        -154.02
Chebyshev (100 dB)            12.39      76.36      88.80     76.40        -153.39

[Save fig 2/3] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s08_windowing_2_coherent.png]

================================================================================
SCENARIO 3: SHORT FFT (COARSE RESOLUTION)
================================================================================
[Sinewave] Fs=[100.00 MHz], Fin=[10.156250 MHz] (coherent, Bin 13), N=[128], A=[0.500 Vpeak]
[Nonideal] Noise RMS=[50.00 uVrms], Theoretical SNR=[76.99 dB], Theoretical NSD=[-153.98 dBFS/Hz]
[Bin width] = 781.2 kHz (coarse resolution)

[Warning from analyze_spectrum]: Harmonics [2] alias to fundamental (excluded from THD)
Window                     ENoB (b)  SNDR (dB)  SFDR (dB)  SNR (dB)  NSD (dBFS/Hz)
------------------------------------------------------------------------------
Rectangular (no window)       12.50      77.03      84.19     78.39        -155.38
Hamming                       12.34      76.02      80.85     77.91        -154.90
Hann (raised cosine)          12.32      75.94      80.70     77.84        -154.84
Blackman                      12.30      75.79      79.75     79.58        -156.57
Blackman-Harris               12.28      75.71      79.00     82.53        -159.52
Flat-top                      12.24      75.47      78.45     79.01        -156.00
Chebyshev (100 dB)            12.24      75.45      79.62     79.08        -156.07
Kaiser (beta=38)              12.21      75.28      77.55    150.00        -226.99

[Save fig 3/3] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s08_windowing_3_short_fft.png]

================================================================================
SUMMARY: Window Function Selection Rules
================================================================================
1. Non-coherent sampling: Use Kaiser/Blackman-Harris for best leakage suppression
2. Coherent sampling: Simpler windows (Rectangular/Hann/Hamming) work equally well
3. Short FFT: Avoid very wide windows (Kaiser). Use Rectangular/Hann/Hamming

Note: Kaiser window shows SNR=150dB in short FFT scenario - this is a known edge case with very short FFT and wide windows.

Window function comparison - spectral leakage

Comparing spectral leakage across different window functions

exp_s10_polar_noise_and_harmonics.py

Description: Polar plot comparison of thermal noise vs harmonic distortion.

[Sinewave] Fs=[800.00 MHz], Fin=[79.98 MHz], Bin/N=[819/8192], A=[0.490 Vpeak]

================================================================================
LEFT: THERMAL NOISE (2 mVrms)
================================================================================
[2 mVrms] SNR=44.8dB → Measured: ENoB=7.13b, SNR=44.72dB

================================================================================
RIGHT: HARMONIC DISTORTION (HD2=-80dB, HD3=-50dB, k3<0)
================================================================================
[HD2=-80dB, HD3=-50dB, k3<0] SNDR=49.07dB, THD=-49.87dB, HD2=-81.22dB, HD3=-49.87dB


[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s10_polar_noise_and_harmonics.png]
Polar spectrum - noise vs harmonics

Polar spectrum comparing thermal noise and harmonic distortion

exp_s11_polar_memory_effect.py

Description: Polar plot showing static vs dynamic nonlinearity.

[Sinewave] Fs=[800 MHz], N=[8192], A=[0.490 Vpeak]
[Nonideal] Noise RMS=[50.00 uVrms], Theoretical SNR=[76.81 dB], Theoretical NSD=[-162.83 dBFS/Hz]

================================================================================
ROW 1: STATIC NONLINEARITY
================================================================================
[Fin=79.98 MHz], Bin/N=[819/8192]

[HD3=-66dB, k3>0] SNDR=65.67dB, THD=-66.01dB, HD3=-66.01dB
[HD3=-66dB, k3<0] SNDR=65.64dB, THD=-65.98dB, HD3=-65.98dB
[HD2+HD3] SNDR=65.47dB, THD=-65.81dB, HD2=-79.78dB, HD3=-65.99dB

================================================================================
ROW 2: MEMORY EFFECT
================================================================================
[Fin=   40MHz, ME=0.02] sndr=60.09dB, snr=60.35dB, thd=-72.38dB
[Fin=   80MHz, ME=0.02] sndr=60.06dB, snr=60.33dB, thd=-72.29dB
[Fin=  160MHz, ME=0.02] sndr=59.96dB, snr=60.23dB, thd=-72.19dB


[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s11_polar_memory_effect.png]

exp_s12_polar_coherent_averaging.py

Description: Polar plot demonstrating coherent averaging improvement.

[Sinewave] Fs=[100.00 MHz], Fin=[4.980469 MHz] (coherent, Bin 51), N=[1024], A=[0.499 Vpeak]
[Nonideal] Noise RMS=[100.00 uVrms], Theoretical SNR=[70.95 dB], Theoretical NSD=[-147.94 dBFS/Hz]
[Nonlinearity] HD2=[-80 dB], HD3=[-73 dB]

[Generated] 100 runs with random phase

[  1 Run(s)] ENoB=[11.09 b], SNDR=[ 68.55 dB], SNR=[ 71.04 dB]
[ 10 Run(s)] ENoB=[11.61 b], SNDR=[ 71.66 dB], SNR=[ 80.98 dB]
[100 Run(s)] ENoB=[11.69 b], SNDR=[ 72.13 dB], SNR=[ 91.11 dB]

[Save fig] -> [D:\ADCToolbox\python\src\adctoolbox\examples\02_spectrum\output\exp_s12_polar_coherent_averaging.png]
Polar spectrum - coherent averaging improvement

Polar spectrum demonstrating coherent averaging improvement