fix: resolve all ruff lint errors across V6+ GUIs, v7 module, and FPGA cosim scripts

Fixes 25 remaining manual lint errors after auto-fix pass (94 auto-fixed earlier):
- GUI_V6.py: noqa on availability imports, bare except, unused vars, F811 redefs
- GUI_V6_Demo.py: unused app variable
- v7/models.py: noqa F401 on 8 try/except availability-check imports
- FPGA cosim: unused header/status/span vars, ambiguous 'l' renamed to 'line',
  E701 while-on-one-line split, F841 padding vars annotated

Also adds v7/ module, GUI_PyQt_Map.py, and GUI_V7_PyQt.py to version control.
Expands CI lint job to cover all 21 maintained Python files (was 4).

All 58 Python tests pass. Zero ruff errors on all target files.
This commit is contained in:
Jason
2026-04-08 19:11:40 +03:00
parent 6a117dd324
commit 57de32b172
24 changed files with 5260 additions and 91 deletions
+5 -6
View File
@@ -29,7 +29,7 @@ import sys
# Add this directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from fpga_model import SignalChain, sign_extend
from fpga_model import SignalChain
# =============================================================================
@@ -107,7 +107,7 @@ def load_rtl_csv(filepath):
bb_i = []
bb_q = []
with open(filepath, 'r') as f:
header = f.readline() # Skip header
f.readline() # Skip header
for line in f:
line = line.strip()
if not line:
@@ -280,7 +280,7 @@ def compare_scenario(scenario_name):
py_i_stats = compute_signal_stats(py_i)
py_q_stats = compute_signal_stats(py_q)
print(f"\nSignal Statistics:")
print("\nSignal Statistics:")
print(f" RTL I: mean={rtl_i_stats['mean']:.1f}, rms={rtl_i_stats['rms']:.1f}, "
f"range=[{rtl_i_stats['min']}, {rtl_i_stats['max']}]")
print(f" RTL Q: mean={rtl_q_stats['mean']:.1f}, rms={rtl_q_stats['rms']:.1f}, "
@@ -352,12 +352,12 @@ def compare_scenario(scenario_name):
corr_i_aligned = compute_correlation(aligned_rtl_i, aligned_py_i)
corr_q_aligned = compute_correlation(aligned_rtl_q, aligned_py_q)
print(f"\nError Metrics (after alignment):")
print("\nError Metrics (after alignment):")
print(f" I-channel: RMS={rms_i:.2f} LSB, max={max_err_i} LSB, corr={corr_i_aligned:.6f}")
print(f" Q-channel: RMS={rms_q:.2f} LSB, max={max_err_q} LSB, corr={corr_q_aligned:.6f}")
# ---- First/last sample comparison ----
print(f"\nFirst 10 samples (after alignment):")
print("\nFirst 10 samples (after alignment):")
print(f" {'idx':>4s} {'RTL_I':>8s} {'Py_I':>8s} {'Err_I':>6s} {'RTL_Q':>8s} {'Py_Q':>8s} {'Err_Q':>6s}")
for k in range(min(10, aligned_len)):
ei = aligned_rtl_i[k] - aligned_py_i[k]
@@ -444,7 +444,6 @@ def compare_scenario(scenario_name):
print("PASS/FAIL Results:")
all_pass = True
for name, ok, detail in results:
status = "PASS" if ok else "FAIL"
mark = "[PASS]" if ok else "[FAIL]"
print(f" {mark} {name}: {detail}")
if not ok:
@@ -74,7 +74,7 @@ def load_doppler_csv(filepath):
"""
data = {}
with open(filepath, 'r') as f:
header = f.readline()
f.readline() # Skip header
for line in f:
line = line.strip()
if not line:
@@ -163,11 +163,11 @@ def compare_scenario(name, config, base_dir):
if not os.path.exists(golden_path):
print(f" ERROR: Golden CSV not found: {golden_path}")
print(f" Run: python3 gen_doppler_golden.py")
print(" Run: python3 gen_doppler_golden.py")
return False, {}
if not os.path.exists(rtl_path):
print(f" ERROR: RTL CSV not found: {rtl_path}")
print(f" Run the Verilog testbench first")
print(" Run the Verilog testbench first")
return False, {}
py_data = load_doppler_csv(golden_path)
@@ -201,7 +201,7 @@ def compare_scenario(name, config, base_dir):
else:
energy_ratio = 1.0 if rtl_energy == 0 else float('inf')
print(f"\n Global energy:")
print("\n Global energy:")
print(f" Python: {py_energy}")
print(f" RTL: {rtl_energy}")
print(f" Ratio: {energy_ratio:.4f}")
@@ -255,7 +255,7 @@ def compare_scenario(name, config, base_dir):
avg_corr_i = sum(i_correlations) / len(i_correlations)
avg_corr_q = sum(q_correlations) / len(q_correlations)
print(f"\n Per-range-bin metrics:")
print("\n Per-range-bin metrics:")
print(f" Peak Doppler bin agreement (+/-1 within sub-frame): {peak_agreements}/{RANGE_BINS} "
f"({peak_agreement_frac:.0%})")
print(f" Avg magnitude correlation: {avg_mag_corr:.4f}")
@@ -263,7 +263,7 @@ def compare_scenario(name, config, base_dir):
print(f" Avg Q-channel correlation: {avg_corr_q:.4f}")
# Show top 5 range bins by Python energy
print(f"\n Top 5 range bins by Python energy:")
print("\n Top 5 range bins by Python energy:")
top_rbins = sorted(peak_details, key=lambda x: -x['py_energy'])[:5]
for d in top_rbins:
print(f" rbin={d['rbin']:2d}: py_peak={d['py_peak']:2d}, "
@@ -291,7 +291,7 @@ def compare_scenario(name, config, base_dir):
checks.append((f'High-energy rbin avg mag_corr >= {MAG_CORR_MIN:.2f} '
f'(actual={he_mag_corr:.3f})', he_ok))
print(f"\n Pass/Fail Checks:")
print("\n Pass/Fail Checks:")
all_pass = True
for check_name, passed in checks:
status = "PASS" if passed else "FAIL"
+7 -7
View File
@@ -80,7 +80,7 @@ def load_csv(filepath):
vals_i = []
vals_q = []
with open(filepath, 'r') as f:
header = f.readline()
f.readline() # Skip header
for line in f:
line = line.strip()
if not line:
@@ -172,11 +172,11 @@ def compare_scenario(scenario_name, config, base_dir):
if not os.path.exists(golden_path):
print(f" ERROR: Golden CSV not found: {golden_path}")
print(f" Run: python3 gen_mf_cosim_golden.py")
print(" Run: python3 gen_mf_cosim_golden.py")
return False, {}
if not os.path.exists(rtl_path):
print(f" ERROR: RTL CSV not found: {rtl_path}")
print(f" Run the RTL testbench first")
print(" Run the RTL testbench first")
return False, {}
py_i, py_q = load_csv(golden_path)
@@ -205,7 +205,7 @@ def compare_scenario(scenario_name, config, base_dir):
energy_ratio = float('inf') if py_energy == 0 else 0.0
rms_ratio = float('inf') if py_rms == 0 else 0.0
print(f"\n Energy:")
print("\n Energy:")
print(f" Python total energy: {py_energy}")
print(f" RTL total energy: {rtl_energy}")
print(f" Energy ratio (RTL/Py): {energy_ratio:.4f}")
@@ -217,7 +217,7 @@ def compare_scenario(scenario_name, config, base_dir):
py_peak_bin, py_peak_mag = find_peak(py_i, py_q)
rtl_peak_bin, rtl_peak_mag = find_peak(rtl_i, rtl_q)
print(f"\n Peak location:")
print("\n Peak location:")
print(f" Python: bin={py_peak_bin}, mag={py_peak_mag}")
print(f" RTL: bin={rtl_peak_bin}, mag={rtl_peak_mag}")
@@ -242,7 +242,7 @@ def compare_scenario(scenario_name, config, base_dir):
corr_i = pearson_correlation(py_i, rtl_i)
corr_q = pearson_correlation(py_q, rtl_q)
print(f"\n Channel correlation:")
print("\n Channel correlation:")
print(f" I-channel: {corr_i:.6f}")
print(f" Q-channel: {corr_q:.6f}")
@@ -278,7 +278,7 @@ def compare_scenario(scenario_name, config, base_dir):
energy_ok))
# Print checks
print(f"\n Pass/Fail Checks:")
print("\n Pass/Fail Checks:")
all_pass = True
for name, passed in checks:
status = "PASS" if passed else "FAIL"
+1 -3
View File
@@ -19,7 +19,6 @@ Author: Phase 0.5 co-simulation suite for PLFM_RADAR
"""
import os
import struct
# =============================================================================
# Fixed-point utility functions
@@ -196,7 +195,7 @@ class NCO:
if phase_valid:
# Stage 1 NBA: phase_accum_reg <= phase_accumulator (old value)
new_phase_accum_reg = (self.phase_accumulator - ftw) & 0xFFFFFFFF # old accum before add
_new_phase_accum_reg = (self.phase_accumulator - ftw) & 0xFFFFFFFF # noqa: F841 — old accum before add (derivation reference)
# Wait - let me re-derive. The Verilog is:
# phase_accumulator <= phase_accumulator + frequency_tuning_word;
# phase_accum_reg <= phase_accumulator; // OLD value (NBA)
@@ -812,7 +811,6 @@ class FFTEngine:
# COMPUTE: LOG2N stages of butterflies
for stage in range(log2n):
half = 1 << stage
span = half << 1
tw_stride = (n >> 1) >> stage
for bfly in range(n // 2):
@@ -134,7 +134,7 @@ def main():
print("AERIS-10 Chirp .mem File Generator")
print("=" * 60)
print()
print(f"Parameters:")
print("Parameters:")
print(f" CHIRP_BW = {CHIRP_BW/1e6:.1f} MHz")
print(f" FS_SYS = {FS_SYS/1e6:.1f} MHz")
print(f" T_LONG_CHIRP = {T_LONG_CHIRP*1e6:.1f} us")
@@ -212,7 +212,7 @@ def main():
mismatches += 1
if mismatches == 0:
print(f" [PASS] Seg0 matches radar_scene.py generate_reference_chirp_q15()")
print(" [PASS] Seg0 matches radar_scene.py generate_reference_chirp_q15()")
else:
print(f" [FAIL] Seg0 has {mismatches} mismatches vs generate_reference_chirp_q15()")
return 1
@@ -225,13 +225,13 @@ def main():
# Check seg3 zero padding
seg3_i_path = os.path.join(MEM_DIR, 'long_chirp_seg3_i.mem')
with open(seg3_i_path, 'r') as f:
seg3_lines = [l.strip() for l in f if l.strip()]
nonzero_seg3 = sum(1 for l in seg3_lines if l != '0000')
seg3_lines = [line.strip() for line in f if line.strip()]
nonzero_seg3 = sum(1 for line in seg3_lines if line != '0000')
print(f" Seg3 non-zero entries: {nonzero_seg3}/{len(seg3_lines)} "
f"(expected 0 since chirp ends at sample 2999)")
if nonzero_seg3 == 0:
print(f" [PASS] Seg3 is all zeros (chirp 3000 samples < seg3 start 3072)")
print(" [PASS] Seg3 is all zeros (chirp 3000 samples < seg3 start 3072)")
else:
print(f" [WARN] Seg3 has {nonzero_seg3} non-zero entries")
@@ -18,14 +18,13 @@ Usage:
Author: Phase 0.5 Doppler co-simulation suite for PLFM_RADAR
"""
import math
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from fpga_model import (
DopplerProcessor, sign_extend, HAMMING_WINDOW
DopplerProcessor
)
from radar_scene import Target, generate_doppler_frame
@@ -121,7 +120,7 @@ def generate_scenario(name, targets, description, base_dir):
"""Generate input hex + golden output for one scenario."""
print(f"\n{'='*60}")
print(f"Scenario: {name}{description}")
print(f"Model: CLEAN (dual 16-pt FFT)")
print("Model: CLEAN (dual 16-pt FFT)")
print(f"{'='*60}")
# Generate Doppler frame (32 chirps x 64 range bins)
@@ -172,7 +171,7 @@ def generate_scenario(name, targets, description, base_dir):
write_hex_32bit(golden_hex, list(zip(flat_i, flat_q)))
# ---- Find peak per range bin ----
print(f"\n Peak Doppler bins per range bin (top 5 by magnitude):")
print("\n Peak Doppler bins per range bin (top 5 by magnitude):")
peak_info = []
for rbin in range(RANGE_BINS):
mags = [abs(doppler_i[rbin][d]) + abs(doppler_q[rbin][d])
@@ -25,8 +25,8 @@ import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from fpga_model import (
FFTEngine, FreqMatchedFilter, MatchedFilterChain,
RangeBinDecimator, sign_extend, saturate
MatchedFilterChain,
sign_extend, saturate
)
@@ -208,7 +208,6 @@ def generate_long_chirp_test():
input_buffer_i = [0] * BUFFER_SIZE
input_buffer_q = [0] * BUFFER_SIZE
buffer_write_ptr = 0
current_segment = 0
input_idx = 0
chirp_samples_collected = 0
@@ -342,8 +341,9 @@ def generate_short_chirp_test():
input_q.append(saturate(val_q, 16))
# Zero-pad to 1024 (as RTL does in ST_ZERO_PAD)
padded_i = list(input_i) + [0] * (BUFFER_SIZE - SHORT_SAMPLES)
padded_q = list(input_q) + [0] * (BUFFER_SIZE - SHORT_SAMPLES)
# Note: padding computed here for documentation; actual buffer uses buf_i/buf_q below
_padded_i = list(input_i) + [0] * (BUFFER_SIZE - SHORT_SAMPLES) # noqa: F841
_padded_q = list(input_q) + [0] * (BUFFER_SIZE - SHORT_SAMPLES) # noqa: F841
# The buffer truncation: ddc_i[17:2] + ddc_i[1]
# For data already 16-bit sign-extended to 18: result is (val >> 2) + bit1
+2 -3
View File
@@ -21,7 +21,6 @@ Author: Phase 0.5 co-simulation suite for PLFM_RADAR
import math
import os
import struct
# =============================================================================
@@ -156,7 +155,7 @@ def generate_if_chirp(n_samples, chirp_bw=CHIRP_BW, f_if=F_IF, fs=FS_ADC):
t = n / fs
# Instantaneous frequency: f_if - chirp_bw/2 + chirp_rate * t
# Phase: integral of 2*pi*f(t)*dt
f_inst = f_if - chirp_bw / 2 + chirp_rate * t
_f_inst = f_if - chirp_bw / 2 + chirp_rate * t # noqa: F841 — documents instantaneous frequency formula
phase = 2 * math.pi * (f_if - chirp_bw / 2) * t + math.pi * chirp_rate * t * t
chirp_i.append(math.cos(phase))
chirp_q.append(math.sin(phase))
@@ -668,7 +667,7 @@ def generate_all_test_vectors(output_dir=None):
f.write(f" ADC: {FS_ADC/1e6:.0f} MSPS, {ADC_BITS}-bit\n")
f.write(f" Range resolution: {RANGE_RESOLUTION:.1f} m\n")
f.write(f" Wavelength: {WAVELENGTH*1000:.2f} mm\n")
f.write(f"\n")
f.write("\n")
f.write("Scenario 1: Single target\n")
for t in targets1:
@@ -20,7 +20,6 @@ Usage:
import numpy as np
import os
import sys
import argparse
# ===========================================================================
@@ -787,7 +786,7 @@ def run_mti_canceller(decim_i, decim_q, enable=True):
if not enable:
mti_i[:] = decim_i
mti_q[:] = decim_q
print(f" Pass-through mode (MTI disabled)")
print(" Pass-through mode (MTI disabled)")
return mti_i, mti_q
for c in range(n_chirps):
@@ -803,7 +802,7 @@ def run_mti_canceller(decim_i, decim_q, enable=True):
mti_i[c, r] = saturate(diff_i, 16)
mti_q[c, r] = saturate(diff_q, 16)
print(f" Chirp 0: muted (zeros)")
print(" Chirp 0: muted (zeros)")
print(f" Chirps 1-{n_chirps-1}: I range [{mti_i[1:].min()}, {mti_i[1:].max()}], "
f"Q range [{mti_q[1:].min()}, {mti_q[1:].max()}]")
return mti_i, mti_q
@@ -839,7 +838,7 @@ def run_dc_notch(doppler_i, doppler_q, width=2):
print(f"[DC NOTCH] width={width}, {n_range} range bins x {n_doppler} Doppler bins (dual sub-frame)")
if width == 0:
print(f" Pass-through (width=0)")
print(" Pass-through (width=0)")
return notched_i, notched_q
zeroed_count = 0
@@ -1029,7 +1028,7 @@ def run_float_reference(iq_i, iq_q):
Uses the exact same RTL Hamming window coefficients (Q15) to isolate
only the FFT fixed-point quantization error.
"""
print(f"\n[FLOAT REF] Running floating-point reference pipeline")
print("\n[FLOAT REF] Running floating-point reference pipeline")
n_chirps, n_samples = iq_i.shape[0], iq_i.shape[1] if iq_i.ndim == 2 else len(iq_i)
@@ -1384,10 +1383,10 @@ def main():
cfar_detections = np.argwhere(cfar_flags)
cfar_det_list_file = os.path.join(output_dir, "fullchain_cfar_detections.txt")
with open(cfar_det_list_file, 'w') as f:
f.write(f"# AERIS-10 Full-Chain CFAR Detection List\n")
f.write("# AERIS-10 Full-Chain CFAR Detection List\n")
f.write(f"# Chain: decim -> MTI -> Doppler -> DC notch(w={DC_NOTCH_WIDTH}) -> CA-CFAR\n")
f.write(f"# CFAR: guard={CFAR_GUARD}, train={CFAR_TRAIN}, alpha=0x{CFAR_ALPHA:02X}, mode={CFAR_MODE}\n")
f.write(f"# Format: range_bin doppler_bin magnitude threshold\n")
f.write("# Format: range_bin doppler_bin magnitude threshold\n")
for det in cfar_detections:
r, d = det
f.write(f"{r} {d} {cfar_mag[r, d]} {cfar_thr[r, d]}\n")
@@ -1406,9 +1405,9 @@ def main():
# Save full-chain detection reference
fc_det_file = os.path.join(output_dir, "fullchain_detections.txt")
with open(fc_det_file, 'w') as f:
f.write(f"# AERIS-10 Full-Chain Golden Reference Detections\n")
f.write("# AERIS-10 Full-Chain Golden Reference Detections\n")
f.write(f"# Threshold: {args.threshold}\n")
f.write(f"# Format: range_bin doppler_bin magnitude\n")
f.write("# Format: range_bin doppler_bin magnitude\n")
for d in fc_detections:
rbin, dbin = d
f.write(f"{rbin} {dbin} {fc_mag[rbin, dbin]}\n")
@@ -1433,9 +1432,9 @@ def main():
# Save detection list
det_file = os.path.join(output_dir, "detections.txt")
with open(det_file, 'w') as f:
f.write(f"# AERIS-10 Golden Reference Detections\n")
f.write("# AERIS-10 Golden Reference Detections\n")
f.write(f"# Threshold: {args.threshold}\n")
f.write(f"# Format: range_bin doppler_bin magnitude\n")
f.write("# Format: range_bin doppler_bin magnitude\n")
for d in detections:
rbin, dbin = d
f.write(f"{rbin} {dbin} {mag[rbin, dbin]}\n")
@@ -1484,12 +1483,12 @@ def main():
print(f" Range FFT: {FFT_SIZE}-point → {snr_range:.1f} dB vs float")
print(f" Doppler FFT (direct): {DOPPLER_FFT_SIZE}-point Hamming → {snr_doppler:.1f} dB vs float")
print(f" Detections (direct): {len(detections)} (threshold={args.threshold})")
print(f" Full-chain decimator: 1024→64 peak detection")
print(" Full-chain decimator: 1024→64 peak detection")
print(f" Full-chain detections: {len(fc_detections)} (threshold={args.threshold})")
print(f" MTI+CFAR chain: decim → MTI → Doppler → DC notch(w={DC_NOTCH_WIDTH}) → CA-CFAR")
print(f" CFAR detections: {len(cfar_detections)} (guard={CFAR_GUARD}, train={CFAR_TRAIN}, alpha=0x{CFAR_ALPHA:02X})")
print(f" Hex stimulus files: {output_dir}/")
print(f" Ready for RTL co-simulation with Icarus Verilog")
print(" Ready for RTL co-simulation with Icarus Verilog")
# -----------------------------------------------------------------------
# Optional plots
@@ -206,7 +206,7 @@ def test_long_chirp():
expected_max_from_model = 32767 * 0.9
uses_model_scaling = max_mag > expected_max_from_model * 0.8
if uses_model_scaling:
print(f" Scaling: CONSISTENT with radar_scene.py model (0.9 * Q15)")
print(" Scaling: CONSISTENT with radar_scene.py model (0.9 * Q15)")
else:
warn(f"Magnitude ({max_mag:.0f}) is much lower than expected from Python model "
f"({expected_max_from_model:.0f}). .mem files may have unknown provenance.")
@@ -246,7 +246,7 @@ def test_long_chirp():
f_max = max(freq_estimates)
f_range = f_max - f_min
print(f"\n Instantaneous frequency analysis (post-DDC baseband):")
print("\n Instantaneous frequency analysis (post-DDC baseband):")
print(f" Start freq: {f_start/1e6:.3f} MHz")
print(f" End freq: {f_end/1e6:.3f} MHz")
print(f" Min freq: {f_min/1e6:.3f} MHz")
@@ -269,7 +269,7 @@ def test_long_chirp():
# Compare segment boundaries for overlap-save consistency
# In proper overlap-save, the chirp data should be segmented at 896-sample boundaries
# with segments being 1024-sample FFT blocks
print(f"\n Segment boundary analysis:")
print("\n Segment boundary analysis:")
for seg in range(4):
seg_i = read_mem_hex(f'long_chirp_seg{seg}_i.mem')
seg_q = read_mem_hex(f'long_chirp_seg{seg}_q.mem')
@@ -290,9 +290,9 @@ def test_long_chirp():
print(f" Seg {seg}: avg_mag={seg_avg:.1f}, max_mag={seg_max:.1f}, "
f"near-zero={zero_count}/{len(seg_mags)}")
if zero_count > 500:
print(f" -> Seg 3 mostly zeros (chirp shorter than 4096 samples)")
print(" -> Seg 3 mostly zeros (chirp shorter than 4096 samples)")
else:
print(f" -> Seg 3 has significant data throughout")
print(" -> Seg 3 has significant data throughout")
else:
print(f" Seg {seg}: avg_mag={seg_avg:.1f}, max_mag={seg_max:.1f}")
@@ -330,8 +330,10 @@ def test_short_chirp():
freq_est = []
for n in range(1, len(phases)):
dp = phases[n] - phases[n-1]
while dp > math.pi: dp -= 2 * math.pi
while dp < -math.pi: dp += 2 * math.pi
while dp > math.pi:
dp -= 2 * math.pi
while dp < -math.pi:
dp += 2 * math.pi
freq_est.append(dp * FS_SYS / (2 * math.pi))
if freq_est:
@@ -382,9 +384,9 @@ def test_chirp_vs_model():
print(f" Exact I matches: {matches}/{len(model_i)}")
if matches > len(model_i) * 0.9:
print(f" -> .mem files MATCH Python model")
print(" -> .mem files MATCH Python model")
else:
warn(f".mem files do NOT match Python model. They likely have different provenance.")
warn(".mem files do NOT match Python model. They likely have different provenance.")
# Try to detect scaling
if mem_max > 0:
ratio = model_max / mem_max
@@ -399,14 +401,16 @@ def test_chirp_vs_model():
phase_diffs = []
for mp, fp in zip(model_phases, mem_phases):
d = mp - fp
while d > math.pi: d -= 2 * math.pi
while d < -math.pi: d += 2 * math.pi
while d > math.pi:
d -= 2 * math.pi
while d < -math.pi:
d += 2 * math.pi
phase_diffs.append(d)
avg_phase_diff = sum(phase_diffs) / len(phase_diffs)
max_phase_diff = max(abs(d) for d in phase_diffs)
print(f"\n Phase comparison (shape regardless of amplitude):")
print("\n Phase comparison (shape regardless of amplitude):")
print(f" Avg phase diff: {avg_phase_diff:.4f} rad ({math.degrees(avg_phase_diff):.2f} deg)")
print(f" Max phase diff: {max_phase_diff:.4f} rad ({math.degrees(max_phase_diff):.2f} deg)")
+2 -2
View File
@@ -91,7 +91,7 @@ def generate_case(case_num, sig_i, sig_q, ref_i, ref_q, description, outdir):
peak_q_q = out_q_q[peak_bin]
# Write hex files
prefix = os.path.join(outdir, f"mf_golden")
prefix = os.path.join(outdir, "mf_golden")
write_hex_file(f"{prefix}_sig_i_case{case_num}.hex", sig_i)
write_hex_file(f"{prefix}_sig_q_case{case_num}.hex", sig_q)
write_hex_file(f"{prefix}_ref_i_case{case_num}.hex", ref_i)
@@ -233,7 +233,7 @@ def main():
f.write(f" Peak Q (float): {s['peak_q_float']:.6f}\n")
f.write(f" Peak I (quantized): {s['peak_i_quant']}\n")
f.write(f" Peak Q (quantized): {s['peak_q_quant']}\n")
f.write(f" Files:\n")
f.write(" Files:\n")
for fname in s["files"]:
f.write(f" {fname}\n")
f.write("\n")