雷达心率估计:呼吸谐波干扰消除新方法——非接触生命体征监测的最后一公里

论文来源:Sensors 期刊, 2026年9月3日
核心创新:呼吸谐波干扰消除方法
关键应用:mmWave 雷达非接触心率监测
IMS 相关性:⭐⭐⭐⭐(座舱非接触生理监测)


论文信息

项目 内容
标题 Radar-Based Heart Rate Estimation Method Under Respiratory Harmonic Interference
期刊 Sensors, 26(17), 5587
发表日期 2026年9月3日
DOI 10.3390/s26175587
栏目 Radar Sensors
链接 https://www.mdpi.com/1424-8220/26/17/5587
应用 医疗/养老/车载非接触监测

核心问题

呼吸干扰心率估计

mmWave 雷达通过检测胸壁微小运动来估计心率和呼吸频率。但呼吸信号的谐波会与心跳信号重叠,导致心率估计错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
mmWave 雷达心率估计的呼吸谐波干扰问题

问题本质:
- 呼吸频率:12-20 次/分(0.2-0.33 Hz)
- 心率:60-100 次/分(1.0-1.67 Hz)
- 呼吸二次谐波:0.4-0.66 Hz ← 可能与心率重叠!
- 呼吸三次谐波:0.6-1.0 Hz ← 与心率直接重叠!

当呼吸谐波频率与心率接近时,传统频谱方法无法区分

解决方案:
1. 自适应滤波:估计呼吸信号 → 生成谐波 → 消除
2. 盲源分离:将混合信号分解为独立成分
3. 相位追踪:利用雷达相位信息区分呼吸和心跳
"""

方法架构

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
"""
雷达心率估计系统 - 呼吸谐波干扰消除

基于 Sensors 2026 论文的方法架构
适配到 IMS 座舱场景
"""

import numpy as np
from scipy.signal import butter, filtfilt, find_peaks
from scipy.fft import fft, fftfreq

class RadarHeartRateEstimator:
"""
mmWave 雷达心率估计器

处理流程:
1. 雷达相位提取 → 胸壁位移信号
2. 带通滤波 → 分离呼吸和心跳
3. 呼吸谐波检测 → 识别干扰频率
4. 自适应消除 → 去除谐波干扰
5. 心率估计 → 最终心率输出
"""

def __init__(self, sample_rate: float = 50.0):
self.fs = sample_rate # Hz

# 呼吸频段:0.1-0.5 Hz (6-30 breaths/min)
self.resp_band = (0.1, 0.5)

# 心率频段:0.8-3.0 Hz (48-180 bpm)
self.heart_band = (0.8, 3.0)

def process(self, radar_phase: np.ndarray) -> dict:
"""
处理雷达相位信号

Args:
radar_phase: (N,) 雷达相位信号(已解卷绕)

