[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This program reads a single ECG signal, attempts to detect QRS complexes, and records their locations in an annotation file. The detector algorithm is based on a Pascal program written by W.A.H. Engelse and C. Zeelenberg, "A single scan algorithm for QRS-detection and feature extraction", Computers in Cardiology 6:37-42 (1979).
1 #include <stdio.h> 2 #include <wfdb/wfdb.h> 3 #include <wfdb/ecgcodes.h> 4 5 #define abs(A) ((A) >= 0 ? (A) : -(A)) 6 7 main(argc, argv) 8 int argc; 9 char *argv[]; 10 { 11 int filter, time=0, slopecrit, sign, maxslope=0, nsig, nslope=0, 12 qtime, maxtime, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, 13 ms160, ms200, s2, scmax, scmin = 0; 14 WFDB_Anninfo a; 15 WFDB_Annotation annot; 16 WFDB_Sample *v; 17 WFDB_Siginfo *s; 18 19 if (argc < 2) { 20 fprintf(stderr, "usage: %s record [threshold]\n", argv[0]); 21 exit(1); 22 } 23 a.name = "qrs"; a.stat = WFDB_WRITE; 24 25 if ((nsig = isigopen(argv[1], NULL, 0)) < 1) exit(2); 26 s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); 27 v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); 28 if (s == NULL || v == NULL) { 29 fprintf(stderr, "%s: insufficient memory\n", argv[0]); 30 exit(2); 31 } 32 if (wfdbinit(argv[1], &a, 1, s, nsig) != nsig) exit(2); 33 if (sampfreq((char *)NULL) < 240. || 34 sampfreq((char *)NULL) > 260.) 35 setifreq(250.); 36 if (argc > 2) scmin = muvadu(0, atoi(argv[2])); 37 if (scmin < 1) scmin = muvadu(0, 1000); 38 slopecrit = scmax = 10 * scmin; 39 ms160 = strtim("0.16"); ms200 = strtim("0.2"); s2 = strtim("2"); 40 annot.subtyp = annot.chan = annot.num = 0; annot.aux = NULL; 41 (void)getvec(v); 42 t9 = t8 = t7 = t6 = t5 = t4 = t3 = t2 = t1 = v[0]; 43 44 do { 45 filter = (t0 = v[0]) + 4*t1 + 6*t2 + 4*t3 + t4 46 - t5 - 4*t6 - 6*t7 - 4*t8 - t9; 47 if (time % s2 == 0) { 48 if (nslope == 0) { 49 slopecrit -= slopecrit >> 4; 50 if (slopecrit < scmin) slopecrit = scmin; 51 } 52 else if (nslope >= 5) { 53 slopecrit += slopecrit >> 4; 54 if (slopecrit > scmax) slopecrit = scmax; 55 } 56 } 57 if (nslope == 0 && abs(filter) > slopecrit) { 58 nslope = 1; maxtime = ms160; 59 sign = (filter > 0) ? 1 : -1; 60 qtime = time; 61 } 62 if (nslope != 0) { 63 if (filter * sign < -slopecrit) { 64 sign = -sign; 65 maxtime = (++nslope > 4) ? ms200 : ms160; 66 } 67 else if (filter * sign > slopecrit && 68 abs(filter) > maxslope) 69 maxslope = abs(filter); 70 if (maxtime-- < 0) { 71 if (2 <= nslope && nslope <= 4) { 72 slopecrit += ((maxslope>>2) - slopecrit) >> 3; 73 if (slopecrit < scmin) slopecrit = scmin; 74 else if (slopecrit > scmax) slopecrit = scmax; 75 annot.time = strtim("i") - (time - qtime) - 4; 76 annot.anntyp = NORMAL; (void)putann(0, &annot); 77 time = 0; 78 } 79 else if (nslope >= 5) { 80 annot.time = strtim("i") - (time - qtime) - 4; 81 annot.anntyp = ARFCT; (void)putann(0, &annot); 82 } 83 nslope = 0; 84 } 85 } 86 t9 = t8; t8 = t7; t7 = t6; t6 = t5; t5 = t4; 87 t4 = t3; t3 = t2; t2 = t1; t1 = t0; time++; 88 } while (getvec(v) > 0); 89 90 wfdbquit(); 91 exit(0); 92 } |
(See http://www.physionet.org/physiotools/wfdb/examples/example10.c for a copy of this program.)
Notes:
setifreq
to specify that we want getvec
to give us data resampled at 250 Hz.
scmin
and scmax
are lower and
upper bounds for the adaptive threshold slopecrit
.
slopecrit
is set to 15/16 of its
previous value if no slopes have been found; in line 53, it is set to
17/16 of its previous value if 5 or more slopes were found (suggesting
the presence of noise).
maxtime
to 160 msec, and save the sign of the slope and the current
time relative to the previous beat.
maxslope
(lines 67--69) for eventual use in updating
the threshold (lines 72--74). Once a sufficient interval has elapsed
following the last threshold crossing (line 70), if there were between
2 and 4 slopes, we have (apparently) found a QRS complex, and the program
records a NORMAL
annotation (lines 75--76). If there were 5 or more
slopes, the program records an artifact annotation (lines 80--81). If
only 1 slope was found, it is assumed to represent a baseline shift and
no output is produced.
tn
variables and another sample is read.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |