ECG 注释 C++ 库






4.91/5 (32投票s)
本文介绍的 electrocardiogram (ECG) 标注 C++ 库基于小波分析和控制台应用程序,用于从 ECG 数据中提取重要的间隔和波形 (P, T, QRS, PQ, QT, RR, RRn),以及异位搏动和噪声检测。
- 下载海报 - 545.5 KB
- 下载 EcgAnnotation 演示项目 - 167.1 KB
- 下载 EcgAnnotation 源代码 - 41.3 KB
- 下载 EcgAnnotation 演示项目 (更新 1) - 108.3 KB
- 下载 EcgAnnotation 源代码 (更新 1) - 13.7 KB
- 下载 EcgAnnotation 演示项目 (更新 1.1) - 108.4 KB
- 下载 EcgAnnotation 源代码 (更新 1.1) - 14.5 KB

引言
对于关心心脏健康的人们以及在该领域进行研究的学者们,我想介绍我在攻读博士学位期间花了数年时间开发的 ECG 标注库。去年,我在剑桥大学的博士后研究期间改进了其标注质量。事实证明,这项工作并非徒劳,我在 Physionet Computers In Cardiology 2006 QT Annotation challenge 中获得了第一名。您也可以在 physionet 源代码 中查看该库的早期版本。描述该算法的论文在线可查阅 Individually Adaptable Automatic QT Detector. Computers in Cardiology 2006. V. 33. PP. 337-341。您可以在本文顶部下载的会议海报(Power Point 2007)中查看。
我为该库提供了一个控制台应用程序,因此您可以使用您的 ECG 数据并对其进行标注。您的数据应为 Physionet ECG 格式,请参阅 网站 获取可将文本数据文件转换为此格式的工具。
背景
如果您想扩展或修改代码,或者使用我库中提供的小波变换类,您应该具备心脏病学基础知识,熟悉 physionet ECG 数据格式,并可选地熟悉 C++ 编程和小波分析。Robi Polikar 提供了一篇关于小波变换的精彩在线教程:Robi Polikar 的教程。
Using the Code
要标注 ECG 文件,只需按此方式运行控制台应用程序(例如,我包含了来自 afpdb 数据库的 physionet 文件 *n26c.dat* 及其头文件 *n26c.hea*)。
>ecg.exe n26c.dat 1
这将标注记录的第一个导联。
>ecg.exe n26c.dat 2
要标注第二个导联,以此类推。
完成后,ECG 标注(包括 P、T、QRS 波、异位搏动和噪声)将打印到 stdout 并保存到 *n26c.atr* Physionet 兼容标注文件中。HRV 数据也将以文本格式保存到 *n26c.hrv* 文件中,平均心率将显示在 stdout 上。要查看带有标注的 ECG 记录,您可以浏览 physionet 工具。我将考虑发布一个简单的 GUI 来查看记录和标注。
由于记录可能持续时间很长,stdout 的输出速度会很慢,因此您可以将其重定向到文件以加快处理速度。
>ecg.exe n26c.dat 1 >output
用于指定最小、最大 ECG 波的间隔、持续时间等的 ECG 标注参数已设置为默认值。我可能会发布一个带有外部设置的修改版,供控制台使用,以适应特定的 ECG 形态,否则您可以自己修改,将其传递给 EcgAnnotation
构造函数。
库中包含的类有:
信号
CWT : public Signal
FWT : public Signal
EcgDenoise : public FWT
EcgAnnotation : public Signal
Signal
类提供以文本、physionet 和我自定义文件格式读取 ECG 数据、将其保存到磁盘、数据归一化例程、去噪操作和一些数学函数。请查看 *signal.h* 文件。
CWT
类提供连续小波变换。它配备了常见的母小波(Mehihan Hat、Morlet、高斯导数)。您可以这样使用它:
double SR; //signal sampling rate
double w0; //parameter for full Morlet wavelet
double* Data; //your data signal
int size; //size of your signal for analysis
double* pSpec; //pointer to the CWT spectrum
CWT cwt;
cwt.InitCWT(size, CWT::MHAT, w0, SR); //init it with Mexihan Hat wavelet
pSpec = cwt->CwtTrans(Data, 30.0); //to transform Data on 30.0Hz
pSpec = cwt->CwtTrans(Data, 45.56); //to transform Data on 45.56Hz
// and so on ...
// size of the spectrum pSpec equals to signal size
cwt.CloseCWT(); //close it
FWT
类提供一维快速小波变换。您可以以与 CWT
类似的方式使用它。
wchar_t filter[] = L"path\\filters\\daub2.flt"; //full path to the filter
FWT fwt;
fwt.InitFWT(filter, Data, size); //init it with Daub2 wavelet
fwt.FwtTrans(3); //3 level FWT transform
//meddle with FWT spectrum
pSpec = GetFwtSpectrum();
fwt.FwtSynth(3); //3 level FWT reconstruction
fwt.CloseFWT(); //close it
EcgDenoise
旨在通过快速小波变换对 ECG 信号进行去噪。
wchar_t path[] = L"fullpath\\filters"; //full path to the filters dir
EcgDenoise enoise;
enoise.InitDenoise(path, Data, size, SR);
enoise.LFDenoise(); //baseline wander removal
enoise.HFDenoise(); //high frequency noise removal
enoise.LFHFDenoise(); //both noises removal
enoise.CloseDenoise(); //close it
初始化后,您可以根据需要调用去噪函数任意次数并按任意顺序调用。每次您的 Data
都将填充去噪后的信号版本。
EcgAnnotation
是用于完整 ECG 标注的类。以下是我的控制台应用程序中用于标注 ECG 数据并保存结果的代码:
class Signal signal;
if (signal.ReadFile(argv[1])) {
int size = signal.GetLength();
double sr = signal.GetSR();
int h, m, s, ms;
int msec = int(((double)size / sr) * 1000.0);
signal.mSecToTime(msec, h, m, s, ms);
wprintf(L" leads: %d\n", signal.GetLeadsNum());
wprintf(L" sr: %.2lf Hz\n", sr);
wprintf(L" bits: %d\n", signal.GetBits());
wprintf(L" UmV: %d\n", signal.GetUmV());
wprintf(L" length: %02d:%02d:%02d.%03d\n\n", h, m, s, ms);
double* data = signal.GetData(leadNumber);
//annotation
class EcgAnnotation ann; //default annotation params
//or add your custom ECG params to annotation class from lib.h
// ANNHDR hdr;
// hdr.minbpm = 30;
// etc...
// class EcgAnnotation ann( &hdr );
wprintf(L" getting QRS complexes... ");
tic();
//get QRS complexes
int** qrsAnn = ann.GetQRS(data, size, sr, L"filters");
//qrsAnn = ann->GetQRS(psig, size, SR, L"filters", qNOISE);
//get QRS complexes if signal is quite noisy
if (qrsAnn) {
wprintf(L" %d beats.\n", ann.GetQrsNumber());
//label Ectopic beats
ann.GetEctopics(qrsAnn, ann.GetQrsNumber(), sr);
wprintf(L" getting P, T waves... ");
int annNum = 0;
int** ANN = ann.GetPTU(data, size, sr, L"filters",
qrsAnn, ann.GetQrsNumber()); //find P,T waves
if (ANN) {
annNum = ann.GetEcgAnnotationSize();
wprintf(L" done.\n");
toc();
wprintf(L"\n");
//save ECG annotation
wcscpy(annName, argv[1]);
change_extension(annName, L".atr");
ann.SaveAnnotation(annName, ANN, annNum);
} else {
ANN = qrsAnn;
annNum = 2 * ann.GetQrsNumber();
wprintf(L" failed.\n");
toc();
wprintf(L"\n");
}
//printing out annotation
for (int i = 0; i < annNum; i++) {
int smpl = ANN[i][0];
int type = ANN[i][1];
msec = int(((double)smpl / sr) * 1000.0);
signal.mSecToTime(msec, h, m, s, ms);
wprintf(L"%10d %02d:%02d:%02d.%03d %s\n",
smpl, h, m, s, ms, anncodes[type]);
}
//saving RR seq
vector<double /> rrs;
vector<int> rrsPos;
wcscpy(hrvName, argv[1]);
change_extension(hrvName, L".hrv");
if (ann.GetRRseq(ANN, annNum, sr, &rrs, &rrsPos)) {
FILE *fp = _wfopen(hrvName, L"wt");
for (int i = 0; i < (int)rrs.size(); i++)
fwprintf(fp, L"%lf\n", rrs[i]);
fclose(fp);
wprintf(L"\n mean heart rate: %.2lf",
signal.Mean(&rrs[0], (int)rrs.size()));
}
} else {
wprintf(L"could not get QRS complexes.
make sure you have got \"filters\"
directory in the ecg application dir.");
exit(1);
}
} else {
wprintf(L"failed to read %s file", argv[1]);
exit(1);
}
历史
更新 1.0 - 2007 年 10 月 28 日
在我的代码的用户研究人员要求我提供更精确的双相 T 波标注并通过外部文件读取标注参数后,我修改了控制台代码和 EcgAnnotation
类。现在您可以在参数文件 *biTwave* 中将最后一个设置从 0 更改为 1 以处理双相 T 波。更改涉及 EcgAnnotation::GetPTU()
函数,我在其中添加了高斯 CWT 滤波器用于标注双相 T 波。

您可以运行控制台,并提供一个额外的可选第三个参数,即包含您特定标注设置的文件名。
>ecg.exe patient1.dat 1 patient1params
>ecg.exe patient2.dat 1 patient2biTwave
>ecg.exe patient3.dat 2 patient3largeTwaves
更新 1.1 - 2007 年 10 月 29 日
此更新提供了从外部文件加载的附加参数。将 ampQRS 设置为 1,您可以在检测过程中预先放大 QRS 波群。qrsFreq 表示 CWT 变换的滤波频率,默认为 13Hz。上述更改允许处理异常 ECG,如下所示。如您所见,T 波是双相的,峰形与 QRS 非常相似。使用默认参数,您无法过滤掉这种 T 波,它会产生虚假的噪声或其他搏动的检测。实际心率是 160 bpm,相当高。要处理此类异常,您需要将 qrsFreq 滤波频率提高到大约 25Hz,并预先放大 QRS 波群 ampQRS = 1。通过这些设置,此类 T 波将被成功过滤掉,QRS 检测阶段将完美无缺。

现在配置文件包含以下字段:
minbpm 40
maxbpm 180
minQRS 0.04
maxQRS 0.2
qrsFreq 13
ampQRS 0
minUmV 0.2
minPQ 0.07
maxPQ 0.20
minQT 0.22
maxQT 0.45
pFreq 9.0
tFreq 3.0
biTwave 0