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
| """ HEAR 论文的 FMCW 多散射体仿真器 生成可控可观测性标签的训练数据 """
import numpy as np from dataclasses import dataclass from typing import List, Tuple
@dataclass class Scatterer: """单个散射体""" range_m: float phase_rad: float amplitude: float has_heartbeat: bool
class FMCWSimulator: """ FMCW 多散射体仿真器 模拟多个散射体的相干叠加 通过控制各散射体的参数生成不同可观测性条件 """ def __init__(self, config: dict): self.center_freq = config.get('center_freq', 60e9) self.bandwidth = config.get('bandwidth', 4e9) self.num_samples = config.get('num_samples', 128) self.sample_rate = config.get('sample_rate', 1e6) self.c = 3e8 def generate_measurement(self, scatterers: List[Scatterer], heart_rate_hz: float, duration_frames: int = 100) -> Tuple[np.ndarray, float]: """ 生成一次测量数据 Args: scatterers: 散射体列表 heart_rate_hz: 真实心率 (Hz) duration_frames: 帧数 Returns: phase_spectrum: 相位谱 (num_frames, num_range_bins) observability_label: 可观测性标签 (0-1) """ c = self.c wavelength = c / self.center_freq range_resolution = c / (2 * self.bandwidth) phase_spectrum = np.zeros((duration_frames, self.num_samples), dtype=complex) for frame_idx in range(duration_frames): t = frame_idx / 20.0 heartbeat_displacement = 0.5e-3 * np.sin(2 * np.pi * heart_rate_hz * t) for scatterer in scatterers: range_bin = int(scatterer.range_m / range_resolution) if range_bin >= self.num_samples: continue if scatterer.has_heartbeat: effective_range = scatterer.range_m + heartbeat_displacement else: effective_range = scatterer.range_m phase = 4 * np.pi * effective_range / wavelength + scatterer.phase_rad phase_spectrum[frame_idx, range_bin] += ( scatterer.amplitude * np.exp(1j * phase) ) heartbeat_bins = [] for i, s in enumerate(scatterers): if s.has_heartbeat: heartbeat_bins.append(int(s.range_m / range_resolution)) if not heartbeat_bins: return phase_spectrum, 0.0 observability_scores = [] for bin_idx in heartbeat_bins: phase_series = np.unwrap(np.angle(phase_spectrum[:, bin_idx])) phase_series = phase_series - np.mean(phase_series) spectrum = np.abs(np.fft.fft(phase_series)) freqs = np.fft.fftfreq(len(phase_series), d=1/20) hr_idx = np.argmin(np.abs(freqs - heart_rate_hz)) peak_power = spectrum[hr_idx] total_power = np.sum(spectrum) + 1e-10 observability_scores.append(peak_power / total_power) observability = np.mean(observability_scores) observability = min(observability / 0.1, 1.0) return phase_spectrum, observability
if __name__ == "__main__": sim = FMCWSimulator({ 'center_freq': 60e9, 'bandwidth': 4e9, 'num_samples': 128, 'sample_rate': 1e6 }) scatterers_good = [ Scatterer(range_m=0.5, phase_rad=0, amplitude=1.0, has_heartbeat=True), Scatterer(range_m=0.5, phase_rad=0.5, amplitude=0.1, has_heartbeat=False), ] spec, obs = sim.generate_measurement(scatterers_good, heart_rate_hz=1.2, duration_frames=100) print(f"高可观测性场景: obs={obs:.3f}") scatterers_bad = [ Scatterer(range_m=0.5, phase_rad=0, amplitude=0.3, has_heartbeat=True), Scatterer(range_m=0.5, phase_rad=2.0, amplitude=0.8, has_heartbeat=False), Scatterer(range_m=0.51, phase_rad=1.5, amplitude=0.7, has_heartbeat=False), ] spec, obs = sim.generate_measurement(scatterers_bad, heart_rate_hz=1.2, duration_frames=100) print(f"低可观测性场景: obs={obs:.3f}")
|