基于C语言实现的HRV分析方法 —— 与Kubios和MATLAB对比

基于C语言实现的HRV分析方法 ------ 与Kubios和MATLAB对比

本文简单记录了使用C语言实现HRV(心率变异性)的频域、时域和非线性分析 ,并与KubiosMATLAB软件结果进行了对比验证。

背景

本文是我帮一位朋友完成的一个小项目,主要目标是用C语言实现HRV的计算,将计算的结果返回以便进行疲劳、压力及抑郁等神经功能的分析。

HRV的分析内容包含时域、频域和非线性三个部分。本项目主要实现以下内容:

  1. RR间期预处理,RR间期预处理主要是将异常的RR间期进行处理,确保仅对窦性的心拍进行分析;
  2. HRV时域、频域和非线性结果计算。频域分析是三个分析的主要实现内容,分析方法包括FFT+Welch、AR和lomb-scargle三种。

在项目的实现中,所有内存均由外部传入,函数内部不进行动态分配,减少内存碎片,且便于调用者进行内存生命周期的控制,更安全。

实现流程

  1. 预处理。通过对RR间期进行预处理,将异常的间期,如过短/过长、房早及室早等进行剔除;
  2. 获取算法所需内存数量。通过接口传入预处理后的RR间期,以及频域分析方法,RR间期插值方法等获取需要的内存数量;
  3. HRV分析。调用者通过第二步获取的内存数量,申请一个内存块后,传入HRV分析接口进行三个HRV的分析,获取分析结果。

预处理技术

HRV是对窦性(NN)间期进行分析,所以在分析之前,需要对异常的间期进行处理。本算法中主要处理以下几种类型的异常间期:

  1. 长度无效间期。去除RR间期中,低于300ms和高于2000ms的间期;
  2. 房早/室早间期。通过提前+补偿的逻辑查找房早及室早间期,剔除这类型的间期;
  3. 异常间期。提出与整体RR间期比较时,出现间期差较大的异常间期。
c 复制代码
/**
 * @brief Preprocess the RR intervals. Remove outliers and interpolate missing values.
 * 
 * @param rr_in_ms      Pointer to the input RR intervals in milliseconds.
 * @param rr_len        Length of the RR intervals array. 
 *                      The value should not be less than MIN_RR_NUM.
 * @param invalid_ratio Pointer to a float to store the invalid ratio. 
 *                      The value should be between 0 and 1.- [基于C语言实现的HRV分析方法 ------ 与Kubios和MATLAB对比](#基于c语言实现的hrv分析方法--与kubios和matlab对比)
 *                      The percentage of invalid intervals to total intervals less than this ratio means
 *                      the preprocessing was successful. Otherwise, it failed. 
 *                      The default value is 0.05 if it is NULL.
 * 
 * @return int          1 on success.
 *                      0 on too many outliers and intervals invalid.
 *                      -1 on error.
 */
int HRVPreprocess(int16_t *rr_in_ms, uint32_t rr_len, float *invalid_ratio);

其中参数invalid_ratio表示可容忍的异常心拍比率,若异常心拍太多,说明RR间期序列的非窦性心拍太多,HRV的分析结果已无意义。

算法分析所需内存数量

在算法的实现中,不进行内存的申请,所有的内存均需要调用者在外部申请好内存块后传入。调用者通过RR间期、频域分析方法、插值方法(如需要)及AR分析方法(如需要)进行内存数量的计算。

c 复制代码
/**
 * @brief Get the size of the context for HRV analysis.
 * 
 * @param rr_clean_in_ms  Pointer to the cleaned RR intervals in milliseconds.
 * @param rr_len          Length of the cleaned RR intervals array.
 * @param psd_method      Method used for PSD calculation.
 *                        Options:
 *                        - PSD_FFT: FFT with Welch method
 *                        - PSD_AR: Autoregressive method
 *                        - PSD_LS: Lomb-Scargle 
 * @param interp_method   Method used for interpolation.
 *                        Options:
 *                        - INTERP_METHOD_LINEAR: Linear interpolation
 *                        - INTERP_METHOD_CUBIC: Cubic spline (default for PSD_FFT/PSD_AR if NULL)
 *                        The value is ignored if psd_method is PSD_LS and can be NULL in this case.
 * @param ar_method       Method used for autoregressive model.
 *                        Options:
 *                        - AR_YULE_WALKER: Yule-Walker method
 *                        - AR_BURG: Burg method (default for PSD_AR if NULL)
 *                        The value is ignored if psd_method is not PSD_AR and can be NULL in this case.
 * 
 * @return size_t         Size of the context in bytes.
 */
size_t HRVGetContextSize
(
    const int16_t *rr_clean_in_ms,
    uint32_t rr_len, 
    PSD_METHOD psd_method,
    INTERP_METHOD *interp_method,
    PSD_AR_METHOD *ar_method
);

