雷达心率估计:呼吸谐波干扰消除新方法——CPD 生命体征监测的关键突破

论文来源:Sensors 期刊, 2026年9月
核心挑战:呼吸信号谐波干扰心率检测
IMS 相关性:⭐⭐⭐⭐(CPD 和健康监测的基础技术)


论文信息

项目 内容
标题 Radar-Based Heart Rate Estimation Method Under Respiratory Harmonic Interference
期刊 Sensors, 2026, 26(17), 5587
发表日期 2026年9月
DOI 10.3390/s26175587
关键词 radar, heart rate, respiration, harmonic interference, FMCW
链接 https://www.mdpi.com/1424-8220/26/17/5587

核心问题

呼吸干扰心率检测的挑战

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
"""
雷达心率估计的呼吸谐波干扰问题

问题:
- 心率:60-100 bpm (1.0-1.67 Hz)
- 呼吸:12-20 bpm (0.2-0.33 Hz)
- 呼吸的 3-5 次谐波正好落入心率频率范围!

示例:
- 呼吸频率 0.25 Hz (15 bpm)
- 4次谐波 = 1.0 Hz = 60 bpm ← 与心率重叠!
- 5次谐波 = 1.25 Hz = 75 bpm ← 与心率重叠!

传统 FFT 无法区分这是呼吸谐波还是真实心率
"""

import numpy as np

def demonstrate_harmonic_interference():
"""演示呼吸谐波对心率检测的干扰"""

# 模拟参数
fs = 50 # 采样率 Hz
duration = 10 # 秒
t = np.arange(0, duration, 1/fs)

# 真实信号
true_hr = 72 / 60 # Hz (72 bpm)
true_rr = 16 / 60 # Hz (16 bpm)

# 心率信号(微弱)
heart_signal = 0.1 * np.sin(2 * np.pi * true_hr * t)

# 呼吸信号(较强)+ 谐波
resp_signal = 1.0 * np.sin(2 * np.pi * true_rr * t)
resp_harmonics = sum(
0.5 / n * np.sin(2 * np.pi * n * true_rr * t)
for n in range(2, 8)
)

# 合成信号
total = heart_signal + resp_signal + resp_harmonics

# FFT 分析
fft = np.fft.rfft(total)
freqs = np.fft.rfftfreq(len(total), 1/fs)
power = np.abs(fft)**2

# 找峰值
top_peaks = np.argsort(power[1:])[::-1][:5] + 1
print("FFT 峰值分析:")
print(f"{'频率(Hz)':<12} {'功率':<12} {'对应bpm':<10} {'来源'}")
print("-" * 50)
for p in top_peaks:
freq = freqs[p]
bpm = freq * 60
power_val = power[p]

if abs(freq - true_rr) < 0.05:
source = "呼吸基频"
elif abs(freq - true_hr) < 0.05:
source = "✅ 真实心率"
else:
harmonic = round(freq / true_rr)
source = f"呼吸{harmonic}次谐波"

print(f"{freq:<12.3f} {power_val:<12.3f} {bpm:<10.1f} {source}")

print(f"\n真实心率: {true_hr*60:.0f} bpm")
print("⚠️ 呼吸谐波与心率重叠,传统FFT无法区分")

demonstrate_harmonic_interference()

解决方案

谐波消除算法

步骤 方法 目标
1. 呼吸频率估计 低频带峰值检测 确定呼吸基频
2. 谐波位置计算 整数倍呼吸频率 定位干扰频率
3. 自适应陷波滤波 在谐波位置窄带滤波 消除谐波
4. 心率提取 残余信号峰值检测 提取真实心率
5. 交叉验证 心率范围合理性检查 防止误判

算法实现

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
"""
雷达心率估计 - 呼吸谐波消除算法

基于 Sensors 2026 论文思路复现
适用于 FMCW / UWB 雷达
"""

import numpy as np
from scipy.signal import butter, filtfilt, iirnotch
from typing import Tuple

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

流程:
1. 雷达相位提取(胸部微动)
2. 带通滤波分离呼吸和心跳
3. 呼吸频率检测
4. 谐波自适应陷波
5. 心率提取

性能目标:
- 心率误差 < 5 bpm
- 呼吸频率误差 < 2 /min
- 处理延迟 < 5s
"""

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

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

Args:
radar_phase: 雷达相位数据 (N,), 已提取的胸部微动信号

Returns:
dict with 'heart_rate', 'resp_rate', 'snr', 'quality'
"""
# 1. 带通滤波分离信号
# 呼吸带:0.1-0.5 Hz (6-30 bpm)
resp_signal = self._bandpass(radar_phase, 0.1, 0.5)

# 心跳带:0.8-2.0 Hz (48-120 bpm)
heart_signal = self._bandpass(radar_phase, 0.8, 2.0)

# 2. 检测呼吸频率
resp_freq = self._find_dominant_freq(resp_signal, 0.1, 0.5)
resp_rate = resp_freq * 60

# 3. 计算呼吸谐波位置
harmonics = [resp_freq * n for n in range(2, 8)]
harmonics = [f for f in harmonics if 0.8 <= f <= 2.0]

# 4. 自适应陷波滤波消除谐波
filtered_heart = heart_signal.copy()
for harmonic in harmonics:
if harmonic > 0:
# 窄带陷波(Q=30, 窄带不影响心率)
w0 = harmonic / (self.fs / 2)
Q = 30
b, a = iirnotch(w0, Q)
filtered_heart = filtfilt(b, a, filtered_heart)

# 5. 提取心率
heart_freq = self._find_dominant_freq(filtered_heart, 0.8, 2.0)
heart_rate = heart_freq * 60

# 6. 质量评估
snr = self._compute_snr(filtered_heart, heart_freq)
quality = 'good' if snr > 3 else 'poor'