Returns:
dict with 'heart_rate', 'resp_rate', 'quality'
"""
# 1. 去趋势
signal = radar_phase - np.mean(radar_phase)

# 2. 分离呼吸信号
resp_signal = self._bandpass(signal, self.resp_band)

# 3. 分离心跳信号(含呼吸谐波干扰)
heart_signal_raw = self._bandpass(signal, self.heart_band)

# 4. 估计呼吸频率
resp_freq = self._dominant_freq(resp_signal)

# 5. 生成呼吸谐波
harmonics = self._generate_harmonics(resp_freq, len(signal))

# 6. 自适应消除
heart_signal_clean = self._adaptive_cancel(
heart_signal_raw, harmonics
)

# 7. 估计心率
heart_rate = self._dominant_freq(heart_signal_clean) * 60

# 8. 质量评估
snr = self._compute_snr(heart_signal_clean)
quality = 'good' if snr > 3 else 'poor'

return {
'heart_rate': heart_rate,
'resp_rate': resp_freq * 60,
'snr': snr,
'quality': quality,
'heart_signal': heart_signal_clean,
}

def _bandpass(self, signal: np.ndarray, band: tuple) -> np.ndarray:
"""带通滤波"""
b, a = butter(4, [band[0]/(self.fs/2), band[1]/(self.fs/2)],
btype='band')
return filtfilt(b, a, signal)

def _dominant_freq(self, signal: np.ndarray) -> float:
"""找到主频"""
N = len(signal)
spectrum = np.abs(fft(signal))
freqs = fftfreq(N, 1/self.fs)
# 只取正频率
pos_mask = freqs > 0
return freqs[pos_mask][np.argmax(spectrum[pos_mask])]

def _generate_harmonics(self, base_freq: float, length: int) -> dict:
"""生成呼吸谐波"""
t = np.arange(length) / self.fs
harmonics = {}
for n in [2, 3, 4, 5]:
freq = base_freq * n
if 0.8 <= freq <= 3.0: # 在心率频段内
harmonics[f'harmonic_{n}'] = np.sin(2 * np.pi * freq * t)
return harmonics

def _adaptive_cancel(self, signal: np.ndarray,
harmonics: dict) -> np.ndarray:
"""自适应谐波消除"""
if not harmonics:
return signal

# 构建谐波矩阵
harmonic_matrix = np.array(list(harmonics.values())).T
# 最小二乘自适应滤波
weights, *_ = np.linalg.lstsq(harmonic_matrix, signal, rcond=None)
# 减去估计的谐波干扰
interference = harmonic_matrix @ weights
return signal - interference

def _compute_snr(self, signal: np.ndarray) -> float:
"""计算信噪比"""
spectrum = np.abs(fft(signal))
freqs = fftfreq(len(signal), 1/self.fs)
pos_mask = freqs > 0
spectrum = spectrum[pos_mask]
freqs = freqs[pos_mask]

# 主峰功率
peak_idx = np.argmax(spectrum)
peak_power = spectrum[peak_idx]

# 噪声功率(主峰外)
noise_mask = np.ones(len(spectrum), dtype=bool)
noise_mask[max(0,peak_idx-3):peak_idx+4] = False
noise_power = np.mean(spectrum[noise_mask])

if noise_power == 0:
return 100.0
return 10 * np.log10(peak_power / noise_power)


# ==================== 测试代码 ====================
if __name__ == "__main__":
import time

estimator = RadarHeartRateEstimator(sample_rate=50.0)

# 模拟 30 秒雷达信号
t = np.arange(0, 30, 1/50)

# 真实参数
true_hr = 75 # bpm = 1.25 Hz
true_rr = 16 # breaths/min = 0.267 Hz

# 胸壁位移 = 心跳 + 呼吸 + 噪声
# 心跳幅度很小(~0.1mm),呼吸幅度大(~4mm)
heartbeat = 0.1 * np.sin(2 * np.pi * true_hr/60 * t)
breathing = 4.0 * np.sin(2 * np.pi * true_rr/60 * t)

# 呼吸谐波(三次谐波 = 0.8 Hz,接近心率 1.25 Hz)
resp_h3 = 0.5 * np.sin(2 * np.pi * 3*true_rr/60 * t)
resp_h4 = 0.3 * np.sin(2 * np.pi * 4*true_rr/60 * t)

noise = 0.05 * np.random.randn(len(t))

# 混合信号
radar_signal = heartbeat + breathing + resp_h3 + resp_h4 + noise

# 处理
start = time.time()
result = estimator.process(radar_signal)
process_time = (time.time() - start) * 1000

print("=" * 60)
print("雷达心率估计测试")
print("=" * 60)
print(f"真实心率: {true_hr} bpm")
print(f"真实呼吸: {true_rr} /min")
print(f"呼吸三次谐波: {3*true_rr/60:.3f} Hz = {3*true_rr:.0f} /min")
print(f"呼吸四次谐波: {4*true_rr/60:.3f} Hz = {4*true_rr:.0f} /min")
print(f"\n估计心率: {result['heart_rate']:.1f} bpm")
print(f"估计呼吸: {result['resp_rate']:.1f} /min")
print(f"SNR: {result['snr']:.2f} dB")
print(f"质量: {result['quality']}")
print(f"处理时间: {process_time:.1f} ms")

error = abs(result['heart_rate'] - true_hr)
print(f"\n心率误差: {error:.1f} bpm")
if error < 5:
print("✅ 误差 <5 bpm,满足监测要求")
else:
print("⚠️ 误差 ≥5 bpm,需优化")

呼吸谐波干扰分析

频率重叠场景

呼吸频率 二次谐波 三次谐波 四次谐波 心率范围 重叠风险
12 /min (0.2 Hz) 0.4 Hz 0.6 Hz 0.8 Hz 60-100 bpm ⚠️ 四次谐波
15 /min (0.25 Hz) 0.5 Hz 0.75 Hz 1.0 Hz 60-100 bpm ⚠️ 四次谐波
18 /min (0.3 Hz) 0.6 Hz 0.9 Hz 1.2 Hz 60-100 bpm 🔴 四次谐波
20 /min (0.33 Hz) 0.67 Hz 1.0 Hz 1.33 Hz 60-100 bpm 🔴 三次+四次
25 /min (0.42 Hz) 0.83 Hz 1.25 Hz 1.67 Hz 60-100 bpm 🔴 三次谐波

IMS 座舱特殊挑战

挑战 描述 影响
运动伪迹 车辆振动/身体移动 SNR 下降 10-20dB
多乘员干扰 前后排多人的呼吸信号 空间分辨率要求
衣物遮挡 冬季厚衣物衰减 心跳信号衰减 5-10x
安全带压力 改变胸壁运动模式 呼吸波形变形
驾驶姿势变化 前倾/后仰改变角度 雷达截面变化

IMS 应用方案

雷达部署位置

位置 优势 劣势 推荐雷达
方向盘后方 正对驾驶员胸壁 需集成到仪表台 60GHz 短距
车顶控制台 俯视角度好 距离较远 60GHz 中距
座椅靠背 贴近身体 可能被遮挡 超宽带 UWB
后视镜 正面视角 多人干扰 60GHz + 波束成形

心率监测的 IMS 价值

应用 心率阈值 检测窗口 价值
疲劳检测 HR < 60 或 HRV ↓ 5 min 疲劳时心率降低、HRV下降
压力/路怒 HR > 100 突变 30s 急性压力反应
酒驾辅助 HR 变异性异常 5 min 酒精影响自主神经
突发疾病 HR 异常(<40 或 >150) 10s 心脏事件检测
情绪识别 HRV 模式变化 2 min 情绪影响自主神经

与 rPPG 方案对比

指标 mmWave 雷达 rPPG(摄像头) 纺织 ECG
精度 ±5 bpm ±8 bpm ±1 bpm
隐私 ✅ 无图像 ❌ 面部图像 ✅ 无图像
穿戴 ✅ 无需 ✅ 无需 ⚠️ 需接触
遮挡鲁棒 ✅ 穿透衣物 ❌ 需见脸 ⚠️ 需接触
成本 ¥200-500 ¥0(已有) ¥200-500
多乘员 ⚠️ 需波束成形 ⚠️ 需多人检测 ❌ 每人一个
实时性 30s 窗口 10s 窗口 实时

总结

雷达心率估计的核心挑战是呼吸谐波干扰,特别是在高呼吸频率时三次/四次谐波与心率直接重叠。本文方法的创新在于自适应谐波消除。

对 IMS 的建议:

  1. 雷达心率作为 rPPG 的补充而非替代——双模态交叉验证
  2. 优先关注 HRV(心率变异度)而非绝对心率——HRV 对疲劳/压力更敏感
  3. 30s 检测窗口可满足疲劳监测,不满足紧急疾病检测

论文链接:https://www.mdpi.com/1424-8220/26/17/5587
DOI:10.3390/s26175587