车载雷达生命体征检测:MCSM与RLSRHS算法详解

车载雷达生命体征检测:MCSM + RLSRHS算法详解(Scientific Reports 2025)

论文信息:


核心创新

问题定义: 复杂环境下雷达生命体征检测面临两大挑战:

  1. 强反射干扰:静态反射物(墙壁、家具)和动态干扰(风扇)掩盖真实目标
  2. 呼吸谐波干扰:呼吸谐波频谱落在心率频段,严重干扰心跳检测

核心方法:

  1. MCSM算法:基于Range-Doppler谱的矩阵系数选择方法,提升复杂环境目标定位鲁棒性
  2. RLSRHS算法:递归最小二乘自适应陷波滤波,自动消除呼吸谐波干扰

性能提升: 复杂环境下心率检测误差 < 7.4 bpm,呼吸检测误差 < 4.9 bpm


1. 技术背景

1.1 FMCW雷达原理

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
import numpy as np

class FMCWRadar:
"""
FMCW雷达信号模型

频率调制连续波雷达
"""

def __init__(self, config: dict):
self.fc = config.get("fc", 60e9) # 载波频率 60GHz
self.B = config.get("B", 4e9) # 扫频带宽 4GHz
self.Tc = config.get("Tc", 100e-6) # 扫频周期 100μs
self.c = 3e8 # 光速

def transmit_signal(self, t: np.ndarray) -> np.ndarray:
"""
发射信号

s_tx(t) = exp(j * 2π * (fc*t + B/(2Tc) * t^2))
"""
phase = 2 * np.pi * (
self.fc * t +
self.B / (2 * self.Tc) * t**2
)
return np.exp(1j * phase)

def receive_signal(self, t: np.ndarray, target_distance: float,
breathing_amp: float, breathing_freq: float,
heartbeat_amp: float, heartbeat_freq: float) -> np.ndarray:
"""
接收信号(含生命体征调制)

胸部位移 = 呼吸幅度 * sin(2π * f_br * t) + 心跳幅度 * sin(2π * f_hr * t)
"""
# 时间延迟
td = 2 * target_distance / self.c

# 胸部位移
chest_displacement = (
breathing_amp * np.sin(2 * np.pi * breathing_freq * t) +
heartbeat_amp * np.sin(2 * np.pi * heartbeat_freq * t)
)

# 接收信号
phase = 2 * np.pi * (
self.fc * (t - td + chest_displacement) +
self.B / (2 * self.Tc) * (t - td)**2
)

return np.exp(1j * phase)

def mix_signal(self, tx: np.ndarray, rx: np.ndarray) -> np.ndarray:
"""
混频(中频信号)

IF = tx * conj(rx)
"""
return tx * np.conj(rx)

1.2 生命体征信号特征

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
class VitalSignsParams:
"""
生命体征参数

正常成人范围
"""

# 呼吸频率 (Hz)
BREATHING_FREQ_RANGE = (0.1, 0.5) # 6-30 次/分钟

# 心率频率 (Hz)
HEART_RATE_FREQ_RANGE = (0.8, 2.0) # 48-120 次/分钟

# 胸壁位移幅度 (mm)
BREATHING_AMPLITUDE = (4, 12) # 呼吸引起的胸壁位移
HEARTBEAT_AMPLITUDE = (0.2, 0.5) # 心跳引起的胸壁位移

@staticmethod
def get_physiological_params(age_group: str = "adult"):
"""
根据年龄组获取生理参数

Args:
age_group: adult, child, infant
"""
params = {
"adult": {
"breathing_freq": (0.2, 0.33), # 12-20 次/分钟
"heart_rate_freq": (1.0, 1.67), # 60-100 次/分钟
},
"child": {
"breathing_freq": (0.33, 0.5), # 20-30 次/分钟
"heart_rate_freq": (1.33, 2.0), # 80-120 次/分钟
},
"infant": {
"breathing_freq": (0.5, 0.83), # 30-50 次/分钟
"heart_rate_freq": (2.0, 2.67), # 120-160 次/分钟
}
}
return params.get(age_group, params["adult"])

2. MCSM算法详解

2.1 算法原理

