HEAR:毫米波雷达心率感知的可观测性评估——仿真到真实的零样本泛化

论文信息

项目 内容
标题 Learning to Assess Heartbeat Observability for mmWave Heart-Rate Sensing
作者 Yuxuan Hu, Shilin Shan, Jianfei Yang, Feng Xu
领域 Artificial Intelligence (cs.AI)
年份 2026
链接 arXiv:2610.03570
项目页 HEAR Project
规模 19页,11图

核心创新

HEAR(Heartbeat Estimation with Assessed Reliability)是首个学习评估毫米波雷达心跳可观测性的框架,解决了一个核心问题:不是所有雷达测量都能可靠提取心率,需要先判断”这个测量值是否可信”。

三大突破:

  1. 可观测性评估:学习预测心跳信号的可读性分数
  2. 可控FMCW仿真器:生成不同可观测条件下的训练数据
  3. 仿真到真实的零样本泛化:仅用仿真数据训练,直接零样本迁移到60GHz和120GHz两个真实数据集(共134名受试者)

关键指标: 120GHz数据集上,基于可观测性分数的选择性预测,将心率MAE从17.9 BPM降至1.6 BPM(50%覆盖率时)

方法详解

1. 问题定义

1
2
3
4
5
6
7
8
9
10
11
12
13
"""
核心问题:
mmWave雷达接触式心率感知中,相干叠加的多散射体回波
可能抑制心跳成分,即使在相似观测几何下也会发生。

这意味着:不能假设"看起来好的测量就一定有好的心率"
必须学习评估每次测量的可观测性。

HEAR方案:
1. 训练双任务Transformer:同时预测可观测性分数+心率
2. 仅用仿真数据训练 → 零样本迁移到真实数据
3. 可观测性分数可用于选择性预测(只在高置信度时输出)
"""

2. 可控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
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
# 示意代码,不可直接运行(为解释论文 Section 3 思想的简化示意,非官方实现)
import torch
import torch.nn as nn
import numpy as np
from typing import Tuple

class ControllableFMCWSimulator:
"""
可控多散射体FMCW雷达仿真器

论文 Section 3: 生成不同可观测条件训练数据

核心思想:
- 模拟多个散射体(胸壁、心脏、呼吸、衣物)
- 控制各成分的幅度和相位
- 自动生成可观测性标签
"""

def __init__(
self,
freq_ghz: float = 60.0,
num_samples: int = 1024,
sample_rate: int = 1000
):
self.freq = freq_ghz * 1e9 # Hz
self.c = 3e8 # 光速
self.num_samples = num_samples
self.sample_rate = sample_rate

def simulate(
self,
heart_rate_bpm: float = 72.0,
breathing_rate_bpm: float = 18.0,
heart_amplitude: float = 0.1e-3, # 心脏微动幅度(米)
breathing_amplitude: float = 1.0e-3, # 呼吸幅度
num_scatterers: int = 5,
noise_level: float = 0.01,
observability: str = 'high' # 'high', 'medium', 'low'
) -> Tuple[np.ndarray, float]:
"""
仿真FMCW雷达相位信号

Args:
heart_rate_bpm: 心率(次/分)
breathing_rate_bpm: 呼吸率
heart_amplitude: 心脏微动幅度
breathing_amplitude: 呼吸幅度
num_scatterers: 散射体数量
noise_level: 噪声水平
observability: 可观测性等级
Returns:
phase_signal: 相位信号
true_observability: 真实可观测性分数
"""
t = np.arange(self.num_samples) / self.sample_rate

# 心跳信号
heart_freq = heart_rate_bpm / 60 # Hz
heart_signal = heart_amplitude * np.sin(2 * np.pi * heart_freq * t)

# 呼吸信号
breath_freq = breathing_rate_bpm / 60
breath_signal = breathing_amplitude * np.sin(2 * np.pi * breath_freq * t)

# 多散射体叠加
scatterer_signals = []
for i in range(num_scatterers):
# 每个散射体有不同的距离和相位
distance = 0.5 + 0.1 * i + np.random.randn() * 0.05
phase_offset = np.random.uniform(0, 2 * np.pi)

# 散射体反射信号(包含心脏+呼吸微动)
s = (heart_signal + breath_signal) * np.cos(phase_offset) \
+ noise_level * np.random.randn(len(t))
scatterer_signals.append(s)

# 相干叠加
combined = np.sum(scatterer_signals, axis=0)

# 提取相位
phase_signal = np.angle(combined + 1j * np.imag(combined))

# 计算真实可观测性
# 频谱中心跳峰与已知心率的吻合度
fft = np.fft.rfft(phase_signal)
freqs = np.fft.rfftfreq(len(phase_signal), d=1/self.sample_rate)

heart_mask = np.abs(freqs - heart_freq) < 0.05
heart_power = np.sum(np.abs(fft[heart_mask]))

breath_mask = np.abs(freqs - breath_freq) < 0.05
breath_power = np.sum(np.abs(fft[breath_mask]))

total_power = np.sum(np.abs(fft))

