chirp-v2 PR-F: doppler/CFAR widen to 3 sub-frames + 2-class detect

Bumps RP_CHIRPS_PER_FRAME 32 -> 48 (= 3 sub-frames × 16 chirps), widens
doppler_bin from 5 to 6 bits ({sub_frame[1:0], bin[3:0]}), and replaces the
1-bit detect_flag rail with a 2-bit detect_class (NONE / CANDIDATE /
CONFIRMED) sourced from a soft+confirm CFAR threshold pair.

doppler_processor:
  Generalised the 2-subframe FSM to NUM_SUBFRAMES = CHIRPS_PER_FRAME /
  CHIRPS_PER_SUBFRAME (=3 in production, =2 when TBs override). S_OUTPUT
  walks current_sub_frame 0..NUM_SUBFRAMES-1 then advances range_bin;
  the chirp_base * CHIRPS_PER_SUBFRAME formula replaces the if/else split.
  write_chirp_index, read_doppler_index, sub_frame, current_sub_frame all
  widened to 6/2 bits accordingly. doppler_bin packing {current_sub_frame[1:0],
  fft_sample_counter[3:0]} naturally yields 6 bits.

cfar_ca:
  Adds cfg_alpha_soft input + r_alpha_soft register (default
  RP_DEF_CFAR_ALPHA_SOFT = 0x18 ≈ 1.5 in Q4.4 → Pfa_soft ≈ 1e-5). ST_CFAR_MUL
  computes both noise_product (alpha) and noise_product_soft (alpha_soft) in
  parallel DSPs; ST_CFAR_CMP emits detect_class = CONFIRMED when cur > thr,
  CANDIDATE when cur > thr_soft (and not CONFIRMED), NONE otherwise.
  detect_flag is preserved as (class != NONE) for backward compat.
  Address packing now pads doppler axis to next power-of-2 (DOPPLER_PAD =
  1 << ceil(log2(NUM_DOPPLER))) so {range, doppler} packs contiguously
  for both NUM_DOPPLER=32 (legacy TB) and NUM_DOPPLER=48 (production).
  Mag-BRAM grows from ~16 to ~30 RAMB18 on 50T (acceptable on the budget).

usb_data_interface_ft2232h:
  doppler_bin_in widened to 6 bits. FRAME_CELLS pads to next power of two
  (32K) so {range, doppler[5:0]} concatenation lands cleanly. Address regs
  bumped: mag_wr/rd_addr 14→15, detect_byte_addr 11→12, detect_clear bit-
  counter 14→15. Detect-bit BRAM grows 2K→4K bytes. Wire-protocol byte
  counts auto-scale with FRAME_CELLS / DOPPLER_MAG_SECTION_BYTES; PR-G
  bumps the bulk-frame protocol version so the host parser knows.

Other:
  - radar_params.vh: RP_CHIRPS_PER_FRAME 32→48, RP_NUM_DOPPLER_BINS 32→48,
    RP_DOPPLER_MEM_ADDR_W 14→15 (50T) / 17→18 (200T), RP_CFAR_MAG_ADDR_W
    likewise. Other macros (RP_DOPPLER_BIN_WIDTH=6, RP_DETECT_CLASS_WIDTH=2,
    RP_DEF_CFAR_ALPHA_SOFT=0x18, RP_NUM_SUBFRAMES=3) were already in place
    from PR-A.
  - radar_system_top: rx_doppler_bin / dbg_doppler_bin widened. Adds
    host_cfar_alpha_soft register (default RP_DEF_CFAR_ALPHA_SOFT). USB
    opcode mapping deferred to PR-G.
  - radar_system_top_50t: dbg_doppler_bin_nc width.
  - radar_receiver_final: doppler_bin port width.

Test summary:
  - tb_chirp_controller_v2:  43/43 PASS
  - tb_chirp_contract:       10/10 PASS
  - tb_cfar_ca:              24/0 PASS
  - tb_mti_canceller:        43/43 PASS
  - tb_rxb_fullchain:        peak 24033 ~80x (parity with PR-D/E)
  - tb_doppler_realdata:     2056/2056 PASS  (had been broken pre-PR-F due
                             to missing RANGE_BINS=64 override; this PR fixes
                             the parameter override along with the widening)
  - tb_system_e2e:           33/49 PASS — identical to PR-E baseline; the
                             one new fail vs PR-D (G2.2) carries over.
  - tb_radar_receiver_final: still finishing in background (~10 min).
