@@ -108,16 +108,23 @@ def process_block(self, block: IQBlock) -> Optional[SpeedReading]:
108108
109109 half = cfg .fft_size // 2
110110 dc_mask = cfg .cfar .dc_mask_bins
111+ nyquist_mask = cfg .cfar .nyquist_mask_bins
111112
112- # Analyze positive frequencies (outbound) above DC mask
113- pos_region = magnitude [dc_mask :half ]
113+ # Valid frequency ranges (excluding DC and Nyquist edges)
114+ # Positive frequencies: dc_mask to (half - nyquist_mask)
115+ # Negative frequencies: (half + nyquist_mask) to (fft_size - dc_mask)
116+ pos_end = half - nyquist_mask
117+ neg_start = half + nyquist_mask
118+ neg_end = cfg .fft_size - dc_mask
119+
120+ # Analyze positive frequencies (outbound) - excludes DC and Nyquist
121+ pos_region = magnitude [dc_mask :pos_end ]
114122 pos_peak_idx = np .argmax (pos_region )
115123 pos_peak_bin = pos_peak_idx + dc_mask
116124 pos_peak_mag = magnitude [pos_peak_bin ]
117125
118- # Analyze negative frequencies (inbound) above DC mask
119- neg_start = half + dc_mask
120- neg_region = magnitude [neg_start :]
126+ # Analyze negative frequencies (inbound) - excludes DC and Nyquist
127+ neg_region = magnitude [neg_start :neg_end ]
121128 neg_peak_idx = np .argmax (neg_region )
122129 neg_peak_bin = neg_peak_idx + neg_start
123130 neg_peak_mag = magnitude [neg_peak_bin ]
@@ -153,6 +160,13 @@ def process_block(self, block: IQBlock) -> Optional[SpeedReading]:
153160 if snr < snr_threshold :
154161 return None # Signal not strong enough
155162
163+ # Minimum magnitude filter (rejects low-energy edge artifacts)
164+ min_mag = cfg .cfar .min_magnitude
165+ if peak_mag < min_mag :
166+ if self .debug :
167+ print (f" [LOW-MAG] mag={ peak_mag :.4f} < { min_mag } speed={ speed_mph :.1f} mph" )
168+ return None
169+
156170 # Speed filter
157171 if not (cfg .min_speed_mph <= speed_mph <= cfg .max_speed_mph ):
158172 if self .debug :
0 commit comments