问题: 复杂环境中强反射体(金属家具、墙壁)和动态干扰(风扇、行人)掩盖真实目标。

解决方案: MCSM(Matrix Coefficient Selection Method)基于Range-Doppler谱,结合幅度和相位信息进行目标定位。

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
class MCSMAlgorithm:
"""
MCSM算法:复杂环境目标检测

Matrix Coefficient Selection Method
"""

def __init__(self, num_chirps: int = 128, num_samples: int = 256):
self.num_chirps = num_chirps
self.num_samples = num_samples

def compute_range_doppler(self, if_signal: np.ndarray) -> np.ndarray:
"""
计算Range-Doppler谱

Args:
if_signal: 中频信号 (num_chirps, num_samples)

Returns:
range_doppler: Range-Doppler谱 (num_chirps, num_samples)
"""
# 距离FFT
range_fft = np.fft.fft(if_signal, axis=1)

# 多普勒FFT
range_doppler = np.fft.fftshift(
np.fft.fft(range_fft, axis=0),
axes=0
)

return np.abs(range_doppler)

def suppress_static_clutter(self, range_doppler: np.ndarray) -> np.ndarray:
"""
静态杂波抑制

低频零化:消除零多普勒频率分量
"""
suppressed = range_doppler.copy()

# 零多普勒区域置零
zero_doppler_range = 2
center = self.num_chirps // 2
suppressed[center-zero_doppler_range:center+zero_doppler_range, :] = 0

return suppressed

def compute_matrix_coefficient(self, range_doppler: np.ndarray) -> np.ndarray:
"""
计算矩阵系数

M = |A|^α * |φ|^β

A: 幅度
φ: 相位
α, β: 权重系数
"""
# 幅度
amplitude = np.abs(range_doppler)

# 相位
phase = np.angle(range_doppler)

# 矩阵系数
alpha = 0.7
beta = 0.3

matrix_coeff = np.power(amplitude, alpha) * np.power(np.abs(phase), beta)

return matrix_coeff

def detect_target(self, if_signal: np.ndarray) -> dict:
"""
目标检测

Returns:
target_info: 目标距离、速度信息
"""
# 1. Range-Doppler谱
rd = self.compute_range_doppler(if_signal)

# 2. 杂波抑制
rd_clean = self.suppress_static_clutter(rd)

# 3. 矩阵系数
mc = self.compute_matrix_coefficient(rd_clean)

# 4. 目标定位(最大值)
max_idx = np.unravel_index(np.argmax(mc), mc.shape)
doppler_idx, range_idx = max_idx

# 5. 计算距离和速度
distance = self._range_idx_to_distance(range_idx)
velocity = self._doppler_idx_to_velocity(doppler_idx)

return {
"distance": distance,
"velocity": velocity,
"confidence": mc[max_idx]
}

def _range_idx_to_distance(self, range_idx: int) -> float:
"""
Range索引转距离
"""
# 距离分辨率 = c / (2 * B)
range_resolution = 3e8 / (2 * 4e9) # 约37.5mm
return range_idx * range_resolution

def _doppler_idx_to_velocity(self, doppler_idx: int) -> float:
"""
Doppler索引转速度
"""
# 速度分辨率 = λ / (2 * N * Tc)
wavelength = 3e8 / 60e9 # 5mm
velocity_resolution = wavelength / (2 * self.num_chirps * 100e-6)

# 频移
doppler_shift = doppler_idx - self.num_chirps // 2

return doppler_shift * velocity_resolution

3. RLSRHS算法详解

3.1 算法原理

问题: 呼吸谐波频谱落在心率频段,严重干扰心跳检测。

解决方案: RLSRHS(Recursive Least Squares Respiratory Harmonic Suppression)自适应消除呼吸谐波。

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
class RLSRHSAlgorithm:
"""
RLSRHS算法:呼吸谐波抑制

Recursive Least Squares Respiratory Harmonic Suppression
"""

def __init__(self, filter_order: int = 32, forget_factor: float = 0.99):
"""
Args:
filter_order: 滤波器阶数
forget_factor: 遗忘因子(越接近1,记忆越长)
"""
self.L = filter_order
self.lambda_ = forget_factor

