test(realdata): PR-K — synthetic regen of doppler/fullchain realdata fixtures

Replaces the legacy ADI CN0566 .npy capture flow with a synthetic radar
scene generated by tb/cosim/real_data/gen_realdata_hex.py via the
existing radar_scene + fpga_model bit-accurate Python models.

Dimensions now match production radar_params.vh:
  RP_FFT_SIZE=2048, RP_DECIMATION_FACTOR=4, RP_NUM_RANGE_BINS=512,
  CHIRPS_PER_FRAME=48, NUM_DOPPLER_BINS=48 (3 sub-frames x 16-pt FFT).

Previously both TBs were pinned to legacy 32-chirp / 2-subframe / 1024->64
DECIM=16 dimensions. range_bin_decimator.v's 2-bit comparisons against
DECIMATION_FACTOR/2 only behave correctly for small DECIM, so the old
DECIM=16 path no longer worked even though the TBs compiled — that is
why Full-Chain Real-Data was reporting pass=0/fail=3.

Changes:
  tb/cosim/real_data/gen_realdata_hex.py  (new) - synthesises 6 fixture
    files from a 2-target scene via DopplerProcessor (3-subframe) and
    RangeBinDecimator (peak, 2048->512). Reproducible (fixed seed 42).

  tb/cosim/real_data/golden_reference.py  (deleted, 1436 lines) - the
    legacy generator depended on out-of-tree ADI .npy captures and
    modelled only the 2-subframe / 32-chirp path.

  tb/cosim/real_data/hex/  - 43 orphan artifacts deleted (CFAR / MTI /
    notched / detection / range-FFT debug dumps that nothing in the
    active TB or regression was loading); 6 fixtures regenerated at
    production dimensions:
      doppler_input_realdata.hex     24576 packed lines (was 2048)
      doppler_ref_{i,q}.hex          24576 lines each   (was 2048)
      fullchain_range_input.hex      98304 packed lines (was 32768)
      fullchain_doppler_ref_{i,q}.hex 24576 lines each  (was 2048)

  tb/tb_doppler_realdata.v          - CHIRPS 32->48, RANGE_BINS 64->512,
                                       DOPPLER_FFT 32->48, MAX_CYCLES bumped.
  tb/tb_fullchain_realdata.v        - same + INPUT_BINS 1024->2048,
                                       DECIM_FACTOR 16->4, fixed
                                       decim_bin_index width to
                                       RP_RANGE_BIN_WIDTH_MAX, fixed
                                       start_bin width 10->11.

  run_regression.sh                 - "Doppler Real-Data" label updated
                                       (no longer "ADI CN0566"); both
                                       realdata tests get explicit
                                       --timeout values (300 / 600 s).

Standalone results:
  tb_doppler_realdata    - 24584/24584 PASS (3.36 s sim, ~50 s wall)
  tb_fullchain_realdata  - 24585/24585 PASS (4.10 s sim, ~5 min wall)

