基于C语言实现的HRV分析方法 ------ 与Kubios和MATLAB对比
本文简单记录了使用C语言实现HRV(心率变异性)的频域、时域和非线性分析 ,并与Kubios 和MATLAB软件结果进行了对比验证。
背景
本文是我帮一位朋友完成的一个小项目,主要目标是用C语言实现HRV的计算,将计算的结果返回以便进行疲劳、压力及抑郁等神经功能的分析。
HRV的分析内容包含时域、频域和非线性三个部分。本项目主要实现以下内容:
- RR间期预处理,RR间期预处理主要是将异常的RR间期进行处理,确保仅对窦性的心拍进行分析;
- HRV时域、频域和非线性结果计算。频域分析是三个分析的主要实现内容,分析方法包括FFT+Welch、AR和lomb-scargle三种。
在项目的实现中,所有内存均由外部传入,函数内部不进行动态分配,减少内存碎片,且便于调用者进行内存生命周期的控制,更安全。
实现流程
- 预处理。通过对RR间期进行预处理,将异常的间期,如过短/过长、房早及室早等进行剔除;
- 获取算法所需内存数量。通过接口传入预处理后的RR间期,以及频域分析方法,RR间期插值方法等获取需要的内存数量;
- HRV分析。调用者通过第二步获取的内存数量,申请一个内存块后,传入HRV分析接口进行三个HRV的分析,获取分析结果。
预处理技术
HRV是对窦性(NN)间期进行分析,所以在分析之前,需要对异常的间期进行处理。本算法中主要处理以下几种类型的异常间期:
- 长度无效间期。去除RR间期中,低于300ms和高于2000ms的间期;
- 房早/室早间期。通过提前+补偿的逻辑查找房早及室早间期,剔除这类型的间期;
- 异常间期。提出与整体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软件的结果进行对比,显示结果基本一致,证明算法准确性较高。
参考资料
- 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.
- github.com/mborgerding...
- MathWorks, Inc. pwelch (Power Spectral Density using Welch method) . www.mathworks.com/help/signal...
- MathWorks, Inc. pyulear (Power Spectral Density using Yule-Walker AR method) . www.mathworks.com/help/signal...
- MathWorks, Inc. pburg (Power Spectral Density using Burg method) . www.mathworks.com/help/signal...
- MathWorks, Inc. plomb (Lomb--Scargle Power Spectrum) . www.mathworks.com/help/signal...
- Kubios Oy. Kubios HRV Software . www.kubios.com/