From 2b5c6592df38072ffe5ff82cc1aac8093224aa03 Mon Sep 17 00:00:00 2001 From: Formatted Date: Fri, 24 Apr 2026 02:00:00 +0000 Subject: [PATCH] fix: three utility bugs in compare, LUT, and triangular waveform scripts - compare.py: capture max_abs_error return values and add pass/fail check (was silently discarded, missing outlier detection) - LUT.py: replace no-op pass with actual print of 8-bit Verilog values - Gen_Triangular.py: fix plt.plot(2*n, y) -> plt.plot(t, x) scalar vs array bug that produced broken time-domain plot --- 8_Utils/Python/Gen_Triangular.py | 2 +- 8_Utils/Python/LUT.py | 2 +- 9_Firmware/9_2_FPGA/tb/cosim/compare.py | 22 ++++++++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/8_Utils/Python/Gen_Triangular.py b/8_Utils/Python/Gen_Triangular.py index 64d5550..01be124 100644 --- a/8_Utils/Python/Gen_Triangular.py +++ b/8_Utils/Python/Gen_Triangular.py @@ -41,7 +41,7 @@ plt.xlim(0, (fmax+fmax/10)) plt.ylim(0, 20) plt.subplot(122) -plt.plot(2*n, y) +plt.plot(t, x) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.tight_layout() diff --git a/8_Utils/Python/LUT.py b/8_Utils/Python/LUT.py index 56a4cb1..a77f1a7 100644 --- a/8_Utils/Python/LUT.py +++ b/8_Utils/Python/LUT.py @@ -21,4 +21,4 @@ y_scaled = np.round(y * 127.5).astype(int) # Scale to 8-bit range (0-255) # Print values in Verilog-friendly format for _i in range(n): - pass + print(f"8'd{y_scaled[_i]},") diff --git a/9_Firmware/9_2_FPGA/tb/cosim/compare.py b/9_Firmware/9_2_FPGA/tb/cosim/compare.py index 429c1cf..e25c138 100644 --- a/9_Firmware/9_2_FPGA/tb/cosim/compare.py +++ b/9_Firmware/9_2_FPGA/tb/cosim/compare.py @@ -38,10 +38,11 @@ from fpga_model import SignalChain # Thresholds for pass/fail # These are generous because of LFSR dithering and CDC latency jitter -MAX_RMS_ERROR_LSB = 50.0 # Max RMS error in 18-bit LSBs -MIN_CORRELATION = 0.90 # Min Pearson correlation coefficient -MAX_LATENCY_DRIFT = 15 # Max latency offset between RTL and model (samples) -MAX_COUNT_DIFF = 20 # Max output count difference (LFSR dithering affects CIC timing) +MAX_RMS_ERROR_LSB = 50.0 # Max RMS error in 18-bit LSBs +MAX_ABS_ERROR_LSB = 200.0 # Max absolute error in 18-bit LSBs (4x RMS threshold) +MIN_CORRELATION = 0.90 # Min Pearson correlation coefficient +MAX_LATENCY_DRIFT = 15 # Max latency offset between RTL and model (samples) +MAX_COUNT_DIFF = 20 # Max output count difference (LFSR dithering affects CIC timing) # Scenarios SCENARIOS = { @@ -314,8 +315,8 @@ def compare_scenario(scenario_name): # ---- Error metrics (after alignment) ---- rms_i = compute_rms_error(aligned_rtl_i, aligned_py_i) rms_q = compute_rms_error(aligned_rtl_q, aligned_py_q) - compute_max_abs_error(aligned_rtl_i, aligned_py_i) - compute_max_abs_error(aligned_rtl_q, aligned_py_q) + max_abs_i = compute_max_abs_error(aligned_rtl_i, aligned_py_i) + max_abs_q = compute_max_abs_error(aligned_rtl_q, aligned_py_q) corr_i_aligned = compute_correlation(aligned_rtl_i, aligned_py_i) corr_q_aligned = compute_correlation(aligned_rtl_q, aligned_py_q) @@ -398,6 +399,15 @@ def compare_scenario(scenario_name): results.append(('Latency offset', lag_ok, f"|{best_lag}| <= {MAX_LATENCY_DRIFT}")) + # Check 7: Max absolute error + # Catches outlier spikes (pipeline corruption, saturation, CDC glitches) + # that RMS and correlation metrics alone can miss. + max_abs_err = max(max_abs_i, max_abs_q) + max_abs_threshold = cfg.get('max_abs', MAX_ABS_ERROR_LSB) + max_abs_ok = max_abs_err <= max_abs_threshold + results.append(('Max absolute error', max_abs_ok, + f"max(I={max_abs_i}, Q={max_abs_q}) <= {max_abs_threshold:.0f}")) + # ---- Report ---- all_pass = True for _name, ok, _detail in results: