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
| """ RT-VSS: FR3频段生命体征射线追踪仿真 论文: arXiv 2609.15310, KU Leuven
工具链: Blender 4.2LTS → Sionna RT → 信号处理
依赖: numpy, scipy, matplotlib """
import numpy as np from scipy.signal import butter, filtfilt, find_peaks
class RTVitalSignsSimulator: """ RT-VSS 生命体征仿真框架 1. Blender建模: 室内场景 + 人体网格 2. 胸壁运动动画: 呼吸(抛物线) + 心跳(正弦) 3. Sionna RT: 射线追踪信道仿真 4. 信号处理: 相位提取 → 呼吸/心跳分离 """ def __init__(self): self.breath_rate = 6 self.heart_rate = 75 self.breath_max = 0.004 self.heart_max = 0.0003 self.duration = 60 self.fps = 24 self.n_frames = self.duration * self.fps self.bands = { 'FR1': {'fc': 6e9, 'bw': 100e6, 'label': 'sub-6 GHz'}, 'FR3_low': {'fc': 7e9, 'bw': 400e6, 'label': 'FR3 low'}, 'FR3_mid': {'fc': 12e9, 'bw': 400e6, 'label': 'FR3 mid'}, 'FR3_high': {'fc': 24e9, 'bw': 400e6, 'label': 'FR3 high'}, 'FR2': {'fc': 28e9, 'bw': 400e6, 'label': 'mmWave'}, } def generate_chest_motion(self, t: np.ndarray) -> dict: """ 生成胸壁运动信号 (论文Eq.2-5) 呼吸: 抛物线吸气 + 指数衰减呼气 心跳: 正弦波 Returns: dict with 'breath', 'heart', 'total' """ breath_hz = self.breath_rate / 60 heart_hz = self.heart_rate / 60 breath_period = 1 / breath_hz t_in_cycle = t % breath_period t_inhale = breath_period * 0.4 t_exhale = breath_period * 0.6 breath = np.zeros_like(t) for i, ti in enumerate(t_in_cycle): if ti < t_inhale: breath[i] = self.breath_max * ( -ti**2 / (t_inhale * t_exhale) + ti / (t_inhale * t_exhale * breath_hz) ) else: tau = 0.5 te = t_exhale ti_e = ti - t_inhale breath[i] = (self.breath_max / (1 - np.exp(-te/tau))) * \ (np.exp(-ti_e/tau) - np.exp(-te/tau)) heart = self.heart_max * np.sin(2 * np.pi * heart_hz * t) + self.heart_max total = breath + heart return {'breath': breath, 'heart': heart, 'total': total} def simulate_radar_phase(self, chest_motion, fc): """ 模拟雷达接收信号相位变化 相位 = 4π(d + chest_motion) / λ FR3优势: 波长cm级,对mm级胸壁运动敏感 """ wavelength = 3e8 / fc base_distance = 1.0 phase = 4 * np.pi * (base_distance + chest_motion) / wavelength multipath = (0.3 * np.sin(2*np.pi*0.3*np.arange(len(chest_motion))/len(chest_motion)) + 0.1 * np.random.randn(len(chest_motion))) phase += multipath * 2 * np.pi / wavelength return phase def extract_vital_signs(self, phase_signal, fs=24): """ 从相位信号提取呼吸和心率 信号处理流程: 1. 相位解包裹 2. 去趋势 3. 带通滤波: 呼吸(0.05-0.5Hz) + 心跳(0.8-2.0Hz) 4. 频谱分析: FFT峰值检测 """ unwrapped = np.unwrap(phase_signal) from scipy.signal import detrend detrended = detrend(unwrapped) b_breath, a_breath = butter(4, [0.05, 0.5], btype='band', fs=fs) breath_signal = filtfilt(b_breath, a_breath, detrended) b_heart, a_heart = butter(4, [0.8, 2.0], btype='band', fs=fs) heart_signal = filtfilt(b_heart, a_heart, detrended) n = len(breath_signal) freq = np.fft.rfftfreq(n, 1/fs) breath_spectrum = np.abs(np.fft.rfft(breath_signal)) heart_spectrum = np.abs(np.fft.rfft(heart_signal)) breath_mask = (freq >= 0.05) & (freq <= 0.5) heart_mask = (freq >= 0.8) & (freq <= 2.0) breath_peak = freq[breath_mask][np.argmax(breath_spectrum[breath_mask])] heart_peak = freq[heart_mask][np.argmax(heart_spectrum[heart_mask])] return { 'breath_rate_bpm': breath_peak * 60, 'heart_rate_bpm': heart_peak * 60, 'breath_signal': breath_signal, 'heart_signal': heart_signal, 'breath_spectrum': breath_spectrum, 'heart_spectrum': heart_spectrum, 'freq': freq, }
if __name__ == "__main__": sim = RTVitalSignsSimulator() print("=" * 60) print("RT-VSS: FR3频段生命体征感知仿真") print("=" * 60) t = np.linspace(0, sim.duration, sim.n_frames) motion = sim.generate_chest_motion(t) print(f"\n胸壁运动参数:") print(f" 呼吸率: {sim.breath_rate} BPM ({sim.breath_rate/60:.2f} Hz)") print(f" 心率: {sim.heart_rate} BPM ({sim.heart_rate/60:.2f} Hz)") print(f" 呼吸位移: {sim.breath_max*1000:.1f}mm") print(f" 心跳位移: {sim.heart_max*1000:.1f}mm") print(f" 仿真时长: {sim.duration}s, {sim.n_frames}帧") print(f"\n{'频段':<12} {'频率':<10} {'波长':<10} {'呼吸误差':<12} {'心跳误差':<12}") print("-" * 60) for band_name, band in sim.bands.items(): fc = band['fc'] wavelength = 3e8 / fc phase = sim.simulate_radar_phase(motion['total'], fc) result = sim.extract_vital_signs(phase, fs=sim.fps) breath_error = abs(result['breath_rate_bpm'] - sim.breath_rate) heart_error = abs(result['heart_rate_bpm'] - sim.heart_rate) print(f"{band_name:<12} {fc/1e9:.0f}GHz {wavelength*1000:.1f}mm " f"{breath_error:.2f} BPM {heart_error:.2f} BPM") print(f"\n{'='*60}") print(f"FR3频段优势分析:") print(f" 1. 波长cm级 → 对mm级胸壁运动高灵敏度") print(f" 2. 7-24GHz → 比FR2(mmWave)穿透性更好") print(f" 3. 丰富带宽 → 400MHz BW,高距离分辨率") print(f" 4. 多径友好 → 座舱多径环境可增强感知") print(f" 5. ISAC潜力 → 通信+感知共享频谱和硬件")
|