Пример #1
0
int fetchannotations(void)
{
    int afirst = 1, i;
    WFDB_Anninfo ai;
    WFDB_Time ta0, taf;

    if (nann < 1) return (0);
    if (tfreq != ffreq) {
	ta0 = (WFDB_Time)(t0*tfreq/ffreq + 0.5);
	taf = (WFDB_Time)(tf*tfreq/ffreq + 0.5);
    }
    else {
	ta0 = t0;
	taf = tf;
    }

    printf("  %c \"annotator\":\n    [", nosig > 0 ? ' ' : '{');  
    setgvmode(WFDB_HIGHRES);
    for (i = 0; i < nann; i++) {
	ai.name = annotator[i];
	ai.stat = WFDB_READ;
	if (annopen(recpath, &ai, 1) >= 0) {
	    char *p;
	    int first = 1;
	    WFDB_Annotation annot;

	    if (ta0 > 0L) iannsettime(ta0);
	    if (!afirst) printf(",");
	    else afirst = 0;
	    printf("\n      { \"name\": \"%s\",\n", annotator[i]);
	    printf("        \"annotation\":\n");
	    printf("        [");
	    while ((getann(0, &annot) == 0) && (taf <= 0 || annot.time < taf)) {
		if (!first) printf(",");
		else first = 0;
		printf("\n          { \"t\": %ld,\n", (long)(annot.time));
		printf("            \"a\": %s,\n",
		       p = strjson(annstr(annot.anntyp)));
		SFREE(p);
		printf("            \"s\": %d,\n", annot.subtyp);
		printf("            \"c\": %d,\n", annot.chan);
		printf("            \"n\": %d,\n", annot.num);
		if (annot.aux && *(annot.aux)) {
		    printf("            \"x\": %s\n", p = strjson(annot.aux+1));
		    SFREE(p);
		}
		else
		    printf("            \"x\": null\n");
		printf("          }");
	    }
	    printf("\n        ]\n      }");	    
	}
    }
    printf("\n    ]\n  }\n");
    return (1);
}
Пример #2
0
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);
}   
Пример #3
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);
}
Пример #4
0
INTEGER setgvmode_(INTEGER *mode)
{
    setgvmode((int)(*mode));
    return (0L);
}
Пример #5
0
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;
	}
    }
Пример #6
0
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);
}