PPG→ECG 增强:P2E-VQ 离散 patch 检索——从光学信号重建医疗级心电

论文标题: P2E-VQ: ECG-linked representation augmentation for PPG via discrete patch retrieval
arXiv: 2608.14656
分类: eess.SP(信号处理)


核心创新

P2E-VQ 提出了一种从 PPG(光电容积脉搏波)信号增强/重建 ECG(心电图)信号的新方法,使用离散向量量化 patch 检索技术:

  1. ECG 码本:从大量 ECG 数据学习离散 patch 表示
  2. PPG→ECG 映射:通过码本检索增强 PPG 信号
  3. 不确定性感知:参考了 Belhasin et al. (2025) 的不确定性扩散模型

1. 为什么 PPG→ECG 重要?

1.1 座舱场景的 ECG 获取难题

信号源 接触方式 精度 车内可行性
ECG(临床级) 12 导联 高 ❌ 不可行
ECG(方向盘) 双手接触 中 ⚠️ 间歇性
PPG(光学) 非接触 低 ✅ rPPG 摄像头
PPG→ECG 增强 非接触 中高 ✅ 可行

1.2 技术价值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class PPGtoECGValue:
"""PPG→ECG 增强的价值"""

value = {
'input': 'rPPG(摄像头面部色彩变化)',
'output': '近似 ECG 波形',
'capability': '从非接触信号提取 QRS 波群',
'applications': [
'心律失常检测(房颤/室早)',
'HRV 精确计算(时域+频域)',
'ST段变化(心肌缺血)',
'P波检测(房性心律失常)'
],
'automotive_value': 'rPPG 摄像头 → 医疗级心脏监测'
}

2. 方法概要

2.1 离散 Patch 检索架构

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
import torch
import torch.nn as nn

class P2EVQ(nn.Module):
"""
P2E-VQ: PPG to ECG via discrete patch retrieval

核心思路:
1. 将 ECG 信号编码为离散 patch(VQ-VAE)
2. 从 PPG 信号检索对应的 ECG patch
3. 拼接 patch 重建 ECG 波形
"""

def __init__(self, signal_length=2560, patch_size=64,
codebook_size=512, hidden=128):
super().__init__()
self.patch_size = patch_size
self.num_patches = signal_length // patch_size

# ECG 编码器(VQ-VAE)
self.ecg_encoder = nn.Sequential(
nn.Linear(patch_size, hidden),
nn.GELU(),
nn.Linear(hidden, hidden)
)

# 离散码本
self.codebook = nn.Embedding(codebook_size, hidden)

# ECG 解码器
self.ecg_decoder = nn.Sequential(
nn.Linear(hidden, hidden),
nn.GELU(),
nn.Linear(hidden, patch_size)
)

# PPG→ECG patch 检索
self.ppg_encoder = nn.Sequential(
nn.Linear(patch_size, hidden),
nn.GELU(),
nn.Linear(hidden, hidden)
)

# 检索投影
self.retrieval_proj = nn.Linear(hidden, hidden)

def encode_ecg_patches(self, ecg_signal):
"""将 ECG 编码为离散 patch"""
B = ecg_signal.shape[0]
# 分 patch
patches = ecg_signal.view(B, self.num_patches, self.patch_size)
# 编码
encoded = self.ecg_encoder(patches) # (B, num_patches, hidden)
# 量化
dist = torch.cdist(encoded, self.codebook.weight.unsqueeze(0))
indices = dist.argmin(dim=-1)
quantized = self.codebook(indices)
# 直通估计器
quantized = encoded + (quantized - encoded).detach()
return quantized, indices

def retrieve_from_ppg(self, ppg_signal):
"""从 PPG 信号检索 ECG patch"""
B = ppg_signal.shape[0]
patches = ppg_signal.view(B, self.num_patches, self.patch_size)
ppg_encoded = self.ppg_encoder(patches)
projected = self.retrieval_proj(ppg_encoded)

# 从码本检索最近的 ECG patch
dist = torch.cdist(projected, self.codebook.weight.unsqueeze(0))
indices = dist.argmin(dim=-1)
retrieved = self.codebook(indices)

# 解码为 ECG patch
ecg_patches = self.ecg_decoder(retrieved)
ecg_signal = ecg_patches.view(B, -1)

return ecg_signal, indices


def test_p2evq():
print("=" * 60)
print("P2E-VQ PPG→ECG 测试")
print("=" * 60)

model = P2EVQ(signal_length=2560, patch_size=64)

# 模拟 PPG 信号(10秒 @ 256Hz = 2560 samples)
ppg = torch.randn(2, 2560)

# 推理
ecg, indices = model.retrieve_from_ppg(ppg)

print(f"PPG 输入: {ppg.shape}")
print(f"ECG 输出: {ecg.shape}")
print(f"Patch 索引: {indices.shape}")
print(f"使用码本: {len(indices.unique())}/{512}")

total = sum(p.numel() for p in model.parameters())
print(f"参数量: {total / 1e6:.2f}M")

return model


if __name__ == "__main__":
test_p2evq()

3. IMS 开发启示

3.1 非接触心脏监测的突破

当前方案 P2E-VQ 增强 提升
rPPG → 心率 rPPG → ECG 波形 从数值到波形
心率±5bpm HRV+心律失常 新增能力
无心律检测 QRS 检测 新增能力
无 ST 段 ST 变化趋势 新增能力

3.2 部署架构

3.3 与 TU Braunschweig 方案互补

方案 传感器 信号 优势 局限
TU Braunschweig 方向盘 ECG 直接 ECG 精度高 需手接触
P2E-VQ rPPG 摄像头 重建 ECG 非接触 精度中等
融合方案 两者 直接+重建 互补覆盖 成本中

论文信息

  • arXiv: 2608.14656
  • 分类: eess.SP
  • 参考: Belhasin et al. (2025) 不确定性扩散 PPG→ECG