FINT wfdbinit(char *record, WFDB_Anninfo *aiarray, unsigned int nann, WFDB_Siginfo *siarray, unsigned int nsig) { int stat; if ((stat = annopen(record, aiarray, nann)) == 0) stat = isigopen(record, siarray, (int)nsig); return (stat); }
void prep_signals() { int n; SUALLOC(recpath, strlen(db) + strlen(record) + 2, sizeof(char)); sprintf(recpath, "%s/%s", db, record); /* Discover the number of signals defined in the header, allocate memory for their signal information structures, open the signals. */ if ((nsig = isigopen(recpath, NULL, 0)) > 0) { SUALLOC(s, nsig, sizeof(WFDB_Siginfo)); nsig = isigopen(recpath, s, nsig); } else { tfreq = ffreq = sampfreq(NULL); return; } /* Shorten signal names of the form "record xxx, signal N" to "v[N]" */ for (n = 0; n < nsig; n++) { if (strncmp(s[n].desc, "record ", 7) == 0) sprintf(s[n].desc, "v[%d]", n); } /* Make reasonably sure that signal names are distinct (see below). */ force_unique_signames(); /* Find the least common multiple of the sampling frequencies (which may not be exactly expressible as floating-point numbers). In WFDB-compatible records, all signals are sampled at the same frequency or at a multiple of the frame frequency, but (especially in EDF records) there may be many samples of each signal in each frame. The for loop below sets the "tick" frequency, tfreq, to the number of instants in each second when at least one sample is acquired. */ setgvmode(WFDB_LOWRES); ffreq = sampfreq(NULL); if (ffreq <= 0.) ffreq = WFDB_DEFFREQ; for (n = 0, tfreq = ffreq; n < nsig; n++) tfreq = approx_LCM(ffreq * s[n].spf, tfreq); }
bool ECGController::readFile(std::string filename) { TRI_LOG_STR(__FUNCTION__); //check filename to be correct with WFDB int pos; if ((pos = filename.find('.')) != std::string::npos) { filename = filename.substr(0, pos); } int nr_samples; size_t i; WFDB_Sample v[2]; WFDB_Siginfo s[2]; if (isigopen(const_cast<char*> (filename.c_str()), s, 2) < 2) { TRI_LOG_STR("File"); TRI_LOG(filename); TRI_LOG_STR("Not loaded"); LOG_END return false; }
int main(int argc, char **argv) { int c; int inflag = 0; int dbg = 0; int sr_ds = 200; char * rec_name = "vfdb/427"; char * db_path = "/opt/physiobank/database"; size_t win_sec = 8; /* r stands for record with folder * p for path * i for information of record * s downsample sr * w window length default:8 * d debug */ while ((c = getopt(argc, argv, "idr:p:s:w:")) != -1) switch (c){ case 'i': inflag = 1; break; case 'r': rec_name = optarg; break; case 'p': db_path = optarg; break; case 's': sr_ds= atoi(optarg); break; case'w': win_sec = atoi(optarg); break; case'd': dbg = 1; break; default: abort(); } int i, j, nsig; WFDB_Sample *v; WFDB_Siginfo *s; WFDB_Anninfo a; setwfdb(db_path); nsig = isigopen(rec_name, NULL, 0); if (nsig < 1){ printf("nsig:%d\n",nsig); exit(1); } s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); if (isigopen(rec_name, s, nsig) != nsig) exit(1); v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); int orig_sr = sampfreq(rec_name); a.name = "atr"; a.stat = WFDB_READ; if (wfdbinit(rec_name, &a, 1, s, nsig) != nsig) exit(3); if(1 == inflag ){ printf("sr:%d\n",orig_sr); printf("%d signals\n", nsig); for (i = 0; i < nsig; i++) { printf("Group %d, Signal %d:\n", s[i].group, i); printf("File: %s\n", s[i].fname); printf("Description: %s\n", s[i].desc); printf("Gain: "); if (s[i].gain == 0.) printf("uncalibrated; assume %g", WFDB_DEFGAIN); else printf("%g", s[i].gain); printf(" adu/%s\n", s[i].units ? s[i].units : "mV"); printf(" Initial value: %d\n", s[i].initval); printf(" Storage format: %d\n", s[i].fmt); printf(" I/O: "); if (s[i].bsize == 0) printf("can be unbuffered\n"); else printf("%d-byte blocks\n", s[i].bsize); printf(" ADC resolution: %d bits\n", s[i].adcres); printf(" ADC zero: %d\n", s[i].adczero); if (s[i].nsamp > 0L) { printf(" Length: %s (%ld sample intervals)\n", timstr(s[i].nsamp), s[i].nsamp); printf(" Checksum: %d\n", s[i].cksum); } else printf(" Length undefined\n"); } } fifo_t fifo_ecg; int fifo_ecg_buf[FIFO_SIZE]; fifo_init(&fifo_ecg, fifo_ecg_buf, FIFO_SIZE); fifo_t fifo_bt; int fifo_bt_buf[FIFO_SIZE]; fifo_init(&fifo_bt, fifo_bt_buf, FIFO_SIZE); int tmp = 0; int sr = 200; WFDB_Time begin_samp = 0; WFDB_Time end_samp = orig_sr*win_sec; WFDB_Annotation begin_ann; WFDB_Annotation end_ann; getann(0, &begin_ann); while(0 == getann(0, &end_ann)) if ((end_ann.aux != NULL && *end_ann.aux > 0) ||0 == strcmp(annstr(end_ann.anntyp), "[") ||0 == strcmp(annstr(end_ann.anntyp), "]") ||0 == strcmp(annstr(end_ann.anntyp), "~") ){ break; } int * pBt_len = (int*)calloc(win_sec,sizeof(int)); ResetBDAC(); for (; ;) { if (getvec(v) < 0) break; // for (j = 0; j < nsig; j++){ // } tmp = v[nsig-1]; tmp = v[0]; int vout1 = 0; static int bt_i = 0; static unsigned int samplecnt = 0; int idx = 0; if(down_sample(tmp, &vout1, orig_sr, sr)) { samplecnt ++; fifo_write(&fifo_ecg, &vout1, 1*sizeof(int)); int beatType, beatMatch; long ltmp = vout1-s[0].adczero; ltmp *= 200; ltmp /= s[0].gain; int bdac_dly = BeatDetectAndClassify(ltmp, &beatType, &beatMatch); idx = bt_i/sr; if (0 != bdac_dly ) { pBt_len[idx]++; fifo_write(&fifo_bt, &beatType, sizeof(int)); } bt_i = ++bt_i%(win_sec*sr); } double cm = 0.0; int size = win_sec*sr; if(fifo_len(&fifo_ecg)/sizeof(int) >= sr*win_sec){ int * win_data = (int*)malloc(win_sec*sr*sizeof(int)); int * ds_data = (int*)malloc(win_sec*sr_ds*sizeof(int)); int len = fifo_len(&fifo_bt)/sizeof(int); int * p = (int*)calloc(len, sizeof(int)); if (0 != len){ //printf("bt_i:%d\n", bt_i); fifo_read_steps(&fifo_bt, p, len*sizeof(int), pBt_len[bt_i/sr]*sizeof(int)); //for (i = 0;i< len;i++) printf("%d ", p[i]); //printf("\n"); } pBt_len[bt_i/sr] = 0; fifo_read_steps(&fifo_ecg, win_data, size*sizeof(int), sr*sizeof(int)); filtering(win_data, size, sr); int i = 0; int ds_size = 0; int vout; for(i = 0;i < size;i++){ // if(down_sample(win_data[i], &vout, sr, sr_ds)) ds_data[ds_size++] = vout; } double dven = 0.0; if (0 != len){ int tmp_cnt = 0; for(i = 0; i < len ; i++){ if(5 == p[i]) dven ++; } //printf("div:%d %d\n", tmp_cnt, len); dven /= len; } //cm = ecg_complexity_measure(win_data, size); //cm = ecg_complexity_measure(ds_data, ds_size); //cm = cpsd(ds_data, ds_size, 0.5*sr_ds); //cm = calc_grid(ds_data, ds_size, 0.5*sr_ds); cm = calc_grid(win_data, size, 0.5*sr); if (-1 == cm ) continue; //VT print 1; //VF print 2; int hr = (int)((double)(len*60)/win_sec+0.5); int ret = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(VT"); if (1 == ret){ printf("%d %lf %lf %d\n", 1, cm, dven, hr); } else if (0 == ret) { ret = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(VFL"); int ret2 = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "["); if (1 == ret || 1 == ret2){ printf("%d %lf %lf %d\n", 2, cm, dven, hr); } else if (0 == ret){ // ret = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(N"); // int ret3 = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "N"); // if ((1 == ret || 1 == ret3) && -1 != begin_ann.subtyp) printf ("%d %lf %lf %d\n", 0, cm, dven, hr); if (1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(AFIB") || 1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(AFL") || 1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(IVR") || 1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(SVTA") || 1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(SBR") || 1 == check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(BII") ) printf ("%d %lf %lf %d\n", 0, cm, dven, hr); // int ret = check_ann(begin_samp, end_samp, &begin_ann, &end_ann, "(SVTA"); // if (1 == ret) printf ("%d %lf\n", 0, cm); } } //iannsettime(begin_samp); begin_samp += orig_sr; end_samp += orig_sr; if(end_ann.time < begin_samp){ begin_ann = end_ann; while(1) if (0 != getann(0, &end_ann)){ end_ann = begin_ann; /*the last sample of the signal*/ end_ann.time = s[nsig-1].nsamp; break; }else if ((end_ann.aux != NULL && *end_ann.aux > 0) ||0 == strcmp(annstr(end_ann.anntyp), "[") ||0 == strcmp(annstr(end_ann.anntyp), "]") ||0 == strcmp(annstr(end_ann.anntyp), "~") ){ break; } if(dbg){ printf("begin tm:%s type:%s ", mstimstr(begin_ann.time), annstr(begin_ann.anntyp)); if(begin_ann.aux != NULL) printf("begin aux:%s", begin_ann.aux+1); printf("\n"); printf("end tm:%s type:%s ", mstimstr(end_ann.time), annstr(end_ann.anntyp)); if (end_ann.aux != NULL) printf("end aux:%s", end_ann.aux+1); printf("\n"); printf("begin sample:%s\n", mstimstr(begin_samp)); printf("ann diff:%s\n", mstimstr(end_ann.time-begin_ann.time)); } } free(p); free(ds_data); free(win_data); } } free(pBt_len); wfdbquit(); return 0; }
main(int argc, char **argv) { char *p; char *record = NULL; /* input record name */ float sps; /* sampling frequency, in Hz (SR) */ float samplingInterval; /* sampling interval, in milliseconds */ int i, max, min, minutes = 0, onset, timer, vflag = 0; int dflag = 0; /* if non-zero, dump raw and filtered samples only; do not run detector */ int jflag = 0; /* if non-zero, annotate J-points */ int Rflag = 0; /* if non-zero, resample at 120 or 150 Hz */ int EyeClosing; /* eye-closing period, related to SR */ int ExpectPeriod; /* if no QRS is detected over this period, the threshold is automatically reduced to a minimum value; the threshold is restored upon a detection */ double Ta, T0; /* high and low detection thresholds */ WFDB_Anninfo a; WFDB_Annotation annot; WFDB_Gain gain; WFDB_Siginfo *s; WFDB_Time from = 0L, next_minute, spm, t, tj, tpq, to = 0L, tt, t1; static int gvmode = WFDB_GVPAD | WFDB_LOWRES; char *prog_name(); void help(); pname = prog_name(argv[0]); for (i = 1; i < argc; i++) { if (*argv[i] == '-') switch (*(argv[i]+1)) { case 'd': /* dump filter data */ dflag = 1; break; case 'f': /* starting time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -f\n", pname); exit(1); } from = i; break; case 'h': /* help requested */ help(); exit(0); break; case 'H': /* operate in WFDB_HIGHRES mode */ gvmode = WFDB_GVPAD | WFDB_HIGHRES; break; case 'j': /* annotate J-points (ends of QRS complexes) */ jflag = 1; break; case 'm': /* threshold */ if (++i >= argc || (Tm = atoi(argv[i])) <= 0) { (void)fprintf(stderr, "%s: threshold ( > 0) must follow -m\n", pname); exit(1); } break; case 'p': /* specify power line (mains) frequency */ if (++i >= argc || (PWFreq = atoi(argv[i])) <= 0) { (void)fprintf(stderr, "%s: power line frequency ( > 0) must follow -p\n", pname); exit(1); } break; case 'r': /* record name */ if (++i >= argc) { (void)fprintf(stderr, "%s: input record name must follow -r\n", pname); exit(1); } record = argv[i]; break; case 'R': /* resample */ Rflag = 1; break; case 's': /* signal */ if (++i >= argc) { (void)fprintf(stderr, "%s: signal number or name must follow -s\n", pname); exit(1); } sig = i; /* remember the argument until the record is open */ break; case 't': /* end time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -t\n", pname); exit(1); } to = i; break; case 'v': /* verbose mode */ vflag = 1; break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); exit(1); } else { (void)fprintf(stderr, "%s: unrecognized argument %s\n", pname, argv[i]); exit(1); } } if (record == NULL) { help(); exit(1); } if (gvmode == 0 && (p = getenv("WFDBGVMODE"))) gvmode = atoi(p); setgvmode(gvmode|WFDB_GVPAD); if ((nsig = isigopen(record, NULL, 0)) < 1) exit(2); if ((s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } if ((nsig = isigopen(record, s, nsig)) < 1) exit(2); sps = sampfreq((char *)NULL); if (sps < PWFreq) { (void)fprintf(stderr, "%s: sampling frequency (%g Hz) is too low%s", pname, sps, (gvmode & WFDB_HIGHRES) ? "\n" : ", try -H option\n"); exit(3); } if (gvmode & WFDB_HIGHRES) setafreq(sampfreq((char *)NULL)); a.name = "wqrs"; a.stat = WFDB_WRITE; if (annopen(record, &a, 1) < 0) exit(2); if (sig >= 0) sig = findsig(argv[sig]); if (sig < 0 || sig >= nsig) sig = 0; if ((gain = s[sig].gain) == 0.0) gain = WFDB_DEFGAIN; if (Rflag) { if (PWFreq == 60.0) setifreq(sps = 120.); else setifreq(sps = 150.); } if (from > 0L) { if ((from = strtim(argv[from])) < 0L) from = -from; } if (to > 0L) { if ((to = strtim(argv[to])) < 0L) to = -to; } else to = strtim("e"); annot.subtyp = annot.num = 0; annot.chan = sig; annot.aux = NULL; Tm = muvadu((unsigned)sig, Tm); samplingInterval = 1000.0/sps; lfsc = 1.25*gain*gain/sps; /* length function scale constant */ spm = 60 * sps; next_minute = from + spm; LPn = sps/PWFreq; /* The LP filter will have a notch at the power line (mains) frequency */ if (LPn > 8) LPn = 8; /* avoid filtering too agressively */ LP2n = 2 * LPn; EyeClosing = sps * EYE_CLS; /* set eye-closing period */ ExpectPeriod = sps * NDP; /* maximum expected RR interval */ LTwindow = sps * MaxQRSw; /* length transform window size */ (void)sample(sig, 0L); if (dflag) { for (t = from; t < to || (to == 0L && sample_valid()); t++) printf("%6d\t%6d\n", sample(sig, t), ltsamp(t)); exit(0); } if (vflag) { printf("\n------------------------------------------------------\n"); printf("Record Name: %s\n", record); printf("Total Signals: %d (", nsig); for (i = 0; i < nsig - 1; i++) printf("%d, ", i); printf("%d)\n", nsig - 1); printf("Sampling Frequency: %.1f Hz\n", sps); printf("Sampling Interval: %.3f ms\n", samplingInterval); printf("Signal channel used for detection: %d\n", sig); printf("Eye-closing period: %d samples (%.0f ms)\n", EyeClosing, EyeClosing*samplingInterval); printf("Minimum threshold: %d A/D units (%d microvolts)\n", Tm, adumuv(sig, Tm)); printf("Power line frequency: %d Hz\n", PWFreq); printf("\n------------------------------------------------------\n\n"); printf("Processing:\n"); } /* Average the first 8 seconds of the length-transformed samples to determine the initial thresholds Ta and T0. The number of samples in the average is limited to half of the ltsamp buffer if the sampling frequency exceeds about 2 KHz. */ if ((t1 = strtim("8")) > BUFLN*0.9) t1 = BUFLN/2; t1 += from; for (T0 = 0, t = from; t < t1 && sample_valid(); t++) T0 += ltsamp(t); T0 /= t1 - from; Ta = 3 * T0; /* Main loop */ for (t = from; t < to || (to == 0L && sample_valid()); t++) { static int learning = 1, T1; if (learning) { if (t > t1) { learning = 0; T1 = T0; t = from; /* start over */ } else T1 = 2*T0; } /* Compare a length-transformed sample against T1. */ if (ltsamp(t) > T1) { /* found a possible QRS near t */ timer = 0; /* used for counting the time after previous QRS */ max = min = ltsamp(t); for (tt = t+1; tt < t + EyeClosing/2; tt++) if (ltsamp(tt) > max) max = ltsamp(tt); for (tt = t-1; tt > t - EyeClosing/2; tt--) if (ltsamp(tt) < min) min = ltsamp(tt); if (max > min+10) { /* There is a QRS near tt */ /* Find the QRS onset (PQ junction) */ onset = max/100 + 2; tpq = t - 5; for (tt = t; tt > t - EyeClosing/2; tt--) { if (ltsamp(tt) - ltsamp(tt-1) < onset && ltsamp(tt-1) - ltsamp(tt-2) < onset && ltsamp(tt-2) - ltsamp(tt-3) < onset && ltsamp(tt-3) - ltsamp(tt-4) < onset) { tpq = tt - LP2n; /* account for phase shift */ break; } } if (!learning) { /* Check that we haven't reached the end of the record. */ (void)sample(sig, tpq); if (sample_valid() == 0) break; /* Record an annotation at the QRS onset */ annot.time = tpq; annot.anntyp = NORMAL; if (putann(0, &annot) < 0) { /* write the annotation */ wfdbquit(); /* close files if an error occurred */ exit(1); } if (jflag) { /* Find the end of the QRS */ for (tt = t, tj = t + 5; tt < t + EyeClosing/2; tt++) { if (ltsamp(tt) > max - (max/10)) { tj = tt; break; } } (void)sample(sig, tj); if (sample_valid() == 0) break; /* Record an annotation at the J-point */ annot.time = tj; annot.anntyp = JPT; if (putann(0, &annot) < 0) { wfdbquit(); exit(1); } } } /* Adjust thresholds */ Ta += (max - Ta)/10; T1 = Ta / 3; /* Lock out further detections during the eye-closing period */ t += EyeClosing; } } else if (!learning) { /* Once past the learning period, decrease threshold if no QRS was detected recently. */ if (++timer > ExpectPeriod && Ta > Tm) { Ta--; T1 = Ta / 3; } } /* Keep track of progress by printing a dot for each minute analyzed */ if (t >= next_minute) { next_minute += spm; (void)fprintf(stderr, "."); (void)fflush(stderr); if (++minutes >= 60) { (void)fprintf(stderr, " %s\n", timstr(t)); minutes = 0; } } } if (minutes) (void)fprintf(stderr, " %s\n", timstr(t)); (void)free(lbuf); (void)free(ebuf); wfdbquit(); /* close WFDB files */ fprintf(stderr, "\n"); if (vflag) { printf("\n\nDone! \n\nResulting annotation file: %s.wqrs\n\n\n", record); } exit(0); }
/* After using isigopen_ or osigopen_, use getsiginfo_ to obtain the contents of the signal information structures if necessary. */ INTEGER isigopen_(char *record, INTEGER *nsig) { return (isigopen(fcstring(record), sinfo, (unsigned int)(*nsig))); }
MAINTYPE main() { char record[10], fname[20] ; int i, ecg[2], delay, recNum ; WFDB_Siginfo s[2] ; WFDB_Anninfo a[2] ; WFDB_Annotation annot ; unsigned char byte ; FILE *newAnn0, *newAnn1 ; long SampleCount = 0, lTemp, DetectionTime ; int beatType, beatMatch ; // Set up path to database directory setwfdb(ECG_DB_PATH) ; // Analyze all 48 MIT/BIH Records. for(recNum = 0; recNum < REC_COUNT; ++recNum) { sprintf(record,"%d",Records[recNum]) ; printf("Record %d\n",Records[recNum]) ; // Open a 2 channel record if(isigopen(record,s,2) < 1) { printf("Couldn't open %s\n",record) ; return ; } ADCZero = s[0].adczero ; ADCUnit = s[0].gain ; InputFileSampleFrequency = sampfreq(record) ; // Setup for output annotations a[0].name = "atest"; a[0].stat = WFDB_WRITE ; if(annopen(record, a, 1) < 0) return ; // Initialize sampling frequency adjustment. NextSample(ecg,2,InputFileSampleFrequency,SAMPLE_RATE,1) ; // Initialize beat detection and classification. ResetBDAC() ; SampleCount = 0 ; // Read data from MIT/BIH file until there is none left. while(NextSample(ecg,2,InputFileSampleFrequency,SAMPLE_RATE,0) >= 0) { ++SampleCount ; // Set baseline to 0 and resolution to 5 mV/lsb (200 units/mV) lTemp = ecg[0]-ADCZero ; lTemp *= 200 ; lTemp /= ADCUnit ; ecg[0] = lTemp ; // Pass sample to beat detection and classification. delay = BeatDetectAndClassify(ecg[0], &beatType, &beatMatch) ; // If a beat was detected, annotate the beat location // and type. if(delay != 0) { DetectionTime = SampleCount - delay ; // Convert sample count to input file sample // rate. DetectionTime *= InputFileSampleFrequency ; DetectionTime /= SAMPLE_RATE ; annot.time = DetectionTime ; annot.anntyp = beatType ; annot.aux = NULL ; putann(0,&annot) ; } } // Reset database after record is done. wfdbquit() ; #if 0 /* This code is obsolete. The annotation files are always written into "<record>.ate" in the current directory. They do not need to be copied in order to be read by bxbep, if the WFDB path includes both the current current directory and the one containing the .atr reference annotation files. */ // Copy "atest.<record>" to "<record>.ate" for future ascess. // (This is necessary for PC files) sprintf(fname,"%s.ate",record) ; newAnn0 = fopen(fname,"rb") ; sprintf(fname,"%s%s.ate",ECG_DB_PATH,record) ; newAnn1 = fopen(fname,"wb") ; // Copy byte image of annotation file in this // directory to a correctly named file in the // database directory. while(fread(&byte,sizeof(char),1,newAnn0) == 1) fwrite(&byte,sizeof(char),1,newAnn1) ; fclose(newAnn0) ; fclose(newAnn1) ; #endif } }
main(int argc, char **argv) { char *record = NULL, *prog_name(); int aindex = 0, alen = 0, framelen = 0; int i, nsig, s, vflag = 0; WFDB_Sample *frame; WFDB_Siginfo *si; void help(); pname = prog_name(argv[0]); for (i = 1; i < argc; i++) { if (*argv[i] == '-') switch (*(argv[i]+1)) { case 'F': if (++i >= argc) { (void)fprintf(stderr, "%s: sampling frequency must follow -F\n", pname); exit(1); } sscanf(argv[i], "%lf", &sfreq); if (sfreq <= 0.0) sfreq = 1.0; break; case 'h': /* help requested */ help(); exit(0); break; case 'r': /* record name */ if (++i >= argc) { (void)fprintf(stderr, "%s: record name must follow -r\n", pname); exit(1); } record = argv[i]; break; case 'v': /* verbose output -- include column headings */ vflag = 1; break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); exit(1); } else { (void)fprintf(stderr, "%s: unrecognized argument %s\n", pname, argv[i]); exit(1); } } if (record == NULL) { help(); exit(1); } setgvmode(WFDB_HIGHRES); if ((nsig = isigopen(record, NULL, 0)) <= 0) exit(2); if ((si = malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } if ((nsig = isigopen(record, si, nsig)) <= 0) exit(2); for (i = framelen = 0; i < nsig; i++) { if (strcmp(si[i].desc, "EDF Annotations") == 0) { aindex = framelen; alen = si[i].spf; } framelen += si[i].spf; } if (alen == 0) { (void)fprintf(stderr, "%s: record %s has no EDF annotations\n", pname, record); (void)free(si); wfdbquit(); exit(3); } if ((frame = (int *)malloc((unsigned)framelen*sizeof(WFDB_Sample)))==NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); (void)free(si); exit(2); } if (sfreq > 0.0) { setgvmode(WFDB_LOWRES); setsampfreq(sfreq); } else sfreq = sampfreq(NULL); /* Print column headers if '-v' option selected. */ if (vflag) (void)printf(" Time Sample # Type Sub Chan Num\tAux\n"); while (getframe(frame) > 0) { WFDB_Sample *p; state = 0; for (i = 0, p = (frame + aindex); i < alen; i++, p++) { if (*p) { proc(*p); proc(*p >> 8); } else break; } }
int main(int argc, char **argv) { char *record = NULL; /* input record name */ float sps; /* sampling frequency, in Hz (SR) */ float samplingInterval; /* sampling interval, in milliseconds */ int i, max, min, minutes = 0, onset, timer, vflag = 0; int dflag = 0; /* if non-zero, dump raw and filtered samples only; do not run detector */ int Rflag = 0; /* if non-zero, resample at 125 Hz */ int EyeClosing; /* eye-closing period, related to SR */ int ExpectPeriod; /* if no ABP pulse is detected over this period, the threshold is automatically reduced to a minimum value; the threshold is restored upon a detection */ int Ta, T0; /* high and low detection thresholds */ WFDB_Anninfo a; WFDB_Annotation annot; WFDB_Siginfo *s; WFDB_Time from = 0L, next_minute, spm, t, tpq, to = 0L, tt, t1; char *p, *prog_name(); static int gvmode = 0; void help(); pname = prog_name(argv[0]); for (i = 1; i < argc; i++) { if (*argv[i] == '-') switch (*(argv[i]+1)) { case 'd': /* dump filter data */ dflag = 1; break; case 'f': /* starting time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -f\n", pname); exit(1); } from = i; break; case 'h': /* help requested */ help(); exit(0); break; case 'H': /* operate in WFDB_HIGHRES mode */ gvmode = WFDB_HIGHRES; break; case 'm': /* threshold */ if (++i >= argc || (Tm = atoi(argv[i])) <= 0) { (void)fprintf(stderr, "%s: threshold ( > 0) must follow -m\n", pname); exit(1); } break; case 'r': /* record name */ if (++i >= argc) { (void)fprintf(stderr, "%s: input record name must follow -r\n", pname); exit(1); } record = argv[i]; break; case 'R': /* resample */ Rflag = 1; break; case 's': /* signal */ if (++i >= argc) { (void)fprintf(stderr, "%s: signal number or name must follow -s\n", pname); exit(1); } sig = i; /* remember argument until record is open */ break; case 't': /* end time */ if (++i >= argc) { (void)fprintf(stderr, "%s: time must follow -t\n", pname); exit(1); } to = i; break; case 'v': /* verbose mode */ vflag = 1; break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); exit(1); } else { (void)fprintf(stderr, "%s: unrecognized argument %s\n", pname, argv[i]); exit(1); } } if (record == NULL) { help(); exit(1); } if (gvmode == 0 && (p = getenv("WFDBGVMODE"))) gvmode = atoi(p); setgvmode(gvmode|WFDB_GVPAD); if ((nsig = isigopen(record, NULL, 0)) < 1) exit(2); if ((s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo))) == NULL) { (void)fprintf(stderr, "%s: insufficient memory\n", pname); exit(2); } a.name = "wabp"; a.stat = WFDB_WRITE; if ((nsig = wfdbinit(record, &a, 1, s, nsig)) < 1) exit(2); if (sig >= 0) sig = findsig(argv[sig]); if (sig < 0 || sig >= nsig) { /* Identify the lowest-numbered ABP, ART, or BP signal */ for (i = 0; i < nsig; i++) if (strcmp(trim_whitespace(s[i].desc), "ABP") == 0 || strcmp(s[i].desc, "ART") == 0 || strcmp(s[i].desc, "BP") == 0) break; if (i == nsig) { fprintf(stderr, "%s: no ABP signal specified; use -s option\n\n", pname); help(); exit(3); } sig = i; } if (vflag) fprintf(stderr, "%s: analyzing signal %d (%s)\n", pname, sig, s[sig].desc); sps = sampfreq((char *)NULL); if (Rflag) setifreq(sps = 125.); if (from > 0L) { if ((from = strtim(argv[from])) < 0L) from = -from; } if (to > 0L) { if ((to = strtim(argv[to])) < 0L) to = -to; } annot.subtyp = annot.num = 0; annot.chan = sig; annot.aux = NULL; Tm = physadu((unsigned)sig, Tm); samplingInterval = 1000.0/sps; spm = 60 * sps; next_minute = from + spm; EyeClosing = sps * EYE_CLS; /* set eye-closing period */ ExpectPeriod = sps * NDP; /* maximum expected RR interval */ SLPwindow = sps * SLPW; /* slope window size */ if (vflag) { printf("\n------------------------------------------------------\n"); printf("Record Name: %s\n", record); printf("Total Signals: %d (", nsig); for (i = 0; i < nsig - 1; i++) printf("%d, ", i); printf("%d)\n", nsig - 1); printf("Sampling Frequency: %.1f Hz\n", sps); printf("Sampling Interval: %.3f ms\n", samplingInterval); printf("Signal channel used for detection: %d\n", sig); printf("Eye-closing period: %d samples (%.0f ms)\n", EyeClosing, EyeClosing*samplingInterval); printf("Minimum threshold: %d\n", Tm); printf("\n------------------------------------------------------\n\n"); printf("Processing:\n"); } (void)sample(sig, 0L); if (dflag) { for (t = from; (to == 0L || t < to) && sample_valid(); t++) printf("%6d\t%6d\n", sample(sig, t), slpsamp(t)); exit(0); } /* Average the first 8 seconds of the slope samples to determine the initial thresholds Ta and T0 */ t1 = from + strtim("8"); for (T0 = 0, t = from; t < t1 && sample_valid(); t++) T0 += slpsamp(t); T0 /= t1 - from; Ta = 3 * T0; /* Main loop */ for (t = from; (to == 0L || t < to) && sample_valid(); t++) { static int learning = 1, T1; if (learning) { if (t > from + LPERIOD) { learning = 0; T1 = T0; t = from; /* start over */ } else T1 = 2*T0; } if (slpsamp(t) > T1) { /* found a possible ABP pulse near t */ timer = 0; /* used for counting the time after previous ABP pulse */ max = min = slpsamp(t); for (tt = t+1; tt < t + EyeClosing/2; tt++) if (slpsamp(tt) > max) max = slpsamp(tt); for (tt = t-1; tt > t - EyeClosing/2; tt--) if (slpsamp(tt) < min) min = slpsamp(tt); if (max > min+10) { onset = max/100 + 2; tpq = t - 5; for (tt = t; tt > t - EyeClosing/2; tt--) { if (slpsamp(tt) - slpsamp(tt-1) < onset) { tpq = tt; break; } } if (!learning) { /* Check that we haven't reached the end of the record. */ (void)sample(sig, tpq); if (sample_valid() == 0) break; /* Record an annotation at the ABP pulse onset */ annot.time = tpq; annot.anntyp = NORMAL; if (putann(0, &annot) < 0) { /* write the annotation */ wfdbquit(); /* close files if an error occurred */ exit(1); } } /* Adjust thresholds */ Ta += (max - Ta)/10; T1 = Ta / 3; /* Lock out further detections during the eye-closing period */ t += EyeClosing; } } else if (!learning) { /* Once past the learning period, decrease threshold if no pulse was detected recently. */ if (++timer > ExpectPeriod && Ta > Tm) { Ta--; T1 = Ta / 3; } } /* Keep track of progress by printing a dot for each minute analyzed */ if (t >= next_minute) { next_minute += spm; (void)fprintf(stderr, "."); (void)fflush(stderr); if (++minutes >= 60) { (void)fprintf(stderr, "\n"); minutes = 0; } } } (void)free(lbuf); (void)free(ebuf); wfdbquit(); /* close WFDB files */ fprintf(stderr, "\n"); if (vflag) { printf("\n\nDone! \n\nResulting annotation file: %s.wabp\n\n\n", record); } exit(0); }