From cb91df196008c2f55ed7d9a0a39a441453b04830 Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Wed, 22 Apr 2026 08:50:06 +0530 Subject: [PATCH] feat(radar): optimize target detection and implement peak grouping - physics: increased metal roughness in Sceneset.py to 1.5mm for better diffuse scattering - cfar: widened guard cells to 5x5 in config.yaml to isolate clutter; threshold kept at 20dB - signal-processing: implemented 3x3 local maximum filter (NMS) in radar_processor.py to eliminate sidelobes - config: enabled peak_grouping toggle in config.yaml --- .../shenron/Sceneset.py | 2 +- scripts/ISOLATE/sim_radar_utils/config.yaml | 5 +++-- .../sim_radar_utils/radar_processor.py | 21 +++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/ISOLATE/e2e_agent_sem_lidar2shenron_package/shenron/Sceneset.py b/scripts/ISOLATE/e2e_agent_sem_lidar2shenron_package/shenron/Sceneset.py index 628d89f..8f5c0ff 100644 --- a/scripts/ISOLATE/e2e_agent_sem_lidar2shenron_package/shenron/Sceneset.py +++ b/scripts/ISOLATE/e2e_agent_sem_lidar2shenron_package/shenron/Sceneset.py @@ -401,7 +401,7 @@ def get_loss_3(points, rho, az_boresight, elev_angle, angles, radar, use_spec = wood_roughness = 0.0017 #1.7mm conc_roughness = 0.0017 #1.7mm human_roughness = 0.01 # 100um - metal_roughness = 0.00005 # 100um + metal_roughness = 0.0015 # 1.5mm (Increased from 0.05mm to ensure diffuse scattering when angled/crashed) roughness = np.array([unlabel_roughness,wood_roughness,conc_roughness,human_roughness,metal_roughness]) diff --git a/scripts/ISOLATE/sim_radar_utils/config.yaml b/scripts/ISOLATE/sim_radar_utils/config.yaml index a2d1468..09a9bdf 100644 --- a/scripts/ISOLATE/sim_radar_utils/config.yaml +++ b/scripts/ISOLATE/sim_radar_utils/config.yaml @@ -49,8 +49,9 @@ ROS: timeStamp: '/time_stamp.npy' CFAR: - win_param: [9, 9, 3, 3] - threshold: 20 + win_param: [9, 9, 5, 5] # [Est. width, Est. height, Guard width, Guard height] - Widened guard to 11x11 to isolate nearby clutter + threshold: 20 # dB (Standard) - Reverted to 20dB as per user request to maintain baseline sensitivity + peak_grouping: true # Toggle Non-Maximum Suppression (NMS) to eliminate range/doppler sidelobes Visualize: diff --git a/scripts/ISOLATE/sim_radar_utils/radar_processor.py b/scripts/ISOLATE/sim_radar_utils/radar_processor.py index 47a0682..9f96c64 100644 --- a/scripts/ISOLATE/sim_radar_utils/radar_processor.py +++ b/scripts/ISOLATE/sim_radar_utils/radar_processor.py @@ -70,6 +70,27 @@ class RadarProcessor: # detect useful peaks using CFAR (NOW RETURNING THRESHOLD BASELINE) hit_matrix, threshold_matrix = self.cfar(rd_heatmap) + # 2.5 Optional Peak Grouping (Non-Maximum Suppression) + # Algorithm: 3x3 Local Maximum Filter + # ----------------------------------- + # This step prunes "ghost" detections by ensuring each hit is the strongest cell + # in its immediate neighborhood. In high-SNR scenarios (like metal poles), + # range/doppler sidelobes (the 'sinc' pattern) often cross the CFAR threshold, + # creating a trail of points. Peak grouping ensures only the true target centroid is kept. + if cfarCfg.get('peak_grouping', False): + # Pad the heatmap to allow comparison at the edges of the RD map + padded_rd = np.pad(rd_heatmap, 1, mode='constant', constant_values=0) + + # Compare current cell against its 4 immediate neighbors (Shifted arrays) + # Logic: is_local_max = (current >= up) & (current >= down) & (current >= left) & (current >= right) + is_local_max = (rd_heatmap >= padded_rd[0:-2, 1:-1]) & \ + (rd_heatmap >= padded_rd[2:, 1:-1]) & \ + (rd_heatmap >= padded_rd[1:-1, 0:-2]) & \ + (rd_heatmap >= padded_rd[1:-1, 2:]) + + # Combine the CFAR mask with the Local Maximum mask + hit_matrix = hit_matrix & is_local_max + # 3. Global Range-Azimuth Heatmap — Doppler-Slice Accumulation # Loop over every Doppler bin, apply a windowed Angle-FFT per slice, # and incoherently sum the power. This preserves angular diversity from