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
| import numpy as np from scipy import signal
class UWBCPDValidator: """ UWB雷达儿童检测验证器 基于needCode电子书Channel Impulse Response (CIR)分析 """ def __init__(self, fs: int = 100, chirp_duration: float = 0.01): """ Args: fs: 采样率(Hz),典型值100Hz chirp_duration: Chirp周期(s),UWB典型值10ms """ self.fs = fs self.chirp_duration = chirp_duration self.breathing_band = (0.2, 0.6) def extract_vital_signs(self, cir_data: np.ndarray) -> dict: """ 从CIR数据提取生命体征 Args: cir_data: Channel Impulse Response, shape=(N_samples, N_antennas) Returns: dict: { 'breathing_rate': 呼吸频率(Hz), 'presence_detected': 是否检测到存在, 'confidence': 检测置信度 } """ phase = np.angle(cir_data) phase_unwrap = np.unwrap(phase, axis=0) b, a = signal.butter(4, self.breathing_band, btype='band', fs=self.fs) breathing_signal = signal.filtfilt(b, a, phase_unwrap, axis=0) fft_result = np.fft.fft(breathing_signal, axis=0) freqs = np.fft.fftfreq(len(breathing_signal), 1/self.fs) positive_freqs = freqs[freqs > 0] breathing_band_idx = (positive_freqs >= self.breathing_band[0]) & \ (positive_freqs <= self.breathing_band[1]) breathing_spectrum = np.abs(fft_result[1:len(positive_freqs)+1]) breathing_spectrum_band = breathing_spectrum[breathing_band_idx] if len(breathing_spectrum_band) > 0: peak_idx = np.argmax(breathing_spectrum_band) breathing_rate = positive_freqs[breathing_band_idx][peak_idx] confidence = breathing_spectrum_band[peak_idx] / np.mean(breathing_spectrum_band) presence_detected = confidence > 3.0 else: breathing_rate = 0 confidence = 0 presence_detected = False return { 'breathing_rate': breathing_rate, 'presence_detected': presence_detected, 'confidence': confidence } def estimate_range_resolution(self, bandwidth_hz: float = 500e6) -> float: """ 估算距离分辨率 Args: bandwidth_hz: UWB带宽(Hz),needCode典型值500MHz Returns: range_resolution_m: 距离分辨率(米) Formula: range_resolution = c / (2 * B) c = 光速 = 3e8 m/s """ c = 3e8 range_resolution = c / (2 * bandwidth_hz) return range_resolution def test_occluded_child_detection(self): """ 测试遮挡儿童检测能力 needCode电子书关键结论: - UWB可穿透座椅+毛毯检测呼吸微动 - 60GHz FMCW被阻挡 """ N_samples = 1000 N_antennas = 4 t = np.arange(N_samples) / self.fs breathing_signal_clean = np.sin(2 * np.pi * 0.33 * t) cir_clean = np.exp(1j * breathing_signal_clean) attenuation_factor = 0.4 breathing_signal_occluded = attenuation_factor * np.sin(2 * np.pi * 0.33 * t) cir_occluded = np.exp(1j * breathing_signal_occluded) result_clean = self.extract_vital_signs(cir_clean.reshape(-1, 1)) result_occluded = self.extract_vital_signs(cir_occluded.reshape(-1, 1)) print("="*60) print("UWB雷达儿童检测精度验证") print("="*60) print(f"距离分辨率: {self.estimate_range_resolution()*100:.1f} cm") print(f"\n场景1 - 无遮挡:") print(f" 呼吸频率: {result_clean['breathing_rate']:.3f} Hz ({result_clean['breathing_rate']*60:.1f} 次/分)") print(f" 检测结果: {'✅ 检测到' if result_clean['presence_detected'] else '❌ 未检测到'}") print(f" 置信度: {result_clean['confidence']:.2f}") print(f"\n场景2 - 毛毯遮挡:") print(f" 呼吸频率: {result_occluded['breathing_rate']:.3f} Hz ({result_occluded['breathing_rate']*60:.1f} 次/分)") print(f" 检测结果: {'✅ 检测到' if result_occluded['presence_detected'] else '❌ 未检测到'}") print(f" 置信度: {result_occluded['confidence']:.2f}") print(f"\n结论: UWB在{attenuation_factor*100:.0f}%衰减下仍可检测呼吸")
if __name__ == "__main__": validator = UWBCPDValidator(fs=100) validator.test_occluded_child_detection()
|