Workflows
Three runnable patterns for the three target use cases. Each example here is exercised verbatim by tests/test_mcp_workflows.py.
Analyze hardware captures
Capture IQ samples from hardware (e.g. via pyadi-iio), save them as .npy, and run the one-shot analyzer.
import numpy as np
from genalyzer.mcp.fourier import analyze_spectrum
# iq_samples: complex128 ndarray captured at 250 MSPS
np.save("/tmp/adc_capture.npy", iq_samples)
result = analyze_spectrum(
npy_path="/tmp/adc_capture.npy",
sample_rate=250e6,
window="blackman_harris",
ssb=12, # absorb NCO imprecision and finite-resolution spread
plot=True, # set False in batch pipelines
)
print(result["sfdr"], result["snr"], result["enob"])
Parameter notes for real hardware data:
ssb=12groups the NCO spillover into the fundamental bin. Use small values (e.g.ssb=3) only for ideal synthetic data.Capture data is normalized internally; a small DC offset does not harm SFDR.
For real (non-IQ) ADCs, save a real-valued array —
analyze_spectrumpicksrfftautomatically.
Simulate-and-verify converter designs
Describe a converter, synthesize a clean tone, apply the quantizer, and verify the measured metrics against the spec.
from genalyzer.mcp.fourier import analyze_spectrum
from genalyzer.mcp.generators import generate_real_tone
from genalyzer.mcp.quantize import quantize
tone = generate_real_tone(
num_points=8192,
sample_rate=250e6,
tone_freq=30e6,
amplitude=0.9,
output_path="/tmp/tone.npy",
)
q = quantize(
npy_path=tone["output_path"],
bits=12,
fullscale=2.0, # fullscale spans [-1, 1] when amplitude = 0.9
output_path="/tmp/tone.q.npy",
)
result = analyze_spectrum(
npy_path=q["output_path"],
sample_rate=250e6,
window="blackman_harris",
ssb=3, # synthetic, coherent — tight grouping
)
# An ideal 12-bit quantizer: ENOB ~= 12, SNR ~= 74 dB
assert 11.5 < result["enob"] < 12.5
Add analyze_dnl, analyze_inl, or analyze_histogram calls on q["output_path"] to close the loop on code-density metrics too.
Automated characterization pipelines
Sweep a parameter (frequency, NFFT, bits, …) from an MCP-driven script, gathering deterministic JSON without plot overhead.
from genalyzer.mcp.fourier import analyze_spectrum
from genalyzer.mcp.generators import generate_test_tone
freqs = [10e6, 30e6, 60e6, 90e6]
sample_rate = 250e6
results = []
for f in freqs:
gen = generate_test_tone(
num_points=8192,
sample_rate=sample_rate,
tone_freq=f,
amplitude=0.9,
)
res = analyze_spectrum(
npy_path=gen["output_path"],
sample_rate=sample_rate,
window="blackman_harris",
ssb=3,
plot=False, # no matplotlib work in a sweep
)
results.append({"tone_freq": f, "sfdr": res["sfdr"], "snr": res["snr"]})
for r in results:
print(r)
From an interactive assistant, this same pattern is just “for each of these frequencies, generate a tone and run analyze_spectrum; return the SFDR and SNR”.