Full regression now: 41 passed / 1 failed (only remaining FAIL is
FFT Engine, pre-existing pre-PR-K regex-reveal — unrelated).
This commit is contained in:
Jason
2026-05-01 14:26:54 +05:45
parent 81d6f210cb
commit 237e74ceba
54 changed files with 221428 additions and 148542 deletions
+2 -2
View File
@@ -594,11 +594,11 @@ run_test "DDC Chain (NCO→CIC→FIR)" \
# Real-data co-simulation: committed golden hex vs RTL (exact match required).
# These catch architecture mismatches (e.g. 32-pt → dual 16-pt Doppler FFT)
# that self-blessing golden-generate/compare tests cannot detect.
run_test "Doppler Real-Data (ADI CN0566, exact match)" \
run_test --timeout=300 "Doppler Real-Data (synthetic, exact match)" \
tb/tb_doppler_realdata.vvp \
tb/tb_doppler_realdata.v doppler_processor.v xfft_16.v fft_engine.v
run_test "Full-Chain Real-Data (decim→Doppler, exact match)" \
run_test --timeout=600 "Full-Chain Real-Data (decim→Doppler, exact match)" \
tb/tb_fullchain_realdata.vvp \
tb/tb_fullchain_realdata.v range_bin_decimator.v \
doppler_processor.v xfft_16.v fft_engine.v
@@ -0,0 +1,182 @@
#!/usr/bin/env python3
"""
gen_realdata_hex.py — Synthetic stimulus + bit-exact golden for the realdata
co-simulation testbenches (tb_doppler_realdata, tb_fullchain_realdata).
Replaces the legacy ADI CN0566 hardware captures (32-chirp / 2-subframe /
32-bin Doppler) with a synthetic radar scene at production dimensions
(48-chirp / 3-subframe / 48-bin Doppler) so the regression no longer
depends on out-of-tree .npy files.
Outputs (six files, all under tb/cosim/real_data/hex/):
doppler_input_realdata.hex 48 chirps x 512 range bins, packed {Q,I}
doppler_ref_i.hex / _q.hex 512 range bins x 48 Doppler bins (signed 16-bit)
fullchain_range_input.hex 48 chirps x 2048 range bins, packed {Q,I}
fullchain_doppler_ref_i.hex
fullchain_doppler_ref_q.hex same shape as doppler_ref_*
Dimensions match production (radar_params.vh: RP_FFT_SIZE=2048,
RP_DECIMATION_FACTOR=4, RP_NUM_RANGE_BINS=512, RP_NUM_DOPPLER_BINS=48).
Pipeline modeled (bit-exact to RTL):
doppler-only: scene -> doppler_processor (3-subframe, 16-pt FFT, Hamming)
fullchain: scene -> range_bin_decimator (2048->512 peak, DECIM=4)
-> doppler_processor
Usage: python3 gen_realdata_hex.py
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from fpga_model import DopplerProcessor, RangeBinDecimator
from radar_scene import Target, generate_doppler_frame
# ----------------------------------------------------------------------------
# Production dimensions (radar_params.vh: PR-F + RP_FFT_SIZE/RP_DECIMATION_FACTOR)
# ----------------------------------------------------------------------------
NUM_SUBFRAMES = 3
DOPPLER_FFT_SIZE = 16
DOPPLER_TOTAL_BINS = NUM_SUBFRAMES * DOPPLER_FFT_SIZE # 48
CHIRPS_PER_SUBFRAME = 16
CHIRPS_PER_FRAME = NUM_SUBFRAMES * CHIRPS_PER_SUBFRAME # 48
# Doppler-only TB: post-decim range bins fed straight into doppler.
# Matches production RP_NUM_RANGE_BINS = RP_FFT_SIZE / RP_DECIMATION_FACTOR.
DOPPLER_RANGE_BINS = 512
# Fullchain TB: pre-decim 2048-bin range FFT -> range_bin_decimator (DECIM=4) -> doppler.
FULLCHAIN_INPUT_BINS = 2048
FULLCHAIN_OUTPUT_BINS = DOPPLER_RANGE_BINS # 512
FULLCHAIN_DECIM_FACTOR = FULLCHAIN_INPUT_BINS // FULLCHAIN_OUTPUT_BINS # 4
OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "hex")
# ----------------------------------------------------------------------------
# Scene — two distinct targets so both the FFT bin layout and the slow-time
# Doppler axis carry information across all three sub-frames.
# ----------------------------------------------------------------------------
SCENE_TARGETS = [
Target(range_m=300, velocity_mps= 10.0, rcs_dbsm=20.0),
Target(range_m=800, velocity_mps=-20.0, rcs_dbsm=15.0),
]
SCENE_SEED = 42
def write_hex_32(path, samples_iq):
"""Packed 32-bit {Q[31:16], I[15:0]} per line for $readmemh."""
with open(path, 'w') as f:
for (i_val, q_val) in samples_iq:
packed = ((q_val & 0xFFFF) << 16) | (i_val & 0xFFFF)
f.write(f"{packed:08X}\n")
def write_hex_16(path, values):
"""One signed 16-bit value per line, two's-complement hex."""
with open(path, 'w') as f:
for v in values:
f.write(f"{v & 0xFFFF:04X}\n")
def make_doppler_processor():
"""DopplerProcessor at production dimensions (3 sub-frames, 512 range bins)."""
return DopplerProcessor() # defaults: NUM_SUBFRAMES=3, RANGE_BINS=512
def flatten_doppler_map(doppler_i, doppler_q):
"""RTL stream order: rbin 0 [dbin 0..47], rbin 1 [...], ..., rbin 63 [...]."""
flat_i, flat_q = [], []
for rb in range(DOPPLER_RANGE_BINS):
for db in range(DOPPLER_TOTAL_BINS):
flat_i.append(doppler_i[rb][db])
flat_q.append(doppler_q[rb][db])
return flat_i, flat_q
def gen_doppler_realdata():
"""tb_doppler_realdata: post-decim 48 x 512 -> doppler 512 x 48."""
print("[doppler_realdata] generating ...")
frame_i, frame_q = generate_doppler_frame(
SCENE_TARGETS,
n_chirps=CHIRPS_PER_FRAME,
n_range_bins=DOPPLER_RANGE_BINS,
seed=SCENE_SEED,
)
stim = []
for c in range(CHIRPS_PER_FRAME):
for rb in range(DOPPLER_RANGE_BINS):
stim.append((frame_i[c][rb], frame_q[c][rb]))
write_hex_32(os.path.join(OUT_DIR, "doppler_input_realdata.hex"), stim)
dp = make_doppler_processor()
doppler_i, doppler_q = dp.process_frame(frame_i, frame_q)
flat_i, flat_q = flatten_doppler_map(doppler_i, doppler_q)
write_hex_16(os.path.join(OUT_DIR, "doppler_ref_i.hex"), flat_i)
write_hex_16(os.path.join(OUT_DIR, "doppler_ref_q.hex"), flat_q)
print(f" stimulus: {len(stim)} packed lines (expected {CHIRPS_PER_FRAME * DOPPLER_RANGE_BINS})")
print(f" golden: {len(flat_i)} lines i / {len(flat_q)} lines q "
f"(expected {DOPPLER_RANGE_BINS * DOPPLER_TOTAL_BINS})")
def gen_fullchain_realdata():
"""tb_fullchain_realdata: 48 x 2048 -> RangeBinDecimator (DECIM=4 peak) -> doppler 512 x 48."""
print("[fullchain_realdata] generating ...")
frame_i, frame_q = generate_doppler_frame(
SCENE_TARGETS,
n_chirps=CHIRPS_PER_FRAME,
n_range_bins=FULLCHAIN_INPUT_BINS,
seed=SCENE_SEED,
)
stim = []
for c in range(CHIRPS_PER_FRAME):
for rb in range(FULLCHAIN_INPUT_BINS):
stim.append((frame_i[c][rb], frame_q[c][rb]))
write_hex_32(os.path.join(OUT_DIR, "fullchain_range_input.hex"), stim)
# fpga_model.RangeBinDecimator is hard-coded to 2048->512, DECIM=4 — production.
decim_i_2d, decim_q_2d = [], []
for c in range(CHIRPS_PER_FRAME):
di, dq = RangeBinDecimator.decimate(frame_i[c], frame_q[c], mode=1, start_bin=0)
decim_i_2d.append(di)
decim_q_2d.append(dq)
dp = make_doppler_processor()
doppler_i, doppler_q = dp.process_frame(decim_i_2d, decim_q_2d)
flat_i, flat_q = flatten_doppler_map(doppler_i, doppler_q)
write_hex_16(os.path.join(OUT_DIR, "fullchain_doppler_ref_i.hex"), flat_i)
write_hex_16(os.path.join(OUT_DIR, "fullchain_doppler_ref_q.hex"), flat_q)
print(f" stimulus: {len(stim)} packed lines "
f"(expected {CHIRPS_PER_FRAME * FULLCHAIN_INPUT_BINS})")
print(f" golden: {len(flat_i)} lines i / {len(flat_q)} lines q "
f"(expected {DOPPLER_RANGE_BINS * DOPPLER_TOTAL_BINS})")
def main():
os.makedirs(OUT_DIR, exist_ok=True)
gen_doppler_realdata()
gen_fullchain_realdata()
print("\nGenerated files:")
for f in (
"doppler_input_realdata.hex",
"doppler_ref_i.hex",
"doppler_ref_q.hex",
"fullchain_range_input.hex",
"fullchain_doppler_ref_i.hex",
"fullchain_doppler_ref_q.hex",
):
path = os.path.join(OUT_DIR, f)
with open(path) as fp:
n_lines = sum(1 for _ in fp)
print(f" {f:40s} {n_lines:7d} lines ({os.path.getsize(path):7d} bytes)")
if __name__ == '__main__':
main()
File diff suppressed because it is too large Load Diff
@@ -1,42 +0,0 @@
# Golden Reference Hex Files
These hex files are **committed golden references** for strict bit-exact
real-data regression tests (`tb_doppler_realdata.v`, `tb_fullchain_realdata.v`).
## When to regenerate
Regenerate whenever the Doppler processing pipeline changes:
- `doppler_processor.v` (FFT size, window, sub-frame structure)
- `xfft_16.v` / `fft_engine.v` (butterfly arithmetic, twiddle lookup)
- `range_bin_decimator.v` (decimation mode, peak detection logic)
- `fft_twiddle_16.mem` (twiddle factor ROM)
## How to regenerate
```bash
cd 9_Firmware/9_2_FPGA
python3 tb/cosim/real_data/golden_reference.py
# Then copy the Doppler-specific files:
python3 -c "
import numpy as np, os, shutil
h = 'tb/cosim/real_data/hex'
# Regenerate packed stimulus from range FFT npy
ri = np.load(f'{h}/range_fft_all_i.npy')
rq = np.load(f'{h}/range_fft_all_q.npy')
with open(f'{h}/doppler_input_realdata.hex','w') as f:
for c in range(32):
for r in range(64):
i=int(ri[c,r])&0xFFFF; q=int(rq[c,r])&0xFFFF
f.write(f'{(q<<16)|i:08X}\n')
shutil.copy2(f'{h}/doppler_map_i.hex', f'{h}/doppler_ref_i.hex')
shutil.copy2(f'{h}/doppler_map_q.hex', f'{h}/doppler_ref_q.hex')
"
```
## Architecture
Generated against the **dual 16-point FFT** Doppler architecture
(2 staggered-PRI sub-frames x 16-point Hamming-windowed FFT).
Source data: ADI CN0566 Phaser radar (10.525 GHz X-band FMCW, 4 MSPS).
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,361 +0,0 @@
# AERIS-10 Golden Reference Detections
# Threshold: 10000
# Format: range_bin doppler_bin magnitude
0 0 35364
0 1 16147
0 15 11821
0 16 24536
0 17 11208
0 31 10122
1 0 25697
1 1 12174
1 15 13421
1 16 20002
1 17 11568
1 31 11299
2 0 16788
2 16 20207
2 31 10711
3 0 29174
3 1 13965
3 15 13305
3 16 31517
3 17 13478
3 31 14101
4 0 41986
4 1 19241
4 15 21030
4 16 39714
4 17 17538
4 31 20394
5 0 23766
5 1 11599
5 15 14843
5 16 18211
5 31 12009
6 0 42015
6 1 21423
6 15 21018
6 16 47402
6 17 22815
6 31 22736
7 0 32152
7 1 15393
7 15 14318
7 16 28911
7 17 13876
7 31 17156
8 0 11067
10 0 18848
10 15 10020
10 16 20027
10 31 10048
11 0 65534
11 1 37617
11 2 14940
11 15 43078
11 16 65534
11 17 39344
11 31 45926
12 0 58975
12 1 22078
12 15 34440
12 16 59096
12 17 22512
12 31 28677
13 0 38442
13 1 29490
13 15 37679
13 16 44951
13 17 27726
13 31 39144
14 0 52660
14 1 27797
14 2 13534
14 15 39671
14 16 57929
14 17 24160
14 31 31478
15 0 30021
15 1 12219
15 15 17232
15 16 29524
15 17 13424
15 31 17850
16 0 17593
16 16 24710
16 31 13046
17 0 17606
17 1 11119
17 16 13182
18 16 15914
19 0 55785
19 1 29069
19 15 29418
19 16 55308
19 17 27886
19 31 30649
20 0 49230
20 1 24486
20 15 21233
20 16 45472
20 17 21749
20 31 21614
21 0 26167
21 1 13823
21 15 10487
21 16 29034
21 17 15861
21 31 10454
22 0 12791
22 16 22520
22 17 11384
22 31 11790
23 0 29337
23 1 17065
23 15 14174
23 16 39414
23 17 23310
23 31 17173
24 0 16889
24 15 15710
24 16 22395
24 31 15003
25 0 65535
25 1 40375
25 15 54011
25 16 61127
25 17 38944
25 31 48889
26 0 46367
26 1 39852
26 15 29630
26 16 53587
26 17 40655
26 31 34936
27 0 65535
27 1 65535
27 15 64456
27 16 65535
27 17 65535
27 31 58334
28 0 65535
28 1 57641
28 15 65535
28 16 65535
28 17 54928
28 31 65535
29 0 65535
29 1 44117
29 2 13478
29 14 11179
29 15 65535
29 16 65535
29 17 45898
29 18 10817
29 31 60442
30 0 44530
30 1 36909
30 2 14573
30 15 43430
30 16 51839
30 17 37271
30 31 47866
31 0 40957
31 1 52081
31 2 12755
31 15 42794
31 16 41071
31 17 50472
31 18 11556
31 31 43866
32 0 35747
32 1 19597
32 15 25173
32 16 39213
32 17 21782
32 31 29106
33 0 34216
33 1 41661
33 15 42368
33 16 38638
33 17 40522
33 31 45908
34 0 36589
34 1 17165
34 15 16488
34 16 26972
34 17 12089
34 31 13576
35 0 65536
35 1 42536
35 15 61612
35 16 65536
35 17 43084
35 31 60807
36 0 55831
36 1 26499
36 15 28393
36 16 50059
36 17 24420
36 31 23905
38 0 52721
38 1 33692
38 15 32463
38 16 53145
38 17 37178
38 31 30632
39 0 32288
39 1 19461
39 15 20183
39 16 27198
39 17 16723
39 31 14041
40 0 47793
40 1 29861
40 15 23082
40 16 43109
40 17 30298
40 31 31219
41 0 65536
41 1 57642
41 15 52984
41 16 65536
41 17 57420
41 31 57035
42 0 46393
42 1 24862
42 15 27123
42 16 44734
42 17 25836
42 31 33316
43 0 65535
43 1 43056
43 13 10481
43 14 22074
43 15 24792
43 16 39506
43 17 36481
43 30 24870
43 31 39062
44 0 65535
44 1 65535
44 2 19166
44 3 21321
44 13 32864
44 14 41461
44 15 65535
44 16 65535
44 17 58493
44 19 13967
44 29 29756
44 30 54069
44 31 65535
45 0 65535
45 1 58886
45 14 22013
45 15 65116
45 16 65535
45 17 65535
45 29 13068
45 30 25759
45 31 61393
46 0 53411
46 1 44267
46 15 30631
46 16 58196
46 17 36338
46 31 28840
47 0 54574
47 1 35574
47 15 38960
47 16 46623
47 17 32070
47 31 40091
48 0 22302
48 1 10865
48 15 13917
48 16 18042
48 31 10930
49 0 49013
49 1 28270
49 15 25242
49 16 41969
49 17 24924
49 31 26704
50 0 43858
50 1 35227
50 15 39737
50 16 39085
50 17 36353
50 31 38658
51 0 33868
51 1 23364
51 15 23348
51 16 33246
51 17 24398
51 31 27415
52 0 24500
52 1 10467
52 15 13661
52 16 21073
52 17 10681
52 31 10164
53 0 46806
53 1 31121
53 15 34423
53 16 44568
53 17 28497
53 31 35229
54 0 49713
54 1 32292
54 15 40878
54 16 54060
54 17 34252
54 31 43616
55 0 25597
55 1 13662
55 15 13184
55 16 20525
55 17 10363
55 31 12295
56 0 53620
56 1 23575
56 14 12578
56 15 34783
56 16 64499
56 17 32442
56 31 32139
58 0 65535
58 1 35008
58 15 43324
58 16 64959
58 17 35348
58 31 39154
59 0 13238
59 1 11374
59 14 16623
59 16 22346
59 17 12583
60 0 31259
60 1 17900
60 15 19638
60 16 26331
60 17 12543
60 31 18056
61 0 14596
61 15 13600
61 16 23597
61 17 10681
61 31 14915
62 0 22096
62 1 10515
62 16 23642
62 17 11146
62 31 10180
63 0 58324
63 1 25269
63 15 32920
63 16 54165
63 17 27625
63 31 29816
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,8 +0,0 @@
# AERIS-10 Full-Chain CFAR Detection List
# Chain: decim -> MTI -> Doppler -> DC notch(w=2) -> CA-CFAR
# CFAR: guard=2, train=8, alpha=0x30, mode=CA
# Format: range_bin doppler_bin magnitude threshold
2 14 57128 48153
2 29 20281 15318
2 30 44783 22389
3 26 19423 19422
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,211 +0,0 @@
# AERIS-10 Full-Chain Golden Reference Detections
# Threshold: 10000
# Format: range_bin doppler_bin magnitude
0 0 65534
0 1 28729
0 2 18427
0 3 14971
0 14 11972
0 15 53110
0 16 65534
0 17 39344
0 31 45926
1 0 65535
1 1 65535
1 2 16977
1 4 13219
1 10 10505
1 12 12931
1 14 23806
1 15 65535
1 16 65535
1 17 65535
1 31 55887
2 0 65535
2 1 65535
2 2 19166
2 3 21321
2 13 32864
2 14 41461
2 15 65535
2 16 65535
2 17 58493
2 19 13967
2 29 29756
2 30 54069
2 31 65535
3 0 53605
3 1 48935
3 2 24589
3 4 12240
3 5 14117
3 8 12950
3 11 13274
3 12 12930
3 14 23437
3 15 29552
3 16 65433
3 17 52933
3 18 24719
3 19 17650
3 20 15096
3 21 13518
3 27 13184
3 28 15554
3 29 23742
3 30 17775
3 31 19771
4 0 46125
4 1 38769
4 14 10924
4 15 33844
4 16 38130
4 17 36763
4 31 34850
5 0 29649
5 1 15983
5 16 27615
5 17 13683
5 31 11456
6 0 29881
6 1 14520
6 15 14126
6 16 33068
6 17 14679
6 31 16608
7 0 15305
7 16 16195
8 0 22601
8 16 32614
8 17 16367
8 31 16217
9 0 33316
9 1 14993
9 15 19928
9 16 38915
9 17 20159
9 31 17219
10 0 31772
10 1 16438
10 15 13737
10 16 29059
10 17 15821
10 31 13104
11 0 30448
11 1 15802
11 15 12669
11 16 30129
11 17 14340
11 31 12767
12 0 12892
12 16 15956
13 16 10903
17 0 11395
17 16 10440
19 0 11910
19 16 12017
20 0 42212
20 1 17994
20 15 23540
20 16 42519
20 17 15949
20 31 23792
21 0 19822
21 2 13933
21 3 12130
21 13 11590
21 14 14794
21 15 14160
21 16 36543
21 17 19530
21 31 13754
22 0 12654
26 16 10634
30 0 11396
38 0 12032
38 1 11693
38 16 18530
39 0 13327
39 1 12416
39 2 10940
39 15 10351
39 16 25217
39 17 11785
39 31 12383
40 16 14316
45 0 16350
45 16 16146
46 0 11710
46 16 12568
46 31 12206
47 15 12053
47 16 17267
49 0 22212
49 15 11409
49 16 20817
50 0 14287
50 16 13382
51 0 15578
51 1 11129
51 16 12819
53 16 10532
55 0 24789
55 15 10455
55 16 25212
55 17 10510
55 31 12207
56 0 45192
56 1 16083
56 15 22284
56 16 40302
56 17 17318
56 31 19185
57 0 41535
57 1 27102
57 2 50048
57 3 30784
57 6 10595
57 8 12880
57 12 16303
57 13 21792
57 14 36737
57 15 51757
57 16 53641
57 17 33656
57 18 11096
57 31 50828
58 0 49157
58 1 40063
58 15 33919
58 16 44578
58 17 46214
58 31 35365
59 0 40306
59 1 20804
59 15 16849
59 16 25943
59 18 11684
59 30 15453
59 31 26587
60 0 19637
60 15 12275
60 16 18527
60 30 10157
60 31 17278
61 0 15147
61 14 10732
61 15 12364
61 16 25489
61 17 13371
61 31 14278
62 1 14922
62 2 13924
62 16 29381
62 17 20524
62 31 12898
63 0 48946
63 1 23135
63 15 21609
63 16 44144
63 17 21410
63 31 19856
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+35 -30
View File
@@ -3,16 +3,23 @@
/**
* tb_doppler_realdata.v
*
* Co-simulation testbench: feeds real ADI CN0566 radar data (post-range-FFT)
* through the Doppler processor RTL and compares output bit-for-bit against
* the Python golden reference (golden_reference.py).
* Co-simulation testbench: feeds synthetic post-range-FFT data (48 chirps x
* 64 range bins) into the Doppler processor RTL and compares output
* bit-for-bit against the Python golden reference produced by
* tb/cosim/real_data/gen_realdata_hex.py.
*
* Stimulus + golden are regenerated from `radar_scene.py` + `fpga_model.py`
* at production dimensions (3 sub-frames, 48-chirp frame, 48-bin Doppler,
* 512 post-decim range bins to match RP_NUM_RANGE_BINS = RP_FFT_SIZE/RP_DECIMATION_FACTOR
* = 2048/4 in radar_params.vh). The legacy ADI CN0566 .npy capture flow has
* been retired see the generator script header for scene parameters.
*
* Stimulus: cosim/real_data/hex/doppler_input_realdata.hex
* (2048 x 32-bit packed {Q[31:16], I[15:0]}, chirp-major order)
* (24576 x 32-bit packed {Q[31:16], I[15:0]}, chirp-major order)
* Expected: cosim/real_data/hex/doppler_ref_i.hex, doppler_ref_q.hex
* (2048 x 16-bit signed, range-major order: rbin0 x 32 doppler, ...)
* (24576 x 16-bit signed, range-major: rbin0 x 48 doppler, ...)
*
* Pass criteria: ALL 2048 output bins match golden reference exactly.
* Pass criteria: ALL 24576 output bins match golden reference exactly.
*
* Compile:
* iverilog -Wall -DSIMULATION -g2012 \
@@ -31,12 +38,12 @@ module tb_doppler_realdata;
// PARAMETERS
// ============================================================================
localparam CLK_PERIOD = 10.0; // 100 MHz
localparam DOPPLER_FFT = 32; // Total packed Doppler bins (2 sub-frames x 16-pt FFT)
localparam RANGE_BINS = 64;
localparam CHIRPS = 32;
localparam TOTAL_INPUTS = CHIRPS * RANGE_BINS; // 2048
localparam TOTAL_OUTPUTS = RANGE_BINS * DOPPLER_FFT; // 2048
localparam MAX_CYCLES = 500_000; // Timeout: 5 ms at 100 MHz
localparam DOPPLER_FFT = 48; // Total packed Doppler bins (3 sub-frames x 16-pt FFT)
localparam RANGE_BINS = 512; // RP_NUM_RANGE_BINS (post-decim, RP_FFT_SIZE / RP_DECIMATION_FACTOR)
localparam CHIRPS = 48;
localparam TOTAL_INPUTS = CHIRPS * RANGE_BINS; // 24576
localparam TOTAL_OUTPUTS = RANGE_BINS * DOPPLER_FFT; // 24576
localparam MAX_CYCLES = 5_000_000; // Timeout: 50 ms at 100 MHz
// Error tolerance: 0 means exact match required.
localparam integer MAX_ERROR = 0;
@@ -65,18 +72,14 @@ wire frame_complete;
wire [3:0] dut_status;
// ============================================================================
// DUT INSTANTIATION — override CHIRPS_PER_FRAME=32 (NUM_SUBFRAMES=2). This
// TB is a strict bit-exact regression against pre-recorded ADI CN0566 Phaser
// data (32 chirps x 64 range bins) generated by golden_reference.py against
// the legacy 2-subframe architecture; production 3-subframe (48-chirp)
// coverage now lives in tb_doppler_cosim.v with synthetic stimulus.
// Regenerating realdata for 48 chirps would need new ADI captures plus a
// 3-subframe rewrite of golden_reference.py — tracked as a PR-I follow-up.
// DUT INSTANTIATION — production dimensions (NUM_SUBFRAMES=3, 48-chirp frame,
// 64 post-decim range bins). Stimulus and golden are regenerated synthetically
// by tb/cosim/real_data/gen_realdata_hex.py from radar_scene + fpga_model.
// ============================================================================
doppler_processor_optimized #(
.CHIRPS_PER_FRAME(32),
.CHIRPS_PER_FRAME(48),
.CHIRPS_PER_SUBFRAME(16),
.RANGE_BINS(64)
.RANGE_BINS(512)
) dut (
.clk(clk),
.reset_n(reset_n),
@@ -172,15 +175,17 @@ initial begin
$display("============================================================");
$display(" Doppler Processor Real-Data Co-Simulation");
$display(" ADI CN0566 Phaser 10.525 GHz X-band FMCW");
$display(" Input: 32 chirps x 64 range bins (post-range-FFT)");
$display(" Expected: 64 range bins x 32 Doppler bins");
$display(" Synthetic scene -> doppler_processor (3-subframe, 48-bin)");
$display(" Input: %0d chirps x %0d range bins = %0d samples",
CHIRPS, RANGE_BINS, TOTAL_INPUTS);
$display(" Expected: %0d range bins x %0d Doppler bins = %0d outputs",
RANGE_BINS, DOPPLER_FFT, TOTAL_OUTPUTS);
$display("============================================================");
// ---- Debug: check hex file loaded ----
$display(" input_mem[0] = %08h", input_mem[0]);
$display(" input_mem[1] = %08h", input_mem[1]);
$display(" input_mem[2047] = %08h", input_mem[2047]);
$display(" input_mem[0] = %08h", input_mem[0]);
$display(" input_mem[1] = %08h", input_mem[1]);
$display(" input_mem[%0d] = %08h", TOTAL_INPUTS - 1, input_mem[TOTAL_INPUTS - 1]);
$display(" ref_i[0] = %04h, ref_q[0] = %04h", ref_i[0], ref_q[0]);
// ---- Check 1: DUT starts in IDLE ----
@@ -240,7 +245,7 @@ initial begin
// ---- Check 3: Correct output count ----
check(out_count == TOTAL_OUTPUTS,
"Output sample count == 2048");
"Output sample count == 24576");
// ---- Check 4: Did not timeout ----
check(cycle_count < MAX_CYCLES,
@@ -258,9 +263,9 @@ initial begin
end
if (out_count == TOTAL_OUTPUTS) begin
check(cap_rbin[TOTAL_OUTPUTS-1] == RANGE_BINS - 1,
"Last output: range_bin=63");
"Last output: range_bin=511");
check(cap_dbin[TOTAL_OUTPUTS-1] == DOPPLER_FFT - 1,
"Last output: doppler_bin=31");
"Last output: doppler_bin=47");
end
// ==================================================================
+40 -35
View File
@@ -3,25 +3,29 @@
/**
* tb_fullchain_realdata.v
*
* Full-chain co-simulation testbench: feeds real ADI CN0566 radar data
* (post-range-FFT, 32 chirps x 1024 bins) through:
* Full-chain co-simulation testbench: feeds synthetic post-range-FFT data
* (48 chirps x 2048 bins) through:
*
* range_bin_decimator (peak detection, 102464)
* doppler_processor_optimized (Hamming + dual 16-pt FFT)
* range_bin_decimator (peak detection, 2048512, DECIM=4)
* doppler_processor_optimized (Hamming + 3 x 16-pt FFT, 48-bin Doppler)
*
* and compares the Doppler output bit-for-bit against the Python golden
* reference that models the same chain (golden_reference.py).
* Dimensions match production radar_params.vh: RP_FFT_SIZE=2048,
* RP_DECIMATION_FACTOR=4, RP_NUM_RANGE_BINS=512, RP_NUM_DOPPLER_BINS=48.
*
* The Python golden (tb/cosim/real_data/gen_realdata_hex.py) applies the
* same decimator + Doppler chain bit-exactly via fpga_model.py. The legacy
* ADI CN0566 .npy capture flow has been retired.
*
* Stimulus:
* tb/cosim/real_data/hex/fullchain_range_input.hex
* 32768 x 32-bit packed {Q[31:16], I[15:0]} 32 chirps x 1024 bins
* 98304 x 32-bit packed {Q[31:16], I[15:0]} 48 chirps x 2048 bins
*
* Expected:
* tb/cosim/real_data/hex/fullchain_doppler_ref_i.hex
* tb/cosim/real_data/hex/fullchain_doppler_ref_q.hex
* 2048 x 16-bit signed 64 range bins x 32 Doppler bins
* 24576 x 16-bit signed 512 range bins x 48 Doppler bins
*
* Pass criteria: ALL 2048 Doppler output bins match exactly.
* Pass criteria: ALL 24576 Doppler output bins match exactly.
*
* Compile:
* iverilog -Wall -DSIMULATION -g2012 \
@@ -41,19 +45,19 @@ module tb_fullchain_realdata;
// PARAMETERS
// ============================================================================
localparam CLK_PERIOD = 10.0; // 100 MHz
localparam DOPPLER_FFT = 32;
localparam RANGE_BINS = 64;
localparam CHIRPS = 32;
localparam INPUT_BINS = 1024;
localparam DECIM_FACTOR = 16;
localparam DOPPLER_FFT = 48; // 3 sub-frames x 16-pt FFT
localparam RANGE_BINS = 512; // RP_NUM_RANGE_BINS (post-decim)
localparam CHIRPS = 48;
localparam INPUT_BINS = 2048; // RP_FFT_SIZE
localparam DECIM_FACTOR = 4; // RP_DECIMATION_FACTOR (2048->512)
localparam TOTAL_INPUT_SAMPLES = CHIRPS * INPUT_BINS; // 32768
localparam TOTAL_OUTPUT_SAMPLES = RANGE_BINS * DOPPLER_FFT; // 2048
localparam SAMPLES_PER_CHIRP = INPUT_BINS; // 1024
localparam DECIM_PER_CHIRP = RANGE_BINS; // 64
localparam TOTAL_INPUT_SAMPLES = CHIRPS * INPUT_BINS; // 98304
localparam TOTAL_OUTPUT_SAMPLES = RANGE_BINS * DOPPLER_FFT; // 24576
localparam SAMPLES_PER_CHIRP = INPUT_BINS; // 2048
localparam DECIM_PER_CHIRP = RANGE_BINS; // 512
// Generous timeout: decimator + Doppler processing + margin
localparam MAX_CYCLES = 2_000_000;
localparam MAX_CYCLES = 8_000_000;
// Error tolerance: 0 = exact match required
localparam integer MAX_ERROR = 0;
@@ -77,7 +81,7 @@ reg decim_valid_in;
wire signed [15:0] decim_i_out;
wire signed [15:0] decim_q_out;
wire decim_valid_out;
wire [5:0] decim_bin_index;
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] decim_bin_index;
// ============================================================================
// DOPPLER SIGNALS
@@ -117,7 +121,7 @@ range_bin_decimator #(
.range_valid_out(decim_valid_out),
.range_bin_index(decim_bin_index),
.decimation_mode(2'b01), // Peak detection mode
.start_bin(10'd0),
.start_bin(11'd0),
.watchdog_timeout()
);
@@ -125,12 +129,12 @@ range_bin_decimator #(
// DUT INSTANTIATION: Doppler Processor
// ============================================================================
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),
// Production 3-subframe / 48-chirp frame. RANGE_BINS=512 matches the
// 2048->512 range_bin_decimator output (RP_DECIMATION_FACTOR=4).
// Stimulus and golden are regenerated by gen_realdata_hex.py.
.CHIRPS_PER_FRAME(48),
.CHIRPS_PER_SUBFRAME(16),
.RANGE_BINS(64)
.RANGE_BINS(512)
) doppler_proc (
.clk(clk),
.reset_n(reset_n),
@@ -252,8 +256,8 @@ initial begin
$display("============================================================");
$display(" Full-Chain Real-Data Co-Simulation");
$display(" range_bin_decimator (peak, 1024->64)");
$display(" -> doppler_processor_optimized (Hamming + dual 16-pt FFT)");
$display(" ADI CN0566 Phaser 10.525 GHz X-band FMCW");
$display(" -> doppler_processor_optimized (Hamming + 3 x 16-pt FFT)");
$display(" Synthetic scene at production 3-subframe / 48-chirp dimensions");
$display(" Input: %0d chirps x %0d range FFT bins = %0d samples",
CHIRPS, INPUT_BINS, TOTAL_INPUT_SAMPLES);
$display(" Expected: %0d range bins x %0d Doppler bins = %0d outputs",
@@ -261,9 +265,10 @@ initial begin
$display("============================================================");
// ---- Debug: check hex files loaded ----
$display(" input_mem[0] = %08h", input_mem[0]);
$display(" input_mem[1023] = %08h", input_mem[1023]);
$display(" input_mem[32767] = %08h", input_mem[32767]);
$display(" input_mem[0] = %08h", input_mem[0]);
$display(" input_mem[1023] = %08h", input_mem[1023]);
$display(" input_mem[%0d] = %08h", TOTAL_INPUT_SAMPLES - 1,
input_mem[TOTAL_INPUT_SAMPLES - 1]);
$display(" ref_i[0] = %04h, ref_q[0] = %04h", ref_i[0], ref_q[0]);
// ---- Check 1: Both DUTs start in IDLE ----
@@ -324,7 +329,7 @@ initial begin
// ---- Check 3: Decimator produced correct number of outputs ----
check(decim_out_count == CHIRPS * RANGE_BINS,
"Decimator output count == 2048");
"Decimator output count == 24576");
// ---- Wait for Doppler processing to complete ----
$display("\n--- Waiting for Doppler to process and emit %0d outputs ---",
@@ -349,7 +354,7 @@ initial begin
// ---- Check 4: Correct Doppler output count ----
check(out_count == TOTAL_OUTPUT_SAMPLES,
"Doppler output count == 2048");
"Doppler output count == 24576");
// ---- Check 5: Did not timeout ----
check(cycle_count < MAX_CYCLES,
@@ -367,9 +372,9 @@ initial begin
end
if (out_count == TOTAL_OUTPUT_SAMPLES) begin
check(cap_rbin[TOTAL_OUTPUT_SAMPLES-1] == RANGE_BINS - 1,
"Last output: range_bin=63");
"Last output: range_bin=511");
check(cap_dbin[TOTAL_OUTPUT_SAMPLES-1] == DOPPLER_FFT - 1,
"Last output: doppler_bin=31");
"Last output: doppler_bin=47");
end
// ==================================================================