频域分析方法有FFT、AR和lomb-scargle三种方法,RR间期插值有线性和三次样条两种方法,AR分析有Yule-Walker和Burg两种方法。总体来说,由于不需要进行RR间期插值和FFT变换,lomb-scargle所需的内存数量最少。

调用示例

调用示例如下所示,包含以下步骤:

  • 函数HRVPreprocess()预处理;
  • 通过函数HRVGetContextSize()获取算法所需内存的字节数,并申请内存;
  • 调用HRVAnalysis()函数进行HRV分析;
  • 释放申请的内存。
c 复制代码
    int16_t ms_arr[MAX_LEN] = {0};
    int count = load_rr_intervals("../matlab/rr.txt", ms_arr, 1000);

    if (HRVPreprocess(ms_arr, count, NULL) != 1) 
    {
        fprintf(stderr, "HRVPreprocess failed\n");
        return;
    }

    PSD_METHOD psd_method = PSD_FFT;
    INTERP_METHOD interp_method = INTERP_METHOD_CUBIC;

    size_t context_size = HRVGetContextSize(ms_arr, count, psd_method, &interp_method, NULL);
    uint8_t *context = (uint8_t *)malloc(context_size);
    if (NULL == context)
    {
        fprintf(stderr, "Failed to allocate memory for context\n");
        return;
    }

    FrequencyDomainFeatures fdf;
    TimeDomainFeatures tdf;
    PoincarePlotFeatures ppf;

    int ret = HRVAnalysis(
        ms_arr,
        count,
        context,
        context_size,
        psd_method,
        &interp_method,
        NULL,
        PSD_UNIT_SEC_SEC_HZ,
        &fdf,
        &tdf,
        &ppf
    );

    free(context);

频域分析方法

频域分析中,实现了FFT+Welch、AR和lomb-scargle三种,也是目前主流的HRV频域分析方法。

RR间期插值

在采用FFT+Welch或是AR的分析方法中,需要对RR间期进行插值,一般采用4Hz的重采样,这样得到的信号最高频率在2Hz,满足HRV分析的0~0.5Hz的要求。

插值方法中,算法实现了线性和三次样条两种插值方法。线性插值的优点是实现简单,缺点是不够平滑,可能会引入高频噪声,影响最后的分析结果;三次样条插值优点是曲线平滑,高频段更稳定,缺点是计算复杂度较高。如果条件允许,尽量选择三次样条插值方法,这也是Kubios默认的插值方法。

RR间期去趋势化

RR间期插值后,信号里存在低频趋势或是漂移,需要进行去趋势化。包含一次线性拟合、高阶多项式拟合等方法。本项目采用简单的减均值进行去趋势化。Kubios默认采用的是平滑先验(Smoothness Priors)正则化方法,由于内存问题,项目未实现该方法。

FFT变换库

项目采用开源的kissfft库,该库基于C语言编写,支持外部传入内存进行FFT变换计算。

FFT+Welch方法

FFT+Welch为最常用的HRV分析方法,是HRV中默认的分析方法。通过对信号进行叠加分段,每段分别做FFT后再进行平均,能有效减少随机噪声对谱估计的影响。得益于其快速、稳健及易实现的特点,FFT+Welch适用于大多数HRV的研究场景,尤其是短时间5分钟RR间期的分析。

AR方法

AR分析方法通过估计AR系数进行功率谱的计算。本项目采用Yule-Walker和Burg两种方法实现AR系数的计算,采用固定值为16的阶次。

Yule-Walker基于自相关函数的估计,具有实现简单,计算效率高等特点,但易受噪声的影响,可能出现谱泄露的情况,适用于信号较长且稳定,数据中噪声不大的情况。

Burg基于最小前向预测误差和后向预测误差,迭代估计AR系数。具有模型稳定,谱分辨率更高的特点,因而更适合短数据(如2分钟HRV片段),或是用于需要更平滑、分辨率更高的谱估计,是目前kubios软件中AR方法默认采用的分析方法。但由于采用前后向预测误差,所需的内存也更大。

Lomb-Scargle方法

lomb-scargle是一种专门针对非均匀采样数据的谱估计方法,与FFT和AR方法的最大区别是它不需要先对RR间期进行插值,直接用原始的非等间隔RR间期进行计算,从而避免了插值带来的伪信号,特别适合不规则RR间期数据或是有RR间期缺失的情况。

由于不涉及RR间期插值及FFT变换,仅对正弦和余弦基函数做加权拟合,lomb-scargle所需的内存是最少的。

三种方法适用场景

FFT+Welch为标准HRV分析,在时间长度大于等于5分钟时,应优先考虑该方法。

AR方法适用于时间较短的记录,如2~5分钟的情况。

Lomb-Scargle适用于RR间期不规则或RR间期有缺失,或是不希望插值对结果产生影响的情况。

时域和非线性分析

时域和非线性的分析较为简单,参数根据相应的公式进行计算即可。

结果对比

对MIT-BIH心律失常数据库的100号数据,取前5分钟的RR间期分析,然后与MATLAB和Kubios软件进行对比,检验结果是否准确。

