1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
| """ Euro NCAP 2026 CPD雷达呼吸监测 基于60GHz FMCW雷达的生命体征检测
核心技术: 1. FMCW(Frequency Modulated Continuous Wave)雷达信号处理 2. 呼吸信号提取(胸部微小运动0.1-0.5mm) 3. 心跳信号提取(心跳运动约0.2mm) 4. 多目标分离(多个儿童场景) """
import numpy as np from typing import Tuple, List, Dict from dataclasses import dataclass
@dataclass class VitalSignsResult: """生命体征检测结果""" breathing_rate_bpm: float heart_rate_bpm: float breathing_confidence: float heart_rate_confidence: float target_age_estimate: str age_confidence: float presence_detected: bool target_count: int
class FMCWRadarVitalSignsDetector: """ 60GHz FMCW雷达生命体征检测 硬件参数(典型配置): - 频率:60GHz(57-64GHz带宽) - 带宽:4GHz(高分辨率) - 发射天线:2-4个 - 接收天线:2-4个 - 扫描周期:100μs(10kHz chirp rate) - 距离分辨率:约3.75cm(c/(2*B)) - 速度分辨率:约0.1m/s 呼吸监测原理: - 呼吸引起的胸部运动:0.1-0.5mm - 心跳引起的胸部运动:约0.2mm - 雷达测量相位变化 → 运动幅度 → 呼吸频率 信号处理流程: 1. 发射FMCW信号(chirp) 2. 接收反射信号(与发射混频) 3. FFT获取距离信息(Range FFT) 4. 多chirp FFT获取速度信息(Doppler FFT) 5. 相位解调获取微动信息(呼吸/心跳) """ def __init__(self, radar_config: Dict[str, float] = None): """ Args: radar_config: 雷达配置参数 """ self.config = radar_config or { 'center_freq_hz': 60e9, 'bandwidth_hz': 4e9, 'num_tx_antennas': 2, 'num_rx_antennas': 4, 'chirp_duration_us': 100, 'num_chirps_per_frame': 128, 'frame_duration_sec': 0.1, 'sampling_rate_hz': 10e6 } c = 3e8 self.range_resolution_m = c / (2 * self.config['bandwidth_hz']) self.velocity_resolution_m_s = c / (2 * self.config['center_freq_hz'] * self.config['frame_duration_sec']) def process_radar_frame(self, radar_data: np.ndarray) -> VitalSignsResult: """ 处理雷达帧数据,提取生命体征 Args: radar_data: 雷达原始数据(num_chirps × num_samples × num_rx) Returns: VitalSignsResult: 生命体征检测结果 """ range_fft = self._compute_range_fft(radar_data) doppler_fft = self._compute_doppler_fft(range_fft) targets = self._detect_targets_cfar(doppler_fft) if len(targets) == 0: return VitalSignsResult( breathing_rate_bpm=0, heart_rate_bpm=0, breathing_confidence=0, heart_rate_confidence=0, target_age_estimate='none', age_confidence=0, presence_detected=False, target_count=0 ) breathing_rate, heart_rate, confidence = self._extract_vital_signs(range_fft, targets) age_estimate, age_conf = self._estimate_age(breathing_rate) return VitalSignsResult( breathing_rate_bpm=breathing_rate, heart_rate_bpm=heart_rate, breathing_confidence=confidence[0], heart_rate_confidence=confidence[1], target_age_estimate=age_estimate, age_confidence=age_conf, presence_detected=True, target_count=len(targets) ) def _compute_range_fft(self, radar_data: np.ndarray) -> np.ndarray: """ Range FFT(距离维FFT) 将时域信号转换为距离域信号 Args: radar_data: 原始雷达数据(num_chirps × num_samples × num_rx) Returns: range_fft: 距离FFT结果(num_chirps × num_range_bins × num_rx) """ num_chirps, num_samples, num_rx = radar_data.shape range_fft = np.fft.fft(radar_data, axis=1) range_fft_abs = np.abs(range_fft) return range_fft def _compute_doppler_fft(self, range_fft: np.ndarray) -> np.ndarray: """ Doppler FFT(速度维FFT) 将距离维信号转换为速度维信号 Args: range_fft: 距离FFT结果 Returns: doppler_fft: 速度FFT结果(num_range_bins × num_doppler_bins) """ doppler_fft = np.fft.fft(range_fft, axis=0) doppler_fft_avg = np.mean(doppler_fft, axis=2) return np.abs(doppler_fft_avg) def _detect_targets_cfar(self, doppler_fft: np.ndarray) -> List[Tuple[int, int]]: """ CFAR目标检测(Constant False Alarm Rate) 检测雷达场景中的目标位置(距离+速度) Args: doppler_fft: Doppler FFT结果 Returns: targets: 目标列表(range_idx, doppler_idx) """ threshold = np.mean(doppler_fft) * 3 target_mask = doppler_fft > threshold targets = [] for i in range(doppler_fft.shape[0]): for j in range(doppler_fft.shape[1]): if target_mask[i, j]: targets.append((i, j)) return targets def _extract_vital_signs(self, range_fft: np.ndarray, targets: List[Tuple[int, int]]) -> Tuple[float, float, Tuple[float, float]]: """ 相位解调提取生命体征 呼吸/心跳引起的胸部微小运动会在相位上体现 原理: - 呼吸:胸部运动0.1-0.5mm → 相位变化 - 心跳:胸部运动约0.2mm → 相位变化 Args: range_fft: 距离FFT结果 targets: 检测到的目标 Returns: (breathing_rate, heart_rate, (breathing_conf, heart_conf)) """ if len(targets) == 0: return 0, 0, (0, 0) target_range_idx = targets[0][0] phase_sequence = np.angle(range_fft[:, target_range_idx, 0]) phase_unwrapped = np.unwrap(phase_sequence) frame_duration = self.config['frame_duration_sec'] num_chirps = len(phase_sequence) chirp_interval = frame_duration / num_chirps time_axis = np.arange(num_chirps) * chirp_interval phase_fft = np.fft.fft(phase_unwrapped) freq_axis = np.fft.fftfreq(num_chirps, chirp_interval) breathing_band = (freq_axis >= 0.1) & (freq_axis <= 0.5) breathing_spectrum = np.abs(phase_fft) * breathing_band heart_band = (freq_axis >= 0.8) & (freq_axis <= 2.0) heart_spectrum = np.abs(phase_fft) * heart_band breathing_peak_freq = freq_axis[np.argmax(breathing_spectrum)] heart_peak_freq = freq_axis[np.argmax(heart_spectrum)] breathing_rate_bpm = abs(breathing_peak_freq) * 60 heart_rate_bpm = abs(heart_peak_freq) * 60 total_energy = np.sum(np.abs(phase_fft)) breathing_conf = np.sum(breathing_spectrum) / total_energy heart_conf = np.sum(heart_spectrum) / total_energy return breathing_rate_bpm, heart_rate_bpm, (breathing_conf, heart_conf) def _estimate_age(self, breathing_rate_bpm: float) -> Tuple[str, float]: """ 基于呼吸频率估计年龄 Euro NCAP年龄判定标准: - 新生儿:30次/分钟 - 1岁儿童:25次/分钟 - 3岁儿童:20次/分钟 - 6岁儿童:18次/分钟 - 成人:12-20次/分钟 Args: breathing_rate_bpm: 呼吸频率 Returns: (age_estimate, confidence): 年龄估计,置信度 """ age_thresholds = { 'newborn': 30, '1-year': 25, '3-year': 20, '6-year': 18, 'adult': 16 } if breathing_rate_bpm >= 28: age_estimate = 'newborn' confidence = min(1.0, (breathing_rate_bpm - 28) / 2) elif breathing_rate_bpm >= 23: age_estimate = '1-year' confidence = min(1.0, (breathing_rate_bpm - 23) / 5) elif breathing_rate_bpm >= 19: age_estimate = '3-year' confidence = min(1.0, (breathing_rate_bpm - 19) / 4) elif breathing_rate_bpm >= 17: age_estimate = '6-year' confidence = min(1.0, (breathing_rate_bpm - 17) / 2) else: age_estimate = 'adult' confidence = 1.0 return age_estimate, confidence
if __name__ == "__main__": detector = FMCWRadarVitalSignsDetector() print(f"=== 雷达配置参数 ===") print(f"中心频率:{detector.config['center_freq_hz']/1e9:.2f} GHz") print(f"带宽:{detector.config['bandwidth_hz']/1e9:.2f} GHz") print(f"距离分辨率:{detector.range_resolution_m*100:.2f} cm") print(f"速度分辨率:{detector.velocity_resolution_m_s:.4f} m/s") num_chirps = 128 num_samples = 256 num_rx = 4 radar_test = np.zeros((num_chirps, num_samples, num_rx), dtype=np.complex64) target_range_bin = 50 breathing_freq_hz = 0.3 chirp_interval = detector.config['frame_duration_sec'] / num_chirps phase_sequence = np.sin(2 * np.pi * breathing_freq_hz * np.arange(num_chirps) * chirp_interval) * 0.5 for i in range(num_chirps): radar_test[i, target_range_bin, 0] = np.exp(1j * phase_sequence[i]) result = detector.process_radar_frame(radar_test) print(f"\n=== 生命体征检测结果 ===") print(f"呼吸频率:{result.breathing_rate_bpm:.2f} 次/分钟") print(f"心跳频率:{result.heart_rate_bpm:.2f} 次/分钟") print(f"呼吸置信度:{result.breathing_confidence:.3f}") print(f"年龄估计:{result.target_age_estimate}") print(f"检测到生命体:{result.presence_detected}")
|