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
| """ UWB CPD 检测算法框架 基于 Calterah Dubhe 芯片的 UWB 信号处理 """
import numpy as np from scipy.signal import find_peaks, butter, filtfilt
class UWBCPDDetector: """ UWB 儿童遗留检测器 工作原理: 1. 利用 UWB 脉冲雷达的测距能力 2. 在座舱内建立距离-时间图 3. 检测静止目标的微动(呼吸) 4. 通过 RCS/距离判断是否为儿童 """ def __init__(self, config: dict): self.sample_rate = config.get('sample_rate', 1e9) self.bandwidth = config.get('bandwidth', 500e6) self.num_samples = config.get('num_samples', 256) self.frame_rate = config.get('frame_rate', 10) self.range_resolution = 3e8 / (2 * self.bandwidth) self.max_range = self.num_samples * self.range_resolution / 2 self.breath_min = 0.1 self.breath_max = 0.5 def range_profile(self, rx_signal: np.ndarray) -> np.ndarray: """ 从接收信号提取距离剖面 Args: rx_signal: UWB 接收信号, shape=(num_samples,) Returns: range_mag: 距离剖面幅度 """ range_fft = np.fft.fft(rx_signal) range_mag = np.abs(range_fft) return range_mag def detect_presence(self, range_profiles: np.ndarray, threshold: float = 1e3) -> list: """ 从多帧距离剖面检测目标 Args: range_profiles: shape=(num_frames, num_samples) Returns: detections: [(range_bin, range_m)] """ avg_profile = np.mean(range_profiles, axis=0) peaks, _ = find_peaks(avg_profile, height=threshold) detections = [] for peak in peaks: range_m = peak * self.range_resolution if 0.2 < range_m < 3.0: detections.append((peak, range_m)) return detections def detect_micro_motion(self, range_profiles: np.ndarray, range_bin: int) -> dict: """ 在指定距离单元检测微动(呼吸) Args: range_profiles: shape=(num_frames, num_samples) range_bin: 目标距离单元 Returns: {'has_breathing': bool, 'breath_rate': float} """ phase_series = np.angle( np.fft.fft(range_profiles, axis=1)[:, range_bin] ) phase_series = np.unwrap(phase_series) phase_series = phase_series - np.mean(phase_series) nyq = self.frame_rate / 2 b, a = butter(4, [self.breath_min/nyq, self.breath_max/nyq], btype='band') breath_signal = filtfilt(b, a, phase_series) spectrum = np.abs(np.fft.fft(breath_signal)) freqs = np.fft.fftfreq(len(breath_signal), 1/self.frame_rate) pos_mask = freqs > 0 breath_mask = (freqs[pos_mask] >= self.breath_min) & \ (freqs[pos_mask] <= self.breath_max) if np.any(breath_mask): peak_idx = np.argmax(spectrum[pos_mask][breath_mask]) breath_freq = freqs[pos_mask][breath_mask][peak_idx] breath_rate = breath_freq * 60 return {'has_breathing': True, 'breath_rate': breath_rate} return {'has_breathing': False, 'breath_rate': 0.0} def classify_target(self, range_m: float, breath_rate: float, rcs_estimate: float) -> str: """ 分类目标类型 Returns: 'child' | 'adult' | 'pet' | 'object' | 'unknown' """ if breath_rate == 0: return 'object' if 0.5 <= breath_rate <= 1.0: return 'child' elif 0.33 <= breath_rate < 0.5: if rcs_estimate < 0.01: return 'child' return 'adult' elif 0.2 <= breath_rate < 0.33: return 'adult' else: return 'unknown'
if __name__ == "__main__": detector = UWBCPDDetector({ 'sample_rate': 1e9, 'bandwidth': 500e6, 'num_samples': 256, 'frame_rate': 10 }) print(f"距离分辨率: {detector.range_resolution*100:.1f} cm") print(f"最大距离: {detector.max_range:.1f} m") np.random.seed(42) profiles = np.random.randn(100, 256) * 0.1 + 0.5 for i in range(100): profiles[i, 50] += np.sin(2 * np.pi * 0.3 * i / 10) dets = detector.detect_presence(profiles) for bin_idx, range_m in dets: motion = detector.detect_micro_motion(profiles, bin_idx) if motion['has_breathing']: target = detector.classify_target( range_m, motion['breath_rate'], 0.005 ) print(f"目标: 距离={range_m:.2f}m, " f"呼吸={motion['breath_rate']:.1f}次/分, " f"类型={target}")
|