# 初始化
self.w = np.zeros(filter_order, dtype=complex) # 滤波器系数
self.P = np.eye(filter_order) * 1000 # 逆相关矩阵

def process(self, signal: np.ndarray, breathing_freq: float,
fs: float = 100) -> np.ndarray:
"""
处理信号,消除呼吸谐波

Args:
signal: 输入信号
breathing_freq: 呼吸频率 (Hz)
fs: 采样率 (Hz)

Returns:
cleaned_signal: 消除谐波后的信号
"""
n_samples = len(signal)
cleaned = np.zeros(n_samples, dtype=complex)

# 生成参考信号(呼吸信号及其谐波)
t = np.arange(n_samples) / fs

for i in range(self.L, n_samples):
# 当前采样点
d = signal[i]

# 参考信号向量
x = self._generate_reference(t[i], breathing_freq)

# RLS更新
y = np.dot(self.w.conj(), x) # 滤波器输出
e = d - y # 误差信号

# 增益向量
Px = np.dot(self.P, x)
k = Px / (self.lambda_ + np.dot(x.conj(), Px))

# 更新滤波器系数
self.w = self.w + k * e.conj()

# 更新逆相关矩阵
self.P = (self.P - np.outer(k, np.dot(x.conj(), self.P))) / self.lambda_

# 输出:误差信号(消除呼吸谐波后的心跳信号)
cleaned[i] = e

return cleaned

def _generate_reference(self, t: float, breathing_freq: float) -> np.ndarray:
"""
生成参考信号

包含基频和谐波(2倍、3倍...)
"""
reference = np.zeros(self.L, dtype=complex)

for harmonic in range(1, 4): # 1倍、2倍、3倍谐波
freq = breathing_freq * harmonic
phase = 2 * np.pi * freq * t
reference[harmonic-1::3] = np.exp(1j * phase)

return reference

3.2 完整生命体征提取流程

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
class VitalSignsExtractor:
"""
完整生命体征提取流程

集成MCSM + RLSRHS
"""

def __init__(self):
self.mcsm = MCSMAlgorithm()
self.rlsrhs = RLSRHSAlgorithm()

def extract(self, if_signal: np.ndarray, fs: float = 100) -> dict:
"""
提取生命体征

Args:
if_signal: 中频信号
fs: 采样率

Returns:
vital_signs: 心率、呼吸频率
"""
# 1. 目标定位
target = self.mcsm.detect_target(if_signal)
print(f"[检测] 目标距离: {target['distance']:.2f}m")

# 2. 提取相位信号(包含生命体征)
phase_signal = self._extract_phase(if_signal, target)

# 3. 初步估计呼吸频率
breathing_freq = self._estimate_breathing_freq(phase_signal, fs)
print(f"[检测] 呼吸频率: {breathing_freq*60:.1f} 次/分钟")

# 4. 消除呼吸谐波
cleaned_signal = self.rlsrhs.process(phase_signal, breathing_freq, fs)

# 5. 提取心跳频率
heart_rate_freq = self._estimate_heart_rate(cleaned_signal, fs)
print(f"[检测] 心率: {heart_rate_freq*60:.1f} 次/分钟")

return {
"breathing_rate_bpm": breathing_freq * 60,
"heart_rate_bpm": heart_rate_freq * 60,
"target_distance_m": target["distance"]
}

def _extract_phase(self, if_signal: np.ndarray, target: dict) -> np.ndarray:
"""
提取相位信号
"""
# 简化:直接使用目标距离处的相位
phase = np.angle(if_signal[:, int(target["distance"] / 0.0375)])
return np.unwrap(phase)

def _estimate_breathing_freq(self, phase: np.ndarray, fs: float) -> float:
"""
估计呼吸频率
"""
# FFT
fft_result = np.fft.fft(phase)
freqs = np.fft.fftfreq(len(phase), 1/fs)

# 呼吸频段搜索
breathing_band = (freqs >= 0.1) & (freqs <= 0.5)
fft_breathing = np.abs(fft_result[breathing_band])
freqs_breathing = freqs[breathing_band]

# 峰值频率
peak_idx = np.argmax(fft_breathing)
return np.abs(freqs_breathing[peak_idx])

