1. 可穿戴设备心率数据采集与实时显示
PPG 心率采集链路与实时刷新机制
智能手表上的 PPG(光电容积脉搏波)心率采集,本质是一条从光学前端到界面刷新的完整信号链。要让界面上的心率值稳定跳动,需要同时打通四个环节:光学驱动与采样、原始信号预处理、心率估计、UI 刷新。任何一环的采样率、缓冲长度或刷新周期设置不当,都会表现为数值跳变、长时间不变或干脆无数据。
采集与刷新实现要点
下面以智能手表常见的嵌入式环境为例,给出采集到显示的关键实现。核心思路是:传感器中断驱动采样,环形缓冲累积数据,定时器触发心率计算与 UI 刷新。
// 心率采集与显示核心逻辑(伪代码,适配嵌入式环境)
#define PPG_SAMPLE_RATE 25 // Hz
#define PPG_BUFFER_SIZE 128 // 约 5.1 s 数据
#define UI_REFRESH_MS 1000 // 1 s 刷新一次
static uint16_t ppg_buffer[PPG_BUFFER_SIZE];
static volatile uint16_t buf_index = 0;
static volatile bool data_ready = false;
// 1. PPG 传感器中断:每 40 ms 触发一次(25 Hz)
void ppg_sensor_isr(uint16_t raw_value) {
ppg_buffer[buf_index] = raw_value;
buf_index = (buf_index + 1) % PPG_BUFFER_SIZE;
if (buf_index == 0) {
data_ready = true; // 缓冲满,通知主循环
}
}
// 2. 带通滤波 + 峰值检测,估算心率
uint16_t estimate_heart_rate(void) {
// 去直流:减去滑动均值
uint32_t sum = 0;
for (int i = 0; i < PPG_BUFFER_SIZE; i++) sum += ppg_buffer[i];
uint16_t dc = sum / PPG_BUFFER_SIZE;
// 简单带通:保留 0.5–5 Hz 成分(此处用差分近似)
int16_t filtered[PPG_BUFFER_SIZE];
for (int i = 1; i < PPG_BUFFER_SIZE; i++) {
filtered[i] = (int16_t)ppg_buffer[i] - (int16_t)ppg_buffer[i-1];
}
// 峰值检测:找局部最大值,计算 IBI
uint32_t ibi_sum = 0;
uint16_t ibi_count = 0;
uint32_t last_peak = 0;
for (int i = 2; i < PPG_BUFFER_SIZE - 2; i++) {
if (filtered[i] > filtered[i-1] && filtered[i] > filtered[i+1]
&& filtered[i] > 50) { // 阈值可调
if (last_peak > 0) {
ibi_sum += (i - last_peak);
ibi_count++;
}
last_peak = i;
}
}
if (ibi_count == 0) return 0; // 无有效峰值
// IBI 单位:采样点数 → 秒
float avg_ibi_sec = (float)ibi_sum / ibi_count / PPG_SAMPLE_RATE;
return (uint16_t)(60.0f / avg_ibi_sec); // BPM
}
// 3. 主循环:定时刷新 UI
void main_loop(void) {
uint32_t last_refresh = 0;
while (1) {
uint32_t now = get_tick_ms();
if (data_ready && (now - last_refresh >= UI_REFRESH_MS)) {
data_ready = false;
uint16_t bpm = estimate_heart_rate();
if (bpm >= 30 && bpm <= 220) {
ui_set_heart_rate(bpm); // 有效值显示
} else {
ui_set_heart_rate(0); // 无效值显示 "--"
}
last_refresh = now;
}
}
}
验证采集链路是否正常:用手指轻按传感器,观察 UI 心率值是否在 1 s 内更新;若长时间显示 "--",检查中断是否触发、缓冲是否填满、峰值阈值是否过高。正常静息状态下,心率应在 60–100 BPM 范围内波动,且相邻两次刷新差值不超过 5 BPM。
常见问题:采样率低于 25 Hz 时,PPG 峰值间隔分辨率不足,心率估计误差会明显增大;缓冲长度小于 4 s 时,IBI 统计样本太少,数值容易跳变。运动状态下光信号受伪影干扰,可临时增大峰值阈值或暂停刷新,避免显示错误心率。
关键参数与刷新机制对照
| 参数 | 推荐值 | 作用 | 异常表现 |
|---|---|---|---|
| 采样率 | 25 Hz | 保证 PPG 峰值可分辨 | 低于 15 Hz 时心率误差 > 10 BPM |
| 缓冲长度 | 128 点(约 5.1 s) | 提供足够 IBI 统计样本 | 过短导致数值频繁跳变 |
| 刷新周期 | 1 s | 兼顾实时性与可读性 | 过快闪烁,过慢失去实时感 |
| 峰值阈值 | 50(可调) | 过滤噪声引起的假峰 | 过高漏检,过低误检 |
| 有效心率范围 | 30–220 BPM | 排除无效计算结果 | 超出范围显示 "--" |
完成上述实现后,可通过以下方式确认链路与刷新机制均已生效:用手指稳定按压传感器,观察 UI 心率值是否每秒更新一次;改变按压力度或轻微移动手指,观察数值是否出现合理波动而非固定不变;若数值持续为 "--",则回到中断触发和缓冲填充环节逐级排查。