1. 血氧检测中的心率算法设计
在可穿戴设备和医疗监测设备中,血氧饱和度(SpO2)和心率(HR)是两个最基础也最重要的生命体征参数。作为一名嵌入式开发者,我曾经参与过多个基于GD32和STM32系列单片机的血氧仪项目,今天想和大家分享一下心率算法设计中的核心要点,特别是峰峰值检测算法的实现细节和优化思路。
从实际项目经验来看,红外(IR)信号由于其交流(AC)分量更大,信噪比更高,通常比红光信号更适合用于心率计算。上图展示的波形中,蓝色IR信号明显比红色红光信号具有更清晰的脉搏波形特征。这也是为什么在大多数实际产品中,我们会优先选择IR信号作为心率计算的主要数据源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础峰峰值检测算法
2.1 算法原理与实现
最基本的峰峰值检测算法通常包含以下几个步骤:
- 信号预处理(滤波去噪)
- 寻找局部极大值和极小值
- 计算峰峰值(相邻极大值与极小值的差值)
- 心率计算(基于峰峰间隔时间)
在嵌入式环境中,考虑到资源限制,我们通常会使用IIR(Infinite Impulse Response)滤波器而非FIR滤波器,因为IIR滤波器可以用更少的计算资源达到相似的滤波效果。典型的实现代码如下:
c复制// 简易IIR低通滤波器实现
float IIR_Filter(float input, float *prev_output, float alpha) {
float output = alpha * input + (1 - alpha) * (*prev_output);
*prev_output = output;
return output;
}
2.2 阈值设定的关键考量
阈值设定是峰峰值检测中最容易出问题的环节。根据人体生理特征,正常成年人的心率范围通常在60-100bpm(每分钟心跳次数),运动员可能低至40bpm,而剧烈运动时可能高达200bpm。这个生理范围约束了我们的算法参数设计。
假设采样频率为100Hz(即每秒100个采样点),那么:
- 对于40bpm的心率:每个心跳周期约150个采样点
- 对于200bpm的心率:每个心跳周期约30个采样点
因此,我们的算法需要能够在这个动态范围内稳定工作。初始实现中,很多开发者会采用简单的80%幅值作为阈值:
c复制peak_threshold = (max_v + min_v) / 2 * 0.8;
但这种简单方法在实际应用中会遇到很多问题,特别是在处理脉搏波顶端的"肩峰"或"重搏波"时。
3. 算法优化与问题解决
3.1 原始算法的问题分析
在实际测试中,我们发现原始算法存在几个明显问题:
-
双峰误检:脉搏波顶端常常会出现"肩峰"现象,简单的阈值法会将同一心跳周期内的肩峰误检为第二个峰,导致计算出的心率值偏高。
-
相位延迟:IIR滤波器虽然能有效降噪,但会引入相位延迟,影响峰值的准确定位。
-
动态适应性差:固定比例的阈值无法适应信号幅度的动态变化,在信号较弱时容易漏检,信号较强时又容易误检。
3.2 改进方案设计
针对上述问题,我们设计了一个基于状态机的改进