与MATLAB对比

MATLAB对比主要是验证频域的分析结果,采用与MATLAB自带函数的结果进行对比的方法。FFT+Welch与pwelch、AR的Yule-Walker与pyulear、AR的Burg与pburg和Lomb-Scargle与plomb分别对比。

通过上图对比结果,算法频域分析的功率谱与MATLAB自带函数分析的结果基本相同。

与Kubios软件对比

Kubios是一款专业的HRV分析软件,由东芬兰大学的研究团队开发。它在临床研究、运动科学、生理学、心理学等领域被广泛使用,是HRV分析领域的权威工具之一。软件有收费版本Kubios HRV Scientific和免费版Kubios HRV Scientific Lite,本项目采用免费的Lite版本进行验证。

Kubios对比主要验证时域、频域和非线性的分析结果。由于Kubios的数据预处理方法不同,在Kubios中的输入为经过预处理完成的RR间期,且软件中去趋势化的选项中选择"None",Kubios会默认使用去均值。且由于使用的Kubios是免费的版本,频域分析中仅能对比FFT和AR的结果,无法对比Lomb-Scargle的结果。

时域和非线性结果对比

项目中,时域计算的参数与Kubios相同的有:Mean RR、SDNN、Mean HR、STD HR、Min HR、Max HR、RMSSD、NN50和pNN50;非线性相同的参数有:SD1、SD2和SD2/SD1。Kubios结果以及对比结果如下:

由上图对比可知,本项目算法在时域和非线性结果与Kubios的结果基本相同,在非线性的SD2参数上略有不同。但根据Kubios自己的计算公式(kubios.com/blog/hrv-analysis-methods/),SD2的计算结果应与算法的结果一致才对,由于差距不大,此处暂不处理。

频域结果对比

频域主要计算几个频段的能量,Kubios结果及对比结果如下:

由上图对比可知,FFT+Welch的结果与Kubios基本相同,由于Kubios的VLF频域范围是0到0.04Hz,标准的VLF范围为0.003到0.04Hz,项目采用标准VLF范围,所以在VLF部分的差别相对较大。对于AR的结果同理,除了VLF的差别较大外,其他参数的差别控制在6%以内。

总结

本项目基于C语言实现了HRV的分析,算法通过接收传入的RR间期序列,预处理去除不符合要求的RR间期后,进行HRV时域、频域和非线性的分析,最后将分析结果返回给调用者。

算法在进行频域相关参数计算时,调用者可选择功率谱计算所需的方法:FFT+Welch、AR(可选Yule-Walker和Burg两种)和Lomb-Scargle,在FFT和AR方法上,可以选择RR间期的插值方式:线性插值和三次样条插值,功率谱单位可选:ms*ms/Hz和s*s/Hz。

算法分析结果通过与MATLAB和Kubios软件的结果进行对比,显示结果基本一致,证明算法准确性较高。

参考资料

  1. Malik, M. (1996). Heart rate variability: Standards of measurement, physiological interpretation, and clinical use: Task force of the European Society of Cardiology and the North American Society for Pacing and Electrophysiology. Annals of Noninvasive Electrocardiology, 1(2), 151-181.
  2. github.com/mborgerding...
  3. MathWorks, Inc. pwelch (Power Spectral Density using Welch method) . www.mathworks.com/help/signal...
  4. MathWorks, Inc. pyulear (Power Spectral Density using Yule-Walker AR method) . www.mathworks.com/help/signal...
  5. MathWorks, Inc. pburg (Power Spectral Density using Burg method) . www.mathworks.com/help/signal...
  6. MathWorks, Inc. plomb (Lomb--Scargle Power Spectrum) . www.mathworks.com/help/signal...
  7. Kubios Oy. Kubios HRV Software . www.kubios.com/
相关推荐
No0d1es2 小时前
电子学会青少年软件编程(C/C++)5级等级考试真题试卷(2024年6月)
c语言·c++·算法·青少年编程·电子学会·五级
大阳1234 小时前
线程(基本概念和相关命令)
开发语言·数据结构·经验分享·算法·线程·学习经验
weixin_307779135 小时前
VS Code配置MinGW64编译GNU 科学库 (GSL)
开发语言·c++·vscode·算法
学行库小秘6 小时前
ANN神经网络回归预测模型
人工智能·python·深度学习·神经网络·算法·机器学习·回归
秋难降6 小时前
线段树的深度解析(最长递增子序列类解题步骤)
数据结构·python·算法
楚韵天工6 小时前
基于GIS的无人机模拟飞行控制系统设计与实现
深度学习·算法·深度优先·无人机·广度优先·迭代加深·图搜索算法
你也向往长安城吗7 小时前
推荐一个三维导航库:three-pathfinding-3d
javascript·算法
百度智能云8 小时前
VectorDB+FastGPT一站式构建:智能知识库与企业级对话系统实战
算法
AI小白的Python之路9 小时前
数据结构与算法-排序
数据结构·算法·排序算法