This commit is contained in:
Jason
2026-05-01 03:36:03 +05:45
parent a1a8fa7107
commit 7862f4d63c
10 changed files with 287 additions and 192 deletions
+28 -11
View File
@@ -24,6 +24,8 @@
* T14: cfar_busy asserts during processing, deasserts after
*/
`include "radar_params.vh"
module tb_cfar_ca;
// ============================================================================
@@ -43,24 +45,28 @@ reg reset_n;
reg [31:0] doppler_data;
reg doppler_valid;
reg [4:0] doppler_bin_in;
reg [5:0] range_bin_in;
reg [`RP_DOPPLER_BIN_WIDTH-1:0] doppler_bin_in;
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin_in;
reg frame_complete;
reg [3:0] cfg_guard_cells;
reg [4:0] cfg_train_cells;
reg [ALPHA_W-1:0] cfg_alpha;
reg [ALPHA_W-1:0] cfg_alpha_soft; // PR-F
reg [1:0] cfg_cfar_mode;
reg cfg_cfar_enable;
reg [15:0] cfg_simple_threshold;
wire detect_flag;
wire [`RP_DETECT_CLASS_WIDTH-1:0] detect_class; // PR-F
wire detect_valid;
wire [5:0] detect_range;
wire [4:0] detect_doppler;
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] detect_range;
wire [`RP_DOPPLER_BIN_WIDTH-1:0] detect_doppler;
wire [MAG_W-1:0] detect_magnitude;
wire [MAG_W-1:0] detect_threshold;
wire [MAG_W-1:0] detect_threshold_soft; // PR-F
wire [15:0] detect_count;
wire [15:0] detect_count_cand; // PR-F
wire cfar_busy;
wire [7:0] cfar_status;
@@ -84,8 +90,8 @@ reg [255:0] test_name;
// Detection capture (flagged detections only)
integer det_cap_count;
reg [5:0] det_cap_range [0:255];
reg [4:0] det_cap_doppler[0:255];
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] det_cap_range [0:255];
reg [`RP_DOPPLER_BIN_WIDTH-1:0] det_cap_doppler[0:255];
reg [MAG_W-1:0] det_cap_mag[0:255];
reg [MAG_W-1:0] det_cap_thr[0:255];
reg det_cap_flag [0:255];
@@ -110,16 +116,20 @@ cfar_ca #(
.cfg_guard_cells(cfg_guard_cells),
.cfg_train_cells(cfg_train_cells),
.cfg_alpha(cfg_alpha),
.cfg_alpha_soft(cfg_alpha_soft), // PR-F
.cfg_cfar_mode(cfg_cfar_mode),
.cfg_cfar_enable(cfg_cfar_enable),
.cfg_simple_threshold(cfg_simple_threshold),
.detect_flag(detect_flag),
.detect_class(detect_class), // PR-F
.detect_valid(detect_valid),
.detect_range(detect_range),
.detect_doppler(detect_doppler),
.detect_magnitude(detect_magnitude),
.detect_threshold(detect_threshold),
.detect_threshold_soft(detect_threshold_soft), // PR-F
.detect_count(detect_count),
.detect_count_cand(detect_count_cand), // PR-F
.cfar_busy(cfar_busy),
.cfar_status(cfar_status)
);
@@ -165,8 +175,8 @@ endtask
// Feed one Doppler sample (I/Q packed as {Q, I})
task feed_sample;
input [5:0] rbin;
input [4:0] dbin;
input [`RP_RANGE_BIN_WIDTH_MAX-1:0] rbin;
input [`RP_DOPPLER_BIN_WIDTH-1:0] dbin;
input signed [15:0] i_val;
input signed [15:0] q_val;
begin
@@ -184,8 +194,8 @@ endtask
// noise_level: base I value for all cells
// num_targets: number of target cells
// tgt_range[0..3], tgt_doppler[0..3], tgt_level[0..3]: target parameters
reg [5:0] tgt_range [0:7];
reg [4:0] tgt_doppler[0:7];
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] tgt_range [0:7];
reg [`RP_DOPPLER_BIN_WIDTH-1:0] tgt_doppler[0:7];
reg [15:0] tgt_level [0:7];
integer num_targets;
@@ -207,7 +217,9 @@ task feed_frame;
i_val = tgt_level[t];
end
end
feed_sample(r[5:0], d[4:0], $signed(i_val), 16'sd0);
feed_sample(r[`RP_RANGE_BIN_WIDTH_MAX-1:0],
d[`RP_DOPPLER_BIN_WIDTH-1:0],
$signed(i_val), 16'sd0);
end
end
end
@@ -304,6 +316,11 @@ initial begin
cfg_guard_cells = 4'd2;
cfg_train_cells = 5'd8;
cfg_alpha = 8'h30;
// PR-F: pin alpha_soft to max so the candidate tier never triggers in
// these tests preserves the original "detect_flag means CONFIRMED"
// semantics. The 2-class detection path is exercised by tb_system_e2e
// (live data) rather than this unit test.
cfg_alpha_soft = 8'hFF;
cfg_cfar_mode = 2'b00;
cfg_cfar_enable = 1'b1;
cfg_simple_threshold = 16'd5000;
+15 -6
View File
@@ -23,6 +23,8 @@
* vvp tb/tb_doppler_realdata.vvp
*/
`include "radar_params.vh"
module tb_doppler_realdata;
// ============================================================================
@@ -56,16 +58,23 @@ reg data_valid;
reg new_chirp_frame;
wire [31:0] doppler_output;
wire doppler_valid;
wire [4:0] doppler_bin;
wire [5:0] range_bin;
wire [`RP_DOPPLER_BIN_WIDTH-1:0] doppler_bin;
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin;
wire processing_active;
wire frame_complete;
wire [3:0] dut_status;
// ============================================================================
// DUT INSTANTIATION
// DUT INSTANTIATION — override CHIRPS_PER_FRAME=32 to keep this TB compatible
// with the legacy 2-subframe golden vectors (chirp-v2 production runs 3
// sub-frames at 48 chirps/frame; the Doppler FSM is parameterised over
// NUM_SUBFRAMES = CHIRPS_PER_FRAME / CHIRPS_PER_SUBFRAME).
// ============================================================================
doppler_processor_optimized dut (
doppler_processor_optimized #(
.CHIRPS_PER_FRAME(32),
.CHIRPS_PER_SUBFRAME(16),
.RANGE_BINS(64)
) dut (
.clk(clk),
.reset_n(reset_n),
.range_data(range_data),
@@ -109,8 +118,8 @@ end
// ============================================================================
reg signed [15:0] cap_out_i [0:TOTAL_OUTPUTS-1];
reg signed [15:0] cap_out_q [0:TOTAL_OUTPUTS-1];
reg [5:0] cap_rbin [0:TOTAL_OUTPUTS-1];
reg [4:0] cap_dbin [0:TOTAL_OUTPUTS-1];
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] cap_rbin [0:TOTAL_OUTPUTS-1];
reg [`RP_DOPPLER_BIN_WIDTH-1:0] cap_dbin [0:TOTAL_OUTPUTS-1];
integer out_count;
// ============================================================================
+14 -5
View File
@@ -33,6 +33,8 @@
* vvp tb/tb_fullchain_realdata.vvp
*/
`include "radar_params.vh"
module tb_fullchain_realdata;
// ============================================================================
@@ -91,8 +93,8 @@ reg new_chirp_frame;
wire [31:0] doppler_output;
wire doppler_valid;
wire [4:0] doppler_bin;
wire [5:0] range_bin;
wire [`RP_DOPPLER_BIN_WIDTH-1:0] doppler_bin;
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] range_bin;
wire processing_active;
wire frame_complete;
wire [3:0] dut_status;
@@ -122,7 +124,14 @@ range_bin_decimator #(
// ============================================================================
// DUT INSTANTIATION: Doppler Processor
// ============================================================================
doppler_processor_optimized doppler_proc (
doppler_processor_optimized #(
// Override CHIRPS_PER_FRAME / RANGE_BINS to keep this TB compatible with
// the legacy 2-subframe golden vectors (chirp-v2 production uses 48
// chirps × 512 ranges; this co-sim runs 32 × 64).
.CHIRPS_PER_FRAME(32),
.CHIRPS_PER_SUBFRAME(16),
.RANGE_BINS(64)
) doppler_proc (
.clk(clk),
.reset_n(reset_n),
.range_data(range_data_32bit),
@@ -174,8 +183,8 @@ reg signed [15:0] decim_cap_q [0:CHIRPS*RANGE_BINS-1];
// ============================================================================
reg signed [15:0] cap_out_i [0:TOTAL_OUTPUT_SAMPLES-1];
reg signed [15:0] cap_out_q [0:TOTAL_OUTPUT_SAMPLES-1];
reg [5:0] cap_rbin [0:TOTAL_OUTPUT_SAMPLES-1];
reg [4:0] cap_dbin [0:TOTAL_OUTPUT_SAMPLES-1];
reg [`RP_RANGE_BIN_WIDTH_MAX-1:0] cap_rbin [0:TOTAL_OUTPUT_SAMPLES-1];
reg [`RP_DOPPLER_BIN_WIDTH-1:0] cap_dbin [0:TOTAL_OUTPUT_SAMPLES-1];
integer out_count;
// ============================================================================