def _estimate_heart_rate(self, cleaned: np.ndarray, fs: float) -> float:
"""
估计心率
"""
# FFT
fft_result = np.fft.fft(cleaned)
freqs = np.fft.fftfreq(len(cleaned), 1/fs)

# 心率频段搜索
hr_band = (freqs >= 0.8) & (freqs <= 2.0)
fft_hr = np.abs(fft_result[hr_band])
freqs_hr = freqs[hr_band]

# 峰值频率
peak_idx = np.argmax(fft_hr)
return np.abs(freqs_hr[peak_idx])


# 使用示例
if __name__ == "__main__":
# 模拟数据
num_chirps = 128
num_samples = 256

# 生成中频信号
t = np.linspace(0, 1, num_chirps)
if_signal = np.random.randn(num_chirps, num_samples) + \
0.5 * np.sin(2 * np.pi * 0.25 * t[:, np.newaxis]) + \
0.1 * np.sin(2 * np.pi * 1.2 * t[:, np.newaxis])

# 提取生命体征
extractor = VitalSignsExtractor()
vitals = extractor.extract(if_signal)

print(f"\n最终结果:")
print(f" 呼吸: {vitals['breathing_rate_bpm']:.1f} 次/分钟")
print(f" 心率: {vitals['heart_rate_bpm']:.1f} 次/分钟")

4. 实验结果

4.1 性能对比

方法 HR误差 (bpm) RR误差 (bpm)
传统FFT 15.2 8.3
EMD分解 12.1 6.5
VMD分解 9.8 5.2
MCSM + RLSRHS 7.4 4.9

4.2 复杂环境测试

环境 目标定位成功率 HR误差 RR误差
空房间 99.5% 5.1 3.2
有风扇 97.2% 6.8 4.1
多人场景 94.8% 8.2 5.5
强反射环境 92.3% 9.1 6.2

5. IMS 应用启示

5.1 车载部署架构

graph LR
    A[60GHz FMCW雷达] --> B[Range-Doppler处理]
    B --> C[MCSM目标定位]
    C --> D[相位提取]
    D --> E[RLSRHS谐波抑制]
    E --> F[HR/RR估计]
    F --> G[DMS融合]

5.2 硬件配置建议

参数 推荐值 说明
频段 60GHz 穿透性好,分辨率高
带宽 4GHz 距离分辨率~37mm
扫频周期 100μs 平衡精度和速度
Chirp数/帧 128 多普勒分辨率

5.3 与DMS融合

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
class IMSVitalSignsFusion:
"""
IMS生命体征融合

雷达生命体征 + 摄像头疲劳检测
"""

def __init__(self):
self.radar_extractor = VitalSignsExtractor()
self.camera_detector = None # 摄像头疲劳检测

def assess_driver_state(self, radar_signal, camera_image):
"""
综合评估驾驶员状态
"""
# 雷达生命体征
vitals = self.radar_extractor.extract(radar_signal)

# 摄像头疲劳指标
fatigue = self.camera_detector.detect(camera_image)

# 融合决策
if vitals["heart_rate_bpm"] > 100 and fatigue["perclos"] > 0.3:
return "HIGH_RISK"
elif fatigue["perclos"] > 0.2:
return "MODERATE_RISK"
else:
return "NORMAL"

6. 总结

方面 内容
MCSM Range-Doppler谱目标定位,抗复杂环境干扰
RLSRHS 自适应滤波消除呼吸谐波,提取心跳信号
性能 HR误差<7.4bpm, RR误差<4.9bpm
部署 60GHz FMCW雷达,实时处理

参考链接:

  1. 论文原文: https://www.nature.com/articles/s41598-025-32042-6
  2. TI AWR1642: https://www.ti.com/product/AWR1642
  3. FMCW雷达原理: https://www.ti.com/lit/wp/spyy005/spyy005.pdf

车载雷达生命体征检测:MCSM与RLSRHS算法详解
https://dapalm.com/2026/06/10/2026-06-10-Radar-Vital-Signs-MCSM-RLSRHS/
作者
Mars
发布于
2026年6月10日
许可协议