return {
'heart_rate': heart_rate,
'resp_rate': resp_rate,
'snr': snr,
'quality': quality,
'harmonics_removed': len(harmonics),
}

def _bandpass(self, signal, low, high):
"""带通滤波"""
b, a = butter(4, [low / (self.fs/2), high / (self.fs/2)], btype='band')
return filtfilt(b, a, signal)

def _find_dominant_freq(self, signal, low, high):
"""找到频带内的主频"""
fft = np.fft.rfft(signal)
freqs = np.fft.rfftfreq(len(signal), 1/self.fs)
power = np.abs(fft)**2

# 限制搜索范围
mask = (freqs >= low) & (freqs <= high)
if not mask.any():
return 0

peak_idx = np.argmax(power[mask])
return freqs[mask][peak_idx]

def _compute_snr(self, signal, freq):
"""计算信噪比"""
if freq == 0:
return 0
fft = np.fft.rfft(signal)
freqs = np.fft.rfftfreq(len(signal), 1/self.fs)
power = np.abs(fft)**2

# 信号功率
peak_idx = np.argmin(np.abs(freqs - freq))
signal_power = power[peak_idx]

# 噪声功率(峰值±5个bin以外)
noise_range = np.concatenate([
power[max(0, peak_idx-10):peak_idx-5],
power[peak_idx+5:peak_idx+10]
])
noise_power = np.mean(noise_range) if len(noise_range) > 0 else 1

return 10 * np.log10(signal_power / (noise_power + 1e-10))


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

estimator = RadarHeartRateEstimator(sample_rate=50)

# 模拟 10 秒雷达相位信号
fs = 50
duration = 10
t = np.arange(0, duration, 1/fs)

true_hr = 72 / 60 # 72 bpm
true_rr = 16 / 60 # 16 bpm

# 心跳信号(微弱)
heart = 0.05 * np.sin(2 * np.pi * true_hr * t)

# 呼吸信号 + 谐波
resp = 0.5 * np.sin(2 * np.pi * true_rr * t)
for n in range(2, 8):
resp += 0.5 / n * np.sin(2 * np.pi * n * true_rr * t)

# 噪声
noise = 0.02 * np.random.randn(len(t))

radar_signal = heart + resp + noise

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

print("=" * 60)
print("雷达心率估计测试")
print("=" * 60)
print(f"真实心率: {true_hr*60:.0f} bpm")
print(f"真实呼吸: {true_rr*60:.0f} /min")
print(f"\n检测结果:")
print(f" 心率: {result['heart_rate']:.1f} bpm")
print(f" 呼吸: {result['resp_rate']:.1f} /min")
print(f" SNR: {result['snr']:.1f} dB")
print(f" 质量: {result['quality']}")
print(f" 消除谐波数: {result['harmonics_removed']}")
print(f"\n处理时间: {elapsed:.1f} ms")

error = abs(result['heart_rate'] - true_hr*60)
print(f"心率误差: {error:.1f} bpm {'✅' if error < 5 else '❌'}")

性能指标

指标 传统 FFT 谐波消除法 提升
心率误差 ±15 bpm ±3 bpm 5x
呼吸误差 ±2 /min ±1 /min 2x
SNR 2-5 dB 8-15 dB 3-10x
可用率 ~60% ~85% +25pp
处理时间 <10ms <50ms 略增

IMS 应用场景

1. CPD 儿童生命体征

检测目标 信号特征 难度 方案
婴儿呼吸 0.3-1.0 Hz ⚠️ 呼吸带直接检测
婴儿心率 2-3 Hz (120-180bpm) ✅ 心率不与呼吸谐波重叠
成人呼吸 0.2-0.33 Hz ✅ 容易检测
成人心率 1.0-1.67 Hz 🔴 呼吸谐波严重干扰

关键发现:婴儿心率(120-180 bpm)远高于成人呼吸谐波范围,更容易检测!

2. 座舱健康监测

应用 可行性 精度需求 当前精度
疲劳心率 ✅ 好方法 ±5 bpm ±3 bpm
压力心率变异 ⚠️ 需高精度 ±2 bpm ±3 bpm
突发疾病 ✅ 异常检测 ±10 bpm ±3 bpm
酒驾心率 ⚠️ 辅助 ±5 bpm ±3 bpm

3. 传感器选型

雷达类型 呼吸检测 心率检测 成本 IMS 推荐
60GHz FMCW ✅ ✅ 中 ✅ 首选
UWB 脉冲 ✅ ⚠️ 中 ✅ CPD
24GHz ⚠️ ❌ 低 ❌ 精度不足
77GHz ✅ ✅ 高 ⚠️ 过高

IMS 开发启示

启示 建议行动 优先级
呼吸谐波是心率检测核心难题 实现自适应陷波滤波 🔴 高
婴儿心率更容易检测 CPD 心率检测优先做婴儿 ✅ 好消息
60GHz FMCW 最佳选择 评估 TI IWR6843AOP 🔴 高
±3bpm 精度可做健康监测 疲劳+突发疾病检测可行 🟡 中
SNR >8dB 需要近距离 雷达安装在座椅附近 🟡 中

总结

雷达心率估计的呼吸谐波消除是 CPD 生命体征监测的关键技术突破:

  1. 自适应陷波滤波:有效消除呼吸 3-7 次谐波,心率误差从 ±15 降到 ±3 bpm
  2. 婴儿心率更容易:120-180 bpm 远离呼吸谐波范围
  3. 60GHz FMCW 最佳:精度和成本的最优平衡
  4. 健康监测可行:±3 bpm 精度满足疲劳和突发疾病检测需求

对 IMS 的直接建议:在 CPD 模块中集成心率检测,优先实现婴儿心率(更容易),再扩展到成人。


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