# 可观测性 = 心跳功率 / (总功率 - 呼吸功率)
true_observability = heart_power / (total_power - breath_power + 1e-10)

# 根据可观测性设置调整
if observability == 'low':
# 增加散射体干扰降低可观测性
combined += 0.5 * heart_amplitude * np.random.randn(len(t))
true_observability *= 0.3

return phase_signal, float(true_observability)

def generate_dataset(
self,
n_samples: int = 10000
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
生成训练数据集
"""
signals = []
heart_rates = []
observabilities = []

for _ in range(n_samples):
# 随机参数
hr = np.random.uniform(50, 120) # 50-120 BPM
br = np.random.uniform(12, 30) # 12-30 BPM
obs = np.random.choice(['high', 'medium', 'low'], p=[0.4, 0.4, 0.2])

signal, true_obs = self.simulate(hr, br, observability=obs)

signals.append(signal)
heart_rates.append(hr)
observabilities.append(true_obs)

return (np.array(signals), np.array(heart_rates),
np.array(observabilities))


# 测试仿真器
if __name__ == "__main__":
sim = ControllableFMCWSimulator(freq_ghz=60)

# 生成一个样本
signal, obs = sim.simulate(heart_rate_bpm=72, observability='high')
print(f"信号长度: {len(signal)}")
print(f"可观测性分数: {obs:.4f}")

# 生成数据集
signals, hrs, obs_list = sim.generate_dataset(100)
print(f"\n数据集: {signals.shape}")
print(f"心率范围: {hrs.min():.0f}-{hrs.max():.0f} BPM")
print(f"可观测性范围: {obs_list.min():.4f}-{obs_list.max():.4f}")

print("\n✅ FMCW仿真器测试通过")

3. HEAR 双任务Transformer

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
# 示意代码,不可直接运行(为解释论文 Section 4 思想的简化示意,非官方实现)
class HEARTransformer(nn.Module):
"""
HEAR: Heartbeat Estimation with Assessed Reliability

论文 Section 4: 紧凑双任务Transformer
- 任务1: 预测可观测性分数(0-1)
- 任务2: 预测心率(BPM)

输入: 频谱幅度 + 相对呼吸基频的频率
"""

def __init__(
self,
input_dim: int = 256, # 频谱bin数
hidden_dim: int = 128,
num_heads: int = 4,
num_layers: int = 3,
max_freq: float = 5.0 # 最大频率 Hz
):
super().__init__()
self.input_dim = input_dim
self.max_freq = max_freq

# 输入嵌入
self.input_proj = nn.Linear(input_dim * 2, hidden_dim) # 幅度+相对频率

# 位置编码
self.pos_encoding = nn.Parameter(torch.randn(1, input_dim, hidden_dim))

# Transformer编码器
encoder_layer = nn.TransformerEncoderLayer(
d_model=hidden_dim,
nhead=num_heads,
dim_feedforward=hidden_dim * 4,
dropout=0.1,
activation='gelu',
batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)

# 池化
self.pool = nn.AdaptiveAvgPool1d(1)

# 可观测性预测头
self.obs_head = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim // 2),
nn.ReLU(),
nn.Linear(hidden_dim // 2, 1),
nn.Sigmoid()
)

# 心率预测头
self.hr_head = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim // 2),
nn.ReLU(),
nn.Linear(hidden_dim // 2, 1)
)

def forward(
self,
spectral_magnitudes: torch.Tensor,
frequencies: torch.Tensor
) -> Tuple[torch.Tensor, torch.Tensor]:
"""
Args:
spectral_magnitudes: 频谱幅度 (B, F)
frequencies: 频率值 (B, F) in Hz
Returns:
obs_score: 可观测性分数 (B, 1), 0-1
heart_rate: 心率预测 (B, 1), BPM
"""
B, F = spectral_magnitudes.shape

# 拼接幅度和频率
x = torch.cat([
spectral_magnitudes.unsqueeze(-1),
frequencies.unsqueeze(-1)
], dim=-1) # (B, F, 2)

# 投影
x = self.input_proj(x) # (B, F, hidden)

# 位置编码
x = x + self.pos_encoding[:, :F, :]

# Transformer
x = self.transformer(x) # (B, F, hidden)

# 池化
x = self.pool(x.transpose(1, 2)).squeeze(-1) # (B, hidden)

# 双任务输出
obs_score = self.obs_head(x) # (B, 1)
heart_rate = self.hr_head(x) # (B, 1)

return obs_score, heart_rate

def predict_with_confidence(
self,
spectral_magnitudes: torch.Tensor,
frequencies: torch.Tensor,
coverage: float = 0.5
) -> dict:
"""
选择性预测:基于可观测性分数选择性输出

Args:
coverage: 输出覆盖率(0-1),越高输出越多
Returns:
results: 包含预测和置信度的字典
"""
with torch.no_grad():
obs_score, hr = self.forward(spectral_magnitudes, frequencies)

# 基于可观测性分数排序
scores = obs_score.squeeze().cpu().numpy()
n_output = int(len(scores) * coverage)
top_indices = np.argsort(scores)[-n_output:]

results = {
'all_heart_rates': hr.squeeze().cpu().numpy(),
'all_observability': scores,
'selected_indices': top_indices,
'selected_hr': hr.squeeze().cpu().numpy()[top_indices],
'coverage': coverage,
'mean_confidence': scores[top_indices].mean() if n_output > 0 else 0
}

return results


# 测试
if __name__ == "__main__":
model = HEARTransformer(input_dim=256, hidden_dim=128)

# 模拟输入
B, F = 4, 256
magnitudes = torch.randn(B, F)
freqs = torch.linspace(0, 5, F).unsqueeze(0).expand(B, -1)

obs, hr = model(magnitudes, freqs)
print(f"可观测性分数: {obs.shape} → {obs.squeeze().tolist()}")
print(f"心率预测: {hr.shape} → {hr.squeeze().tolist()}")

# 选择性预测
result = model.predict_with_confidence(magnitudes, freqs, coverage=0.5)
print(f"\n选择性预测 (50%覆盖):")
print(f" 选中数: {len(result['selected_indices'])}")
print(f" 平均置信度: {result['mean_confidence']:.4f}")

total_params = sum(p.numel() for p in model.parameters())
print(f"\n模型参数量: {total_params:,} ({total_params/1e6:.2f}M)")
print("✅ HEAR模型测试通过")

实验结果

1. 心率估计性能

120GHz VitalSense 数据集上,基于可观测性分数做选择性预测(HEAR 选择器,论文 Table III):

覆盖率 MAE (BPM) Acc@5 BPM
100% 17.9 62%
90% 13.5 69%
70% 3.2 86%
60% 1.9 91%
50% 1.6 93%
40% 1.3 96%
30% 1.2 97%

作为参照:50% 覆盖率时理论 Oracle 选择器可达 0.8 BPM——HEAR 的实际选择器(1.6 BPM)与 Oracle 之间仍有差距。

2. 仿真到真实的零样本泛化

注意:HEAR 的泛化是仿真训练→真实数据零样本迁移,不是”60GHz 仿真训练、120GHz 测试”这类跨频段训练实验。论文明确说明两个真实数据集的任何窗口都没有参与训练/验证/阈值调优(Sec. IV-A):

真实数据集 频段 受试者 门控 AUC(可观测性判别)
Parralejo 等 60GHz — 0.856
VitalSense 120GHz — 0.941

两个频段的评估均来自同一个仅用仿真数据训练的模型。

3. 边缘部署性能

指标 数值 说明
处理延迟 50.8 ms / 25s 窗口 含 47.7ms 信号前处理 + 3.1ms 网络推理
边缘设备 NVIDIA Jetson AGX Orin(30W 模式) 仅用 ARMv8 CPU,未用 GPU/DLA 加速
模型大小 5,295 参数(约 20.7 KB FP32 权重) 约 0.26M FLOPs/窗口

IMS 开发启示

1. 60GHz雷达心率监测落地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 示意代码,不可直接运行(仅为集成路线的梳理笔记)
class IMSRadarVitalSigns:
"""IMS 60GHz雷达生命体征监测方案"""

def __init__(self):
# 60GHz雷达已在CPD中引入(参考Murata方案)
# HEAR框架可直接集成
self.radar_config = {
'frequency': '60 GHz',
'application': 'CPD + 心率监测',
'advantage': '已有雷达硬件,复用做生命体征',
}

def integration_plan(self):
return {
'Phase 1': 'CPD雷达检测活体(呼吸频率)',
'Phase 2': '+ 心率监测(HEAR框架)',
'Phase 3': '+ 可观测性评估(选择性输出)',
'Phase 4': '健康座舱(持续生命体征监控)',
}

2. 可观测性评估的通用价值

应用场景 可观测性评估价值 IMS集成
CPD心率 区分活体/非活体 直接应用
疲劳心率变异(HRV) 确保HRV数据质量 疲劳深度检测
呼吸监测 区分正常呼吸/暂停 儿童检测+健康监测
驾驶员健康 长期健康趋势 健康座舱

3. 仿真到真实的迁移方法论

HEAR的纯仿真训练→真实零样本方法论对IMS有重大启示:

步骤 HEAR做法 IMS可借鉴
仿真器 可控FMCW多散射体 构建座舱雷达仿真器
标签 频谱峰值自动标注 自动标注替代人工
训练 仅仿真数据 降低数据采集成本
验证 60+120GHz真实数据 多平台验证
部署 50ms边缘延迟 车载实时可行

总结

HEAR 论文是 mmWave 雷达生命体征监测的重要突破:

  1. 可观测性评估解决了”什么时候可信”的核心问题
  2. 纯仿真训练+零样本迁移大幅降低数据需求
  3. 50%覆盖率下1.6 BPM MAE达到医疗级精度
  4. 50ms边缘延迟满足车载实时要求

对 IMS 的核心启示:CPD雷达模块复用做生命体征监测时,必须引入可观测性评估。不是每次雷达测量都适合心率提取,HEAR框架提供了判断哪些测量可信的方案。这直接支撑了IMS从CPD向”健康座舱”的演进路线。