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
| import numpy as np from typing import Dict, Optional, List
class MultimodalHeartbeatFusion: """ 多模态心跳检测融合器 5种模态:ECG, PPG, iPPG-RGB, iPPG-IR, iPPG-Thermal 每种模态独立评估信号质量,选择最佳模态或加权融合 """ MODALITIES = ['ecg', 'ppg', 'ippg_rgb', 'ippg_ir', 'ippg_thermal'] def __init__(self): self.signal_quality = {m: 0.0 for m in self.MODALITIES} self.heart_rates = {m: None for m in self.MODALITIES} def assess_quality(self, modality: str, signal: np.ndarray) -> float: """ 评估各模态信号质量 Returns: quality_score: 0-1 """ if signal is None or len(signal) == 0: return 0.0 fft = np.fft.rfft(signal) power = np.abs(fft) ** 2 freqs = np.fft.rfftfreq(len(signal), d=1/500) heart_mask = (freqs >= 0.8) & (freqs <= 3.0) heart_power = np.sum(power[heart_mask]) total_power = np.sum(power) + 1e-10 snr = heart_power / total_power motion_artifact = np.std(np.diff(signal)) / (np.std(signal) + 1e-10) if modality == 'ecg': quality = snr * (1 / (1 + motion_artifact * 0.5)) elif modality in ['ppg']: quality = snr * 0.9 elif modality in ['ippg_rgb', 'ippg_ir']: quality = snr * 0.7 elif modality == 'ippg_thermal': quality = snr * 0.6 return min(quality, 1.0) def fuse(self, signals: Dict[str, np.ndarray]) -> dict: """ 多模态融合 策略: 1. 如果最佳模态质量>0.7,直接使用 2. 否则加权融合前2-3个模态 3. 如果所有模态质量<0.3,标记为不可靠 """ for m in self.MODALITIES: if m in signals and signals[m] is not None: self.signal_quality[m] = self.assess_quality(m, signals[m]) self.heart_rates[m] = self._extract_hr(signals[m]) sorted_mods = sorted( self.MODALITIES, key=lambda m: self.signal_quality[m], reverse=True ) best = sorted_mods[0] best_quality = self.signal_quality[best] if best_quality > 0.7: strategy = 'best_single' fused_hr = self.heart_rates[best] confidence = best_quality elif best_quality > 0.3: top3 = [m for m in sorted_mods if self.signal_quality[m] > 0.3][:3] weights = np.array([self.signal_quality[m] for m in top3]) weights /= weights.sum() hrs = np.array([self.heart_rates[m] for m in top3 if self.heart_rates[m] is not None]) if len(hrs) > 0: fused_hr = np.average(hrs, weights=weights[:len(hrs)]) else: fused_hr = None strategy = 'weighted_fusion' confidence = best_quality * 0.8 else: strategy = 'unreliable' fused_hr = None confidence = 0.0 return { 'heart_rate': fused_hr, 'confidence': confidence, 'strategy': strategy, 'best_modality': best, 'modality_qualities': {m: self.signal_quality[m] for m in self.MODALITIES if self.signal_quality[m] > 0}, 'all_heart_rates': {m: self.heart_rates[m] for m in self.MODALITIES if self.heart_rates[m] is not None} } def _extract_hr(self, signal: np.ndarray) -> Optional[float]: """从信号中提取心率""" if signal is None or len(signal) < 100: return None fft = np.fft.rfft(signal) freqs = np.fft.rfftfreq(len(signal), d=1/500) heart_mask = (freqs >= 0.8) & (freqs <= 3.0) if np.any(heart_mask): peak_idx = np.argmax(np.abs(fft[heart_mask])) peak_freq = freqs[heart_mask][peak_idx] return peak_freq * 60 return None
if __name__ == "__main__": fusion = MultimodalHeartbeatFusion() t = np.arange(0, 10, 1/500) ecg = np.sin(2*np.pi*1.2*t) + 0.1*np.random.randn(len(t)) ppg = np.sin(2*np.pi*1.2*t) + 0.3*np.random.randn(len(t)) ippg_rgb = np.sin(2*np.pi*1.2*t) + 0.5*np.random.randn(len(t)) ippg_ir = np.sin(2*np.pi*1.2*t) + 0.4*np.random.randn(len(t)) thermal = np.sin(2*np.pi*1.2*t) + 0.8*np.random.randn(len(t)) result = fusion.fuse({ 'ecg': ecg, 'ppg': ppg, 'ippg_rgb': ippg_rgb, 'ippg_ir': ippg_ir, 'ippg_thermal': thermal, }) print("多模态心跳融合结果") print("=" * 50) print(f"融合心率: {result['heart_rate']:.1f} BPM" if result['heart_rate'] else "不可靠") print(f"置信度: {result['confidence']:.2f}") print(f"策略: {result['strategy']}") print(f"最佳模态: {result['best_modality']}") print(f"\n各模态质量:") for m, q in result['modality_qualities'].items(): print(f" {m:15s}: {q:.3f}") print("\n✅ 多模态融合测试通过")
|