diff --git a/intel/radar/metrology_suite/README.md b/intel/radar/metrology_suite/README.md index bbad0c1..d640303 100644 --- a/intel/radar/metrology_suite/README.md +++ b/intel/radar/metrology_suite/README.md @@ -2,6 +2,9 @@ This directory serves as the source of truth for the **C-SHENRON Radar Metrology Suite**. The goal of this suite is to transform the physics-based radar simulation from a "Black Box" into a transparent "Radar Lab" environment. +> [!TIP] +> **New Feature:** For a detailed step-by-step guide on using these new tools, see the official [**Walkthrough Guide**](./walkthrough.md). + --- ## 🎯 1. The Core Objective @@ -26,28 +29,33 @@ Current state: Successfully converts LiDAR points into complex ADC time-series. ### B. Signal Processing (`radar_processor.py` & `cfar_detector.py`) Current state: Performs 2D FFT and CA-CFAR detection. -* **Modification Plan:** - - Retain the **3D FFT Cube** (Range x Doppler x Angle). - - Extract the **Threshold Matrix** from `CA_CFAR.__call__`. - - Compute global **Range-Azimuth** energy maps via mean-Doppler reduction. +* **Implementation Status:** + - Exposes the **3D FFT Cube** (Range x Doppler x Angle). + - Extracts the **Detection Gate** from `CA_CFAR.__call__`. + - Computes global **Range-Azimuth** energy maps via mean-Doppler reduction. --- -## 🗺️ 3. Active Implementation Roadmap +## 🗺️ 3. Implementation Roadmap + +### Phase 1: Engine Heatmap Extraction (COMPLETED) +- [x] Modify `cfar_detector.py` to return the `detection_gate` (Threshold Baseline). +- [x] Update `radar_processor.py` to capture RD and compute global RA heatmaps. +- [x] Update `model_wrapper.py` to expose heatmaps and signal telemetry. -### Phase 1: Engine Heatmap Extraction (IN PROGRESS) -- [ ] Modify `cfar_detector.py` to return the `rd_avg_noise_power` (Threshold Baseline). -- [ ] Update `radar_processor.py` to capture RD and compute global RA heatmaps. -- [ ] Update `model_wrapper.py` to expose heatmaps and signal telemetry. +### Phase 2: Signal-to-Visual Pipeline (COMPLETED) +- [x] Implement 8-bit normalization and Viridis colormapping for radar image topics. +- [x] Update `test_shenron.py` to register new `/heatmaps/` image channels in MCAP. +- [x] Add JSON telemetry packaging for SNR/Noise metrics. -### Phase 2: Signal-to-Visual Pipeline (PENDING) -- [ ] Implement 8-bit normalization and Viridis colormapping for radar image topics. -- [ ] Update `test_shenron.py` to register new `/heatmaps/` image channels in MCAP. -- [ ] Add JSON telemetry packaging for SNR/Noise metrics. +### Phase 3: Raw Data Persistence (COMPLETED) +- [x] Create `metrology/rd`, `metrology/ra`, and `metrology/cfar` directory structure. +- [x] Implement `.npy` serialization for every frame during the simulation loop. -### Phase 3: Raw Data Persistence (PENDING) -- [ ] Create `metrology/rd`, `metrology/ra`, and `metrology/cfar` directory structure. -- [ ] Implement `.npy` serialization for every frame during the simulation loop. +### Phase 4: Verification (COMPLETED) +- [x] Run Iteration 18 (250-frame simulation sweep). +- [x] Inspect raw `.npy` files for precision integrity. +- [x] Verify Foxglove visual alignment. --- @@ -58,4 +66,4 @@ Current state: Performs 2D FFT and CA-CFAR detection. * **Performance:** Keep the `signal.convolve2d` calls optimized; we must maintain at least 1.0 FPS for UX. --- -*Created by Antigravity | Project: Fox CARLA ADAS | 2026-04-07* +*Created by Antigravity | Project: Fox CARLA ADAS | 2026-04-08* diff --git a/scripts/test_shenron.py b/scripts/test_shenron.py index 29d2a29..4794432 100644 --- a/scripts/test_shenron.py +++ b/scripts/test_shenron.py @@ -337,21 +337,24 @@ def run_testbench(iter_name): if rd_p.exists(): rd_data = np.load(rd_p) - b64 = render_heatmap(np.log10(rd_data + 1e-9), cmap='viridis') + # Flip UD so Range 0 (ego) is at the bottom + b64 = render_heatmap(np.log10(np.flipud(rd_data) + 1e-9), cmap='viridis') if b64: msg = {"timestamp": {"sec": ts_sec, "nsec": ts_nsec}, "frame_id": "ego_vehicle", "format": "png", "data": b64} writer.add_message(metrology_channels[r_type]["rd"], log_time=ts_ns, data=json.dumps(msg).encode(), publish_time=ts_ns) if ra_p.exists(): ra_data = np.load(ra_p) - b64 = render_heatmap(np.log10(ra_data + 1e-9), cmap='magma') # Magma for top-down contrast + # Flip UD so Range 0 (ego) is at the bottom + b64 = render_heatmap(np.log10(np.flipud(ra_data) + 1e-9), cmap='magma') # Magma for top-down contrast if b64: msg = {"timestamp": {"sec": ts_sec, "nsec": ts_nsec}, "frame_id": "ego_vehicle", "format": "png", "data": b64} writer.add_message(metrology_channels[r_type]["ra"], log_time=ts_ns, data=json.dumps(msg).encode(), publish_time=ts_ns) if cf_p.exists(): cf_data = np.load(cf_p) - b64 = render_heatmap(np.log10(cf_data + 1e-9), cmap='plasma') # Plasma for threshold mask + # Flip UD so Range 0 (ego) is at the bottom + b64 = render_heatmap(np.log10(np.flipud(cf_data) + 1e-9), cmap='plasma') # Plasma for threshold mask if b64: msg = {"timestamp": {"sec": ts_sec, "nsec": ts_nsec}, "frame_id": "ego_vehicle", "format": "png", "data": b64} writer.add_message(metrology_channels[r_type]["cfar"], log_time=ts_ns, data=json.dumps(msg).encode(), publish_time=ts_ns)