资讯详情

PulseSensor开发文档(二)动态阈值算法获取心率值

文章目录

    • 1、摘要
    • 2.算法核心思想和心率信号的有效特征
    • 3.动态阈值算法分为思维分析
    • 4.算法的整体实现
    • 5.算法实现效果
    • 6、小结

1、摘要

上一篇文章具体介绍了如何使用DMA和ADC收集心电数据并上传到上位机。在收集心电数据后,微处理器需要做的是将数据转换为可分析的生理指标心率。顾名思义,心率是指一分钟内的心跳次数。传统的心率计算方法是计时一分钟,测量一分钟内产生多少脉搏。这种做法的缺点很明显,一是效率很低,每次心率测量的时间间隔很长,二是容易分析错误,可能会忽略一些关键数据点。为了解决这种方法的缺点,本文将介绍一种心率分析算法:动态阈值算法,从采样的心电信号中分析实时心率,并将实时心率大小上传到上位机进行观察。

2.算法核心思想和心率信号的有效特征

算法的核心思想是测量相邻两个脉搏的时间间隔,然后用心率的单位时间(一分钟)除以这个时间间隔来获得心率。基于这种心率分析算法,可以在心率信号中获得两个有效的特征点

  • IBI(Inter-Beat Intervals):心搏间隔是指两次有效脉搏之间的时间间隔。ms。心电图中的标记如下图所示(有多种选择标准,效果相同): 在这里插入图片描述

  • BPM(Beat Per Minute):每分钟节拍数,这里指的是心率值IBI两者之间的转换关系是BPM = 60000 / IBI;

3.动态阈值算法分为思维分析

无论采用传统传统方法和动态阈值算法,只有识别一个脉搏,才能在一分钟内计算脉搏数或两个相邻脉搏之间的时间间隔。我们立即想到的方法可能是从收集的电压波形数据中识别峰/谷,并在程序中人工设置阈值。当读取的电压数据超过此阈值时,系统可以认为检测到脉搏。该方法在应对输出的电压波形相对完整时是可行的(峰谷值相对稳定,波形频率重量较小),但在心率计算中,这种测量会与实际心率产生较大的误差,原因如下:

  • 心电波形电压输出不稳定,振幅大小,极易变化;
  • 心电波形含有较多的频率重量,采用常规方法计算容易识别无效波形,导致结果与真实值之间的偏差。

由于固定阈值的方法不可取,因此自然会考虑根据信号振幅调整阈值以适应不同信号的峰值检测。通过对一个周期内的信号进行多次采样,得到信号的最高和最低电压值,从而计算阈值,然后判断采集的电压值是否为峰值。也就是说,电压信号的处理分为两个步骤。首先计算参考阈值,然后用阈值确定电压信号,识别峰值,如下图所示:

以上是计算有效波形的有效波形IBI只需要一点。需要从有效信号中选择特征点,其性质是:每个有效波形只有一个特征点,代表有效脉搏,只要能识别特征点,就能触发任何动作(如计数、记录特征点时间)。通过记录两个相邻特征点的时间并寻求差值来计算IBI在本节中,我们将选择心电波形上升到振幅的一半作为特征点。我们可以捕获这个特征点,记录捕获时间,然后计算它IBI。

4.算法的整体实现

动态阈值算法的总体思路如下:

  1. 在波形周期中缓存多次采样值,找出最大最小值,计算振幅中间值作为信号判定阈值;
  2. 将当前采样值与上一采样值与阈值进行比较,找出信号上升到振幅中间位置的特征点,记录当前时间;
  3. 找到下一个特征点并记录时间,计算两个点的时差,即相邻两个脉搏的时间间隔IBI;
  4. 由IBI计算心率值BPM;

算法代码实现如下:

/** *@brief 寻找当前数组的最大值 *@attention 无 *@param data[] 16.无符号整形数组 *@retval 目前数组最大值 */ static uint16_t MaxElement(uint16_t data[]) { 
             uint8_t i;     uint16_t max = data[0];     for(i = 1; i < Size; i )     { 
                 if(data[i] >= max)         { 
                     max = data[i];         }     }     return max; }  /** *@brief 寻找当前数组的最小值 *@attention 无 *@param data[] 16.无符号整形数组 *@retval 目前数组最小值 */ static uint16_t MinElement(uint16_t data[])
{ 
        
    uint8_t i;
    uint16_t min = data[0];
    for(i = 1; i < Size; i++)
    { 
        
        if(data[i] <= min)
        { 
        
            min = data[i];
        }
    }
    return min;
}
    
/** *@brief 计算心率函数 *@attention 在主函数中以15Hz频率工作 *@param data 16位无符号整形数据 *@retval 无 */
void Rate_Calculate(uint16_t data)
{ 
        
    static uint8_t index; //当前数组下标
    static uint8_t pulseflag; //特征点数目
    static uint16_t Input_Data[Size]; //缓存数据数组
    static uint16_t predata, redata; //一个波形周期内读取上一次值、当前值 
    uint16_t Maxdata, Mindata; //最大值,最小值
    static uint16_t Middata; //平均值
    static uint16_t range = 1024; //幅度
    static uint8_t prepulse, pulse; //衡量指标值,用以标记特征点
    static uint16_t time1, time2, time; //检测时间
    uint16_t IBI, BIM; //两个特征点间隔时间,心率大小
    
    predata = redata; //保存上一次的值
    redata = data; //读取当前值
    if(redata - predata < range) //滤除突变噪声信号干扰
    { 
        
        Input_Data[index] = redata; //填充缓存数组
        index++;
    }
    if(index >= Size)
    { 
        
        index = 0; //覆盖数组
        Maxdata = MaxElement(Input_Data); 
        Mindata = MinElement(Input_Data);
        Middata = (Maxdata + Mindata) / 2; //更新参考阈值
        range = (Maxdata - Mindata) / 2; //更新突变阈值
    }
    
    prepulse = pulse; //保存当前脉冲状态
    pulse = (redata > Middata) ? 1 : 0; //采样值大于中间值为有效脉冲
    if(prepulse == 0 && pulse == 1) //当检测到两个有效脉冲时为一个有效心率周期
    { 
        
        pulseflag++;
        pulseflag = pulseflag % 2;
        
        if(pulseflag == 1) //检测到第一个有效脉冲
        { 
        
            time1 = time; //标记第一个特征点检测时间
        }
        if(pulseflag == 0) //检测到第二个有效脉冲
        { 
        
            time2 = time; //标记第二个特征点检测时间
            time = 0; //清空计时
          if(time1 < time2)
            { 
        
                IBI = (time2 - time1) * Period; //计算两个有效脉冲的时间间隔(单位:ms)
                BIM = 60000 / IBI; //1分钟有60000ms
                /**限制BIM最高/最低值*/
                if(BIM > 200)
                { 
        
                    BIM = 200;
                }
                if(BIM < 30)
                { 
        
                    BIM = 30;
                }
                printf("Currented Heart Rate:%d ", BIM);
            }
        }
    }
    time++;
}

注意事项:

5、算法实现效果

按照正确的操作测量得到的心率数据在上位机中显示如下: 所测量的数据会自动保存在指定路径的txt文档中:

6、小结

本节介绍了采用动态阈值算法获取心率值的核心思想以及实现步骤,较为精确地测量出了实时心率数据。下一节将会介绍上位机的具体实现。

标签: 传感器固定阈值

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台