mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-06-10 23:41:18 +00:00
fix(radar): RX chain corrections, GUI bin alignment, MCU boot ordering
FPGA — RX chain
matched_filter_multi_segment.v: drop the gratuitous /4 scaling on
DDC sign-extended input (was ddc_i[17:2] + ddc_i[1]); use
ddc_i[15:0] directly. fft_engine has INTERNAL_W=32 with
saturating 16-bit output, so full 16-bit input is safe. Restores
~12 dB of MF input dynamic range.
radar_receiver_final.v: remove latency_buffer (count-N-pulses-then-
prime FIFO that left frame 1 with all-zero ref). Replaced with
a single-FF alignment register on ref_i/ref_q that matches the
1-FF stage multi_segment ST_PROCESSING uses on adc_data.
Verified by tb/tb_rxb_fullchain_latency.v — autocorrelation peak
at bin 0 with peak/mean ~88x.
doppler_processor.v / mti_canceller.v / cfar_ca.v /
range_bin_decimator.v / radar_receiver_final.v / radar_system_top.v
/ usb_data_interface_ft2232h.v: switch port and parameter widths
from RP_NUM_RANGE_BINS / RP_RANGE_BIN_BITS (always 512 / 9-bit)
to RP_MAX_OUTPUT_BINS / RP_RANGE_BIN_WIDTH_MAX (auto-scales:
50T 512 / 9-bit, 200T 4096 / 12-bit). Unblocks 200T 20 km mode
at the RX module boundary; USB wire-protocol extension still
pending.
radar_receiver_final.v: doppler_frame_done_prev reset value 0 -> 1
to prevent false done pulse on cycle 1 when level signal is
HIGH at reset.
matched_filter_processing_chain.v: delete the broken `ifdef
SIMULATION inline behavioural FFT (482 lines removed). It
produced wrong-bin peaks and 100-1000x weak magnitudes. Chain
now uses production fft_engine.v + frequency_matched_filter.v
in both iverilog and Vivado. Iverilog tests are ~38x slower per
chain pass but produce correct results. Misleading "OK with
Xilinx IP" comments at three test sites updated since the FFT
is in-house, not an IP placeholder.
FPGA — testbenches
tb/tb_rxb_latency_measure.v (new): measures chain internal pipeline
depth (~2057 cycles, chirp-agnostic).
tb/tb_rxb_fullchain_latency.v (new): full-chain autocorrelation
verification — drives ddc with the same chirp samples the loader
serves as ref, finds peak position and peak/mean.
tb/tb_matched_filter_processing_chain.v: wait timeouts bumped
50000 -> 500000 cycles to accommodate production FFT pipeline.
MCU
main.cpp checkSystemHealthStatus: latch system_emergency_state on
the error_count > 10 path so the SAFE-MODE blink loop in main()
actually engages (was bypassed because predicate was false).
main.cpp: move FPGA reset BEFORE the if(PowerAmplifier) block so
adar_tr_x is driven LOW (RX commanded externally) before PA Vdd
reaches 22 V. Old reset block at the original location removed.
main.cpp MX_GPIO_Init: add GPIO_PIN_12 (FPGA reset) to the
explicit WritePin(LOW) list so the safe initial state is no
longer implicit.
main.cpp checkSystemHealth: rate-limit ADAR1000
verifyDeviceCommunication (HAL_Delay 1ms x 4 devices = 4 ms
blocking SPI burst per main-loop iteration) from every-loop to
every 2 s. readTemperature stays per-loop so over-temp
detection latency is unchanged.
USBHandler.cpp processSettingsData: dispatch threshold bumped
74 -> 82 (matches parser minimum); buffer drained after parse
attempt (slide remaining bytes left) so a false END find no
longer sticks the buffer until 256-byte overflow.
GUI
radar_protocol.py: NUM_RANGE_BINS 64 -> 512 (matches FPGA
RP_NUM_RANGE_BINS); NUM_CELLS 2048 -> 16384.
radar_protocol.py _ingest_sample: honor FPGA frame_start bit for
resync after a USB drop; capture range_profile[rbin] once per
range bin at dbin == 0 (FPGA emits the same range_i/range_q for
all 32 Doppler cells of a given range bin; previous accumulator
inflated the profile 32x).
v7/models.py RadarSettings: range_resolution 24 -> 6 m (matches
c/(2*100MHz)*4); max_distance and coverage_radius 1536 -> 3072 m;
map_size 2000 -> 4000.
v7/models.py WaveformConfig: n_range_bins 64 -> 512, fft_size
1024 -> 2048, decimation_factor 16 -> 4.
GUI_V65_Tk.py: _RANGE_PER_BIN math and stale "~24 m / ~1536 m"
comments updated.
test_v7.py: assertion values updated to match new defaults.
Tests
test_ddc_cosim_fuzz.py: remove unused os/tempfile imports, wrap
three long lines for ruff E501 compliance.
This commit is contained in:
@@ -44,20 +44,16 @@
|
||||
`include "radar_params.vh"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// !!! 200T 20 km MODE BROKEN — FIX BEFORE 200T BRING-UP !!!
|
||||
// The prev-chirp BRAM buffer is sized to NUM_RANGE_BINS (512) and the
|
||||
// range_bin_in port is 9 bits (`RP_RANGE_BIN_BITS). In 20 km mode the
|
||||
// upstream range_bin_decimator emits `RP_OUTPUT_RANGE_BINS_20KM = 4096
|
||||
// bins per chirp (8 segments × 512 decimated bins), which aliases into
|
||||
// the 9-bit address space and collapses bins 512..4095 onto bins 0..511.
|
||||
// On XC7A50T this is latent (SUPPORT_LONG_RANGE undefined → 3 km only),
|
||||
// but on XC7A200T with SUPPORT_LONG_RANGE the 20 km data path will
|
||||
// silently corrupt every range cell above 3 km.
|
||||
// Fix before 200T bring-up: scale NUM_RANGE_BINS/range_bin width with
|
||||
// `RP_MAX_OUTPUT_BINS, or gate MTI off entirely in 20 km mode.
|
||||
// [RX-D FIX] NUM_RANGE_BINS and range_bin port widths now scale with
|
||||
// `RP_MAX_OUTPUT_BINS and `RP_RANGE_BIN_WIDTH_MAX (conditional on
|
||||
// SUPPORT_LONG_RANGE):
|
||||
// 50T (no SUPPORT_LONG_RANGE): 512 bins / 9-bit — 3 km only
|
||||
// 200T (SUPPORT_LONG_RANGE): 4096 bins / 12-bit — supports 20 km mode
|
||||
// The prev-chirp BRAM buffer auto-resizes accordingly; in 20 km mode all
|
||||
// 4096 range cells are stored without aliasing.
|
||||
// ----------------------------------------------------------------------------
|
||||
module mti_canceller #(
|
||||
parameter NUM_RANGE_BINS = `RP_NUM_RANGE_BINS, // 512
|
||||
parameter NUM_RANGE_BINS = `RP_MAX_OUTPUT_BINS, // 512 (50T) / 4096 (200T)
|
||||
parameter DATA_WIDTH = `RP_DATA_WIDTH // 16
|
||||
) (
|
||||
input wire clk,
|
||||
@@ -67,13 +63,13 @@ module mti_canceller #(
|
||||
input wire signed [DATA_WIDTH-1:0] range_i_in,
|
||||
input wire signed [DATA_WIDTH-1:0] range_q_in,
|
||||
input wire range_valid_in,
|
||||
input wire [`RP_RANGE_BIN_BITS-1:0] range_bin_in, // 9-bit
|
||||
input wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin_in, // 9-bit (50T) / 12-bit (200T)
|
||||
|
||||
// ========== OUTPUT (to Doppler processor) ==========
|
||||
output reg signed [DATA_WIDTH-1:0] range_i_out,
|
||||
output reg signed [DATA_WIDTH-1:0] range_q_out,
|
||||
output reg range_valid_out,
|
||||
output reg [`RP_RANGE_BIN_BITS-1:0] range_bin_out, // 9-bit
|
||||
output reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin_out, // 9-bit (50T) / 12-bit (200T)
|
||||
|
||||
// ========== CONFIGURATION ==========
|
||||
input wire mti_enable, // 1=MTI active, 0=pass-through
|
||||
@@ -111,7 +107,7 @@ module mti_canceller #(
|
||||
|
||||
reg signed [DATA_WIDTH-1:0] range_i_d1, range_q_d1;
|
||||
reg range_valid_d1;
|
||||
reg [`RP_RANGE_BIN_BITS-1:0] range_bin_d1;
|
||||
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin_d1;
|
||||
reg mti_enable_d1;
|
||||
reg use_long_chirp_d1;
|
||||
|
||||
@@ -120,7 +116,7 @@ always @(posedge clk or negedge reset_n) begin
|
||||
range_i_d1 <= {DATA_WIDTH{1'b0}};
|
||||
range_q_d1 <= {DATA_WIDTH{1'b0}};
|
||||
range_valid_d1 <= 1'b0;
|
||||
range_bin_d1 <= {`RP_RANGE_BIN_BITS{1'b0}};
|
||||
range_bin_d1 <= {`RP_RANGE_BIN_WIDTH_MAX{1'b0}};
|
||||
mti_enable_d1 <= 1'b0;
|
||||
use_long_chirp_d1 <= 1'b0;
|
||||
end else begin
|
||||
@@ -211,7 +207,7 @@ always @(posedge clk or negedge reset_n) begin
|
||||
range_i_out <= {DATA_WIDTH{1'b0}};
|
||||
range_q_out <= {DATA_WIDTH{1'b0}};
|
||||
range_valid_out <= 1'b0;
|
||||
range_bin_out <= {`RP_RANGE_BIN_BITS{1'b0}};
|
||||
range_bin_out <= {`RP_RANGE_BIN_WIDTH_MAX{1'b0}};
|
||||
has_previous <= 1'b0;
|
||||
mti_first_chirp <= 1'b1;
|
||||
prev_chirp_was_long <= 1'b0;
|
||||
|
||||
Reference in New Issue
Block a user