diff -Naur wfdb-10.2.9/MANIFEST wfdb-10.3.0/MANIFEST --- wfdb-10.2.9/MANIFEST Sat Oct 26 23:42:58 2002 +++ wfdb-10.3.0/MANIFEST Mon Nov 25 23:59:30 2002 @@ -6,7 +6,7 @@ app/calsig.c app/cshsetwfdb app/ecgeval.c -app/epic.c +app/epicmp.c app/fir.c app/ihr.c app/Makefile @@ -34,6 +34,7 @@ app/setwfdb app/setwfdb.bat app/sigamp.c +app/sigavg.c app/skewedit.c app/snip.c app/sortann.c @@ -49,6 +50,7 @@ app/wfdb-config.c app/wfdbdesc.c app/wfdbwhich.c +app/wqrs.c app/wrann.c app/wrsamp.c app/wvscript.c @@ -61,6 +63,7 @@ checkpkg/expected/100s.a2r checkpkg/expected/100s.mix checkpkg/expected/100s.qrs +checkpkg/expected/100s.wqrs checkpkg/expected/100s.wra checkpkg/expected/100w.dat checkpkg/expected/100w.hea @@ -119,6 +122,9 @@ checkpkg/Makefile.tpl conf/ conf/cygwin.def +conf/cygwin-slib.def +conf/darwin.def +conf/darwin-slib.def conf/exechmod conf/exestrip conf/freebsd.def @@ -147,6 +153,7 @@ convert/Makefile.tpl convert/makeid.c convert/md2a.c +convert/mit2edf.c convert/readid.c convert/README convert/revise.c @@ -240,25 +247,27 @@ doc/wag-src/a2m.1 doc/wag-src/ann2rr.1 doc/wag-src/annot.5 -doc/wag-src/appguide.int doc/wag-src/blankpage doc/wag-src/bxb.1 doc/wag-src/calsig.1 doc/wag-src/coherence.1 doc/wag-src/dfa.1 doc/wag-src/ecgeval.1 +doc/wag-src/ecgpuwave.1 doc/wag-src/edf2mit.1 -doc/wag-src/epic.1 -doc/wag-src/eval.tex +doc/wag-src/edr.1 +doc/wag-src/epicmp.1 +doc/wag-src/eval0.tex doc/wag-src/faq.ht0 doc/wag-src/fft.1 doc/wag-src/fir.1 doc/wag-src/fixag.sed doc/wag-src/fixag.sh +doc/wag-src/getpagenos.c doc/wag-src/header.5 doc/wag-src/hrfft.1 doc/wag-src/ihr.1 -doc/wag-src/install.tex +doc/wag-src/install0.tex doc/wag-src/intro.ht0 doc/wag-src/.latex2html-init doc/wag-src/log10.1 @@ -266,6 +275,9 @@ doc/wag-src/Makefile doc/wag-src/Makefile.top doc/wag-src/Makefile.tpl +doc/wag-src/maketoc-html.sh +doc/wag-src/maketoclines.c +doc/wag-src/maketoc-tex.sh doc/wag-src/manhtml.sh doc/wag-src/maninst.sh doc/wag-src/memse.1 @@ -286,6 +298,7 @@ doc/wag-src/sample.1 doc/wag-src/setwfdb.1 doc/wag-src/sigamp.1 +doc/wag-src/sigavg.1 doc/wag-src/signal.5 doc/wag-src/skewedit.1 doc/wag-src/snip.1 @@ -298,6 +311,7 @@ doc/wag-src/view.1 doc/wag-src/wag.cover doc/wag-src/wag.ht0 +doc/wag-src/wag.ht1 doc/wag-src/wag.tex doc/wag-src/wave.1 doc/wag-src/wfdb.3 @@ -308,6 +322,7 @@ doc/wag-src/wfdbdesc.1 doc/wag-src/wfdbf.3 doc/wag-src/wfdbwhich.1 +doc/wag-src/wqrs.1 doc/wag-src/wrann.1 doc/wag-src/wrsamp.1 doc/wag-src/wview.1 diff -Naur wfdb-10.2.9/Makefile wfdb-10.3.0/Makefile --- wfdb-10.2.9/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/Makefile Tue Nov 26 13:40:19 2002 @@ -39,12 +39,12 @@ # create source archives, type `make tarballs'; or to make a binary archive, # type `make bin-tarball'. Making archives requires PGP, gzip, and GNU tar). # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -61,13 +61,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -176,6 +176,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/NEWS wfdb-10.3.0/NEWS --- wfdb-10.2.9/NEWS Sat Oct 26 23:55:07 2002 +++ wfdb-10.3.0/NEWS Sun Nov 24 14:51:04 2002 @@ -1,3 +1,56 @@ +10.3.0: + The WFDB Software Package has been ported to MacOS/X (Darwin), + version 10.2 (the port should also work under 10.1 but this + has not been tested and will not be supported). + + It is now possible to generate a shared WFDB library (DLL) + under MS-Windows using Cygwin/gcc. + + Fixed bugs in lib/signal.c that caused improper accounting of + signal group numbers when reading from two or more records at + the same time (as in 'nst'), a bug that caused a segfault in + 'nst', and a bug that referenced uninitialized memory in + newheader() if nsig = 0. + + Added functions sample() and sample_valid() to the WFDB library + (in lib/signal.c). sample(s, t) returns the sample at time (sample + number) t from signal s, handling all necessary buffering + internally and allowing the caller to treat the signal file + as a virtual array of randomly accessible samples. sample_valid() + can be invoked to check if the most recent value returned by + sample() was valid (e.g., to see if the end of the input was + reached). For an example of the use of these functions, see + app/wqrs.c . + + Use -p -p to obtain higher precision in 'rdsamp' output. + + New -w option for 'ann2rr' and 'rr2ann' for attaching annotation + types to intervals. + + Fixed a subtle bug in 'bxb' that caused it to count matching + annotations as mismatches in very rare circumstances when the heart + rate exceeds 200 bpm. The effect of this bug was only to cause + a tiny fraction of correct detections to be counted as errors, and not + to cause detector errors to be counted as correct. Thanks to James + Pardey for reporting the problem and for providing a test case that + was useful for developing and testing the fix. See the comments in + 'app/bxb.c' for details. + + The application formerly known as 'epic' has be renamed 'epicmp' + (episode comparator), to avoid conflicts with a new but widely + distributed IRC chat client named 'epic'. + + Conversion of floating-point values to integer samples has been + modified to obtain better cross-platform consistency in psfd and + wrsamp. + + Wei Zong's length-transform-based QRS detector, wqrs, has been + added to the package. + + New 'mit2edf' application converts records to European Data Format. + + Numerous updates in the WFDB Applications Guide. + 10.2.9: Fixed a bug in example 9 in the WFDB Programmer's Guide (introduced in version 10.2.0). diff -Naur wfdb-10.2.9/app/Makefile wfdb-10.3.0/app/Makefile --- wfdb-10.2.9/app/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/app/Makefile Tue Nov 26 13:40:19 2002 @@ -33,12 +33,12 @@ # type `make listing'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -55,13 +55,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -171,6 +171,40 @@ # uncomment the next line. # STRIP = : +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... + # `make' (with no target specified) will be equivalent to `make all'. make-all: all @@ -181,21 +215,22 @@ lib-post-uninstall: echo "Nothing to be done for lib-post-uninstall" # _____________________________________________________________________________ -# file: Makefile.tpl G. Moody 23 May 2000 -# Last revised: 26 October 2002 +# file: Makefile.tpl G. Moody 23 May 2000 +# Last revised: 26 November 2002 # This section of the Makefile should not need to be changed. -CFILES = ann2rr.c bxb.c calsig.c ecgeval.c epic.c fir.c ihr.c mfilt.c \ +CFILES = ann2rr.c bxb.c calsig.c ecgeval.c epicmp.c fir.c ihr.c mfilt.c \ mrgann.c mxm.c nst.c plotstm.c pscgen.c pschart.c psfd.c rdann.c rdsamp.c \ - rr2ann.c rxr.c sampfreq.c sample.c sigamp.c skewedit.c snip.c sortann.c \ - sqrs.c sqrs125.c sumann.c sumstats.c tach.c view.c vsetup.c wfdbcat.c \ - wfdbcollate.c wfdb-config.c wfdbdesc.c wfdbwhich.c wrann.c wrsamp.c \ - wvscript.c xform.c -XFILES = ann2rr bxb calsig ecgeval epic fir ihr mfilt \ + rr2ann.c rxr.c sampfreq.c sample.c sigamp.c sigavg.c skewedit.c snip.c \ + sortann.c sqrs.c sqrs125.c sumann.c sumstats.c tach.c view.c vsetup.c \ + wfdbcat.c wfdbcollate.c wfdb-config.c wfdbdesc.c wfdbwhich.c wqrs.c wrann.c \ + wrsamp.c wvscript.c xform.c +XFILES = ann2rr bxb calsig ecgeval epicmp fir ihr mfilt \ mrgann mxm nst plotstm pscgen pschart psfd rdann rdsamp \ - rr2ann rxr sampfreq sigamp skewedit snip sortann \ - sqrs sqrs125 sumann sumstats tach wfdbcat \ - wfdbcollate wfdb-config wfdbdesc wfdbwhich wrann wrsamp xform + rr2ann rxr sampfreq sigamp sigavg skewedit snip \ + sortann sqrs sqrs125 sumann sumstats tach \ + wfdbcat wfdbcollate wfdb-config wfdbdesc wfdbwhich wqrs wrann \ + wrsamp xform SCRIPTS = cshsetwfdb setwfdb PSFILES = pschart.pro psfd.pro 12lead.pro OTHERFILES = cshsetwfdb setwfdb setwfdb.bat sample8.hea @@ -264,3 +299,5 @@ wfdb-config: wfdb-config.c Makefile $(CC) -DVERSION='"$(VERSION)"' -DCFLAGS='"-I$(INCDIR)"' \ -DLDFLAGS='"$(LDFLAGS)"' -o $@ wfdb-config.c +wqrs: wqrs.c + $(CC) $(CFLAGS) wqrs.c -o $@ $(LDFLAGS) -lm diff -Naur wfdb-10.2.9/app/Makefile.dos wfdb-10.3.0/app/Makefile.dos --- wfdb-10.2.9/app/Makefile.dos Sat Oct 26 15:25:12 2002 +++ wfdb-10.3.0/app/Makefile.dos Fri Nov 22 14:35:41 2002 @@ -1,5 +1,5 @@ # file: Makefile.dos G. Moody 2 November 1989 -# Last revised: 26 October 2002 +# Last revised: 22 November 2002 # MSDOS/Windows `make' description file template for WFDB applications # # ----------------------------------------------------------------------------- @@ -101,12 +101,13 @@ # anything below this line. # ----------------------------------------------------------------------------- -XFILES = ann2rr.exe bxb.exe calsig.exe ecgeval.exe epic.exe fir.exe ihr.exe \ +XFILES = ann2rr.exe bxb.exe calsig.exe ecgeval.exe epicmp.exe fir.exe ihr.exe \ mfilt.exe mrgann.exe mxm.exe nst.exe plotstm.exe pscgen.exe pschart.exe \ psfd.exe rdann.exe rdsamp.exe rr2ann.exe rxr.exe sampfreq.exe sigamp.exe \ skewedit.exe snip.exe sortann.exe sqrs.exe sqrs125.exe sumann.exe \ sumstats.exe tach.exe wfdbcat.exe wfdbcollate.exe wfdb-config.exe \ - wfdbdesc.exe wfdbwhich.exe wrann.exe wrsamp.exe wvscript.exe xform.exe \ + wfdbdesc.exe wfdbwhich.exe wqrs.exe wrann.exe wrsamp.exe wvscript.exe \ + xform.exe \ $(XXFILES) # General rule for compiling C sources into executable files diff -Naur wfdb-10.2.9/app/Makefile.tpl wfdb-10.3.0/app/Makefile.tpl --- wfdb-10.2.9/app/Makefile.tpl Sat Oct 26 15:31:42 2002 +++ wfdb-10.3.0/app/Makefile.tpl Tue Nov 26 13:40:10 2002 @@ -1,18 +1,19 @@ -# file: Makefile.tpl G. Moody 23 May 2000 -# Last revised: 26 October 2002 +# file: Makefile.tpl G. Moody 23 May 2000 +# Last revised: 26 November 2002 # This section of the Makefile should not need to be changed. -CFILES = ann2rr.c bxb.c calsig.c ecgeval.c epic.c fir.c ihr.c mfilt.c \ +CFILES = ann2rr.c bxb.c calsig.c ecgeval.c epicmp.c fir.c ihr.c mfilt.c \ mrgann.c mxm.c nst.c plotstm.c pscgen.c pschart.c psfd.c rdann.c rdsamp.c \ - rr2ann.c rxr.c sampfreq.c sample.c sigamp.c skewedit.c snip.c sortann.c \ - sqrs.c sqrs125.c sumann.c sumstats.c tach.c view.c vsetup.c wfdbcat.c \ - wfdbcollate.c wfdb-config.c wfdbdesc.c wfdbwhich.c wrann.c wrsamp.c \ - wvscript.c xform.c -XFILES = ann2rr bxb calsig ecgeval epic fir ihr mfilt \ + rr2ann.c rxr.c sampfreq.c sample.c sigamp.c sigavg.c skewedit.c snip.c \ + sortann.c sqrs.c sqrs125.c sumann.c sumstats.c tach.c view.c vsetup.c \ + wfdbcat.c wfdbcollate.c wfdb-config.c wfdbdesc.c wfdbwhich.c wqrs.c wrann.c \ + wrsamp.c wvscript.c xform.c +XFILES = ann2rr bxb calsig ecgeval epicmp fir ihr mfilt \ mrgann mxm nst plotstm pscgen pschart psfd rdann rdsamp \ - rr2ann rxr sampfreq sigamp skewedit snip sortann \ - sqrs sqrs125 sumann sumstats tach wfdbcat \ - wfdbcollate wfdb-config wfdbdesc wfdbwhich wrann wrsamp xform + rr2ann rxr sampfreq sigamp sigavg skewedit snip \ + sortann sqrs sqrs125 sumann sumstats tach \ + wfdbcat wfdbcollate wfdb-config wfdbdesc wfdbwhich wqrs wrann \ + wrsamp xform SCRIPTS = cshsetwfdb setwfdb PSFILES = pschart.pro psfd.pro 12lead.pro OTHERFILES = cshsetwfdb setwfdb setwfdb.bat sample8.hea @@ -81,3 +82,5 @@ wfdb-config: wfdb-config.c Makefile $(CC) -DVERSION='"$(VERSION)"' -DCFLAGS='"-I$(INCDIR)"' \ -DLDFLAGS='"$(LDFLAGS)"' -o $@ wfdb-config.c +wqrs: wqrs.c + $(CC) $(CFLAGS) wqrs.c -o $@ $(LDFLAGS) -lm diff -Naur wfdb-10.2.9/app/ann2rr.c wfdb-10.3.0/app/ann2rr.c --- wfdb-10.2.9/app/ann2rr.c Mon May 20 17:40:17 2002 +++ wfdb-10.3.0/app/ann2rr.c Fri Nov 1 07:07:58 2002 @@ -1,5 +1,5 @@ -/* file: ann2rr.c G. Moody 16 May 1995 - Last revised: 20 May 2002 +/* file: ann2rr.c G. Moody 16 May 1995 + Last revised: 1 November 2002 ------------------------------------------------------------------------------- ann2rr: Calculate RR intervals from an annotation file Copyright (C) 2002 George B. Moody @@ -44,7 +44,8 @@ { char *record = NULL, *prog_name(); double sps, spm, sph, rrsec; - int cflag=0, i, j, pflag=0, previous_annot_valid=0, tformat=0, vflag=0; + int cflag=0, i, j, pflag=0, previous_annot_valid=0, tformat=0, vflag=0, + wflag=0; long beat_number = 0L, from = 0L, to = 0L, rr, tp = 0L, atol(); static char flag[ACMAX+1]; static WFDB_Anninfo ai; @@ -124,6 +125,9 @@ default: tformat = 0; break; /* use sample intervals */ } break; + case 'w': /* output annotation types following intervals */ + wflag = 1; + break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); @@ -187,8 +191,11 @@ } } /* print RR interval */ - if (tformat) (void)printf("%.3lf\n", rr/sps); - else (void)printf("%ld\n", rr); + if (tformat) (void)printf("%.3lf", rr/sps); + else (void)printf("%ld", rr); + /* print annotation type if requested */ + if (wflag) (void)printf("\t%s", annstr(annot.anntyp)); + printf("\n"); } tp = annot.time; previous_annot_valid = 1; @@ -240,6 +247,7 @@ " -Vh same as -V, but print times in hours and RR intervals in seconds", " -Vm same as -V, but print times in minutes and RR intervals in seconds", " -Vs same as -V, but print times and RR intervals in seconds", + " -w print annotation types following intervals", NULL }; diff -Naur wfdb-10.2.9/app/bxb.c wfdb-10.3.0/app/bxb.c --- wfdb-10.2.9/app/bxb.c Mon May 20 17:52:34 2002 +++ wfdb-10.3.0/app/bxb.c Sun Nov 24 15:15:04 2002 @@ -1,5 +1,5 @@ /* file: bxb.c G. Moody 14 December 1987 - Last revised: 20 May 2002 + Last revised: 24 November 2002 ------------------------------------------------------------------------------- bxb: ANSI/AAMI-standard beat-by-beat annotation file comparator @@ -38,15 +38,6 @@ #include #include /* for declaration of sqrt() */ -#ifndef BSD -#include -#else -#include -#endif -#ifndef __STDC__ -extern void exit(); -#endif - #include #define map1 #define map2 @@ -141,6 +132,47 @@ huge_time). - If the option `-t 0' was specified (end_time = 0), the loop ends when EOF is first reached in either annotation file (T or t = huge_time). + + 24 November 2002: The comparison algorithm has been very slightly modified + by the addition of an alternative criterion for accepting a match in cases + 1 and 3 below. The original match criterion for case 1 was: + if (T-t <= match_dt && T-t < abs(T-tprime)) ... + and for case 3, the original match criterion was: + if (t-T <= match_dt && t-T < abs(t-Tprime)) ... + The alternative criteria were added to account for rare cases in which + (for case 1) both t and tprime are in the match window, or (for case 3) + both T and Tprime are in the match window. + + Consider case 3. The original algorithm paired the current test and + reference annotations only if their times matched more closely than + those of the current test and next reference annotations. The modified + algorithm also checks how well the next test annotation matches the next + reference annotation; if this is a better match than that between the + current test and next reference annotations, then the current annotations + are paired. An example may make this clear; assume match_dt = 37 and + the following annotation times: + ref1 = 96 test1 = 128 + ref2 = 160 test2 = 185 + Since test1-ref1 (32) is not less than ref2-test1 (also 32), the original + algorithm would not match ref1 and test1, and would count ref1 as missed. + Since ref2-test1 (32) is not less than test2-ref2 (15), the original + algorithm would also fail to match test1 and ref2, and would count test1 + as an extra detection. The modified algorithm finds that test2-ref2 (15) + is less than ref2-test1 (32), and therefore excludes ref2 as a possible + match for test1; having done so, it then matches ref1 and test1. Similar + reasoning applies in case 1, in which the roles of ref and test are + reversed. + + Note that the only situation in which these modifications will have an + effect is when consecutive reference annotations and consecutive test + annotations occur at intervals less than or equal to twice the match + window. Generally, the match window is chosen so that this is unlikely; + using the standard window, this can only happen if both the true heart + rate and the detected heart rate exceed 200 bpm. + + Thanks to James Pardey for reporting the problem with the original + algorithm and for providing a test case that was helpful for developing + and testing these modifications. */ while ((end_time > 0L && (T <= end_time || t <= end_time)) || (end_time == -1L && T != huge_time) || @@ -148,7 +180,8 @@ if (t < T) { /* test annotation is earliest */ /* (1) If t is within the match window, and is a better match than the next test annotation, pair it. */ - if (T-t <= match_dt && T-t < abs(T-tprime)) { + if (T-t <= match_dt && + (T-t < abs(T-tprime) || abs(Tprime-tprime) < abs(T-tprime))) { pair(A, a); getref(); gettest(); @@ -163,7 +196,8 @@ else { /* reference annotation is earliest */ /* (3) If T is within the match window, and is a better match than the next reference annotation, pair it. */ - if (t-T <= match_dt && t-T < abs(t-Tprime)) { + if (t-T <= match_dt && + (t-T < abs(t-Tprime) || abs(tprime-Tprime) < abs(t-Tprime))) { pair(A, a); gettest(); getref(); diff -Naur wfdb-10.2.9/app/calsig.c wfdb-10.3.0/app/calsig.c --- wfdb-10.2.9/app/calsig.c Tue Oct 9 13:18:30 2001 +++ wfdb-10.3.0/app/calsig.c Thu Nov 14 17:14:50 2002 @@ -1,9 +1,9 @@ /* file: calsig.c G. Moody 4 March 1991 - Last revised: 9 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- -calsig: measure gains and baselines in a DB record and rewrite header -Copyright (C) 2001 George B. Moody +calsig: measure gains and baselines in a WFDB record and rewrite header +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -56,21 +56,6 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif -#ifndef BSD -#include -#else -#include -#endif #include #define UNITSLEN 20 diff -Naur wfdb-10.2.9/app/cshsetwfdb wfdb-10.3.0/app/cshsetwfdb --- wfdb-10.2.9/app/cshsetwfdb Sat Mar 11 21:25:08 2000 +++ wfdb-10.3.0/app/cshsetwfdb Fri Nov 22 22:19:12 2002 @@ -1,6 +1,7 @@ -setenv WFDB :${HOME}/database:${HOME}/database/%3r:/usr/local/database:/usr/local/database/%3r:/cdrom:/cdrom/mimicdb:/cdrom/mimicdb/%3r:/cdrom/mitdb:/cdrom/cudb:/cdrom/nstdb:/cdrom/stdb:/cdrom/vfdb:/cdrom/afdb:/cdrom/cdb:/cdrom/svdb:/cdrom/ltdb:/cdrom/odb:/cdrom/udb:/cdrom/edb:/cdrom/valedb:/cdrom/slpdb:/cdrom/mghdb:/cdrom/database:/cdrom/database/%3r:/usr/local/ahadb -setenv WFDBCAL wfdbcal +setenv WFDB ". ${HOME}/database /usr/local/database /cdrom http://www.physionet.org/physiobank/database" +# Change www.physionet.org above to your favorite mirror if you wish +setenv WFDBCAL wfdbcalx # For compatibility with older applications only -setenv DB $WFDB +setenv DB "$WFDB" setenv DBCAL $WFDBCAL diff -Naur wfdb-10.2.9/app/ecgeval.c wfdb-10.3.0/app/ecgeval.c --- wfdb-10.2.9/app/ecgeval.c Mon Dec 17 21:47:33 2001 +++ wfdb-10.3.0/app/ecgeval.c Fri Nov 22 14:46:50 2002 @@ -1,9 +1,9 @@ /* file: ecgeval.c G. Moody 22 March 1992 - Last revised: 17 December 2001 + Last revised: 22 November 2002 ------------------------------------------------------------------------------- ecgeval: Generate and run a script of commands to compare sets of annotations -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,20 +26,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif -#ifndef BSD -#include -#else -#include -#define strchr index -#endif #include #include @@ -133,14 +119,14 @@ int evalsv = 1, evalvf = 1, evalaf = 1, evalst = 1, evalst2 = 1; struct tm *now; static char rhrname[20], tname[20], tans[20], *dbfn, dbtn[5], - reportname[30], scriptname[20], *epicSoption, evalcommand[30]; + reportname[30], scriptname[20], *epicmpSoption, evalcommand[30]; static char bxbcommand[256], rxrcommand[256], mxmcommand[256], - epiccommand[256]; + epicmpcommand[256]; static char bxbfile1[40] = "bxb.out", bxbfile2[40] = "sd.out", rxrfile1[40] = "vruns.out", rxrfile2[40] = "sruns.out", - mxmfile[40] = "hr%d.out", epicaffile[40] = "af.out", - epicvffile[40] = "vf.out", epicstfile1[40] = "st.out", - epicstfile2[40] = "stm.out", plotstmfile[40] = "stm.ps"; + mxmfile[40] = "hr%d.out", epicmpaffile[40] = "af.out", + epicmpvffile[40] = "vf.out", epicmpstfile1[40] = "st.out", + epicmpstfile2[40] = "stm.out", plotstmfile[40] = "stm.ps"; static char *rname = "atr"; #ifdef __STDC__ @@ -334,10 +320,10 @@ if (!evalst2) { (void)fprintf(stderr, "ST episodes will be defined for signal 0 only.\n"); - epicSoption = " -S0 "; + epicmpSoption = " -S0 "; } else - epicSoption = " -S "; + epicmpSoption = " -S "; } (void)fprintf(stderr, "\nDo you wish to change any of your answers? [y]: "); @@ -483,24 +469,24 @@ if (evalvf) { (void)fprintf(stderr, - "Ventricular fibrillation file [%s]: ", epicvffile); - getans(epicvffile, 40); + "Ventricular fibrillation file [%s]: ", epicmpvffile); + getans(epicmpvffile, 40); } if (evalaf) { (void)fprintf(stderr, - "Atrial fibrillation file [%s]: ", epicaffile); - getans(epicaffile, 40); + "Atrial fibrillation file [%s]: ", epicmpaffile); + getans(epicmpaffile, 40); } if (evalst) { (void)fprintf(stderr, - "ST analysis file [%s]: ", epicstfile1); - getans(epicstfile1, 40); + "ST analysis file [%s]: ", epicmpstfile1); + getans(epicmpstfile1, 40); (void)fprintf(stderr, - "ST measurement file [%s]: ", epicstfile2); - getans(epicstfile2, 40); + "ST measurement file [%s]: ", epicmpstfile2); + getans(epicmpstfile2, 40); (void)fprintf(stderr, "PostScript scatter plot of ST measurements [%s]: ", plotstmfile); @@ -538,22 +524,22 @@ (void)sprintf(mxmcommand, "mxm -r %%s -a %s %s -L %s -m %%d\n", rhrname, tname, mxmfile); if (evalaf || evalvf || evalst) { - (void)sprintf(epiccommand, "epic -r %%s -a %s %s -L", rname, tname); + (void)sprintf(epicmpcommand,"epicmp -r %%s -a %s %s -L", rname, tname); if (evalaf) { - (void)strcat(epiccommand, " -A "); - (void)strcat(epiccommand, epicaffile); + (void)strcat(epicmpcommand, " -A "); + (void)strcat(epicmpcommand, epicmpaffile); } if (evalvf) { - (void)strcat(epiccommand, " -V "); - (void)strcat(epiccommand, epicvffile); + (void)strcat(epicmpcommand, " -V "); + (void)strcat(epicmpcommand, epicmpvffile); } if (evalst) { - (void)strcat(epiccommand, epicSoption); - (void)strcat(epiccommand, epicstfile1); - (void)strcat(epiccommand, " "); - (void)strcat(epiccommand, epicstfile2); + (void)strcat(epicmpcommand, epicmpSoption); + (void)strcat(epicmpcommand, epicmpstfile1); + (void)strcat(epicmpcommand, " "); + (void)strcat(epicmpcommand, epicmpstfile2); } - (void)strcat(epiccommand, "\n"); + (void)strcat(epicmpcommand, "\n"); } #ifdef MSDOS @@ -585,7 +571,7 @@ for (i = 0; i < nhr; i++) (void)fprintf(sfile, mxmcommand, record, i, i); if (evalaf || evalvf || evalst) - (void)fprintf(sfile, epiccommand, record); + (void)fprintf(sfile, epicmpcommand, record); } (void)fclose(dbf); @@ -635,7 +621,7 @@ "echo Ventricular fibrillation detection performance >>%s\n", reportname); (void)fprintf(sfile, ECHONOTHING, reportname); - (void)fprintf(sfile, "sumstats %s >>%s\n", epicvffile, reportname); + (void)fprintf(sfile, "sumstats %s >>%s\n", epicmpvffile, reportname); (void)fprintf(sfile, ECHONOTHING, reportname); } @@ -644,7 +630,7 @@ "echo Atrial fibrillation detection performance >>%s\n", reportname); (void)fprintf(sfile, ECHONOTHING, reportname); - (void)fprintf(sfile, "sumstats %s >>%s\n", epicaffile, reportname); + (void)fprintf(sfile, "sumstats %s >>%s\n", epicmpaffile, reportname); (void)fprintf(sfile, ECHONOTHING, reportname); } @@ -653,12 +639,12 @@ "echo Ischemic ST detection performance >>%s\n", reportname); (void)fprintf(sfile, ECHONOTHING, reportname); - (void)fprintf(sfile, "sumstats %s >>%s\n", epicstfile1, reportname); + (void)fprintf(sfile, "sumstats %s >>%s\n", epicmpstfile1, reportname); (void)fprintf(sfile, ECHONOTHING, reportname); (void)fprintf(sfile, ": Generate PostScript scatter plot of ST measurements\n"); - (void)fprintf(sfile, "plotstm %s >%s\n", epicstfile2, plotstmfile); + (void)fprintf(sfile, "plotstm %s >%s\n", epicmpstfile2, plotstmfile); } (void)fprintf(sfile, diff -Naur wfdb-10.2.9/app/epic.c wfdb-10.3.0/app/epic.c --- wfdb-10.2.9/app/epic.c Mon May 20 17:54:33 2002 +++ wfdb-10.3.0/app/epic.c Wed Dec 31 19:00:00 1969 @@ -1,1025 +0,0 @@ -/* file: epic.c G. Moody 3 March 1992 - Last revised: 7 November 2001 - -------------------------------------------------------------------------------- -epic: ANSI/AAMI-standard episode-by-episode annotation file comparator -Copyright (C) 2001 George B. Moody - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 2 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place - Suite 330, Boston, MA 02111-1307, USA. - -You may contact the author by e-mail (george@mit.edu) or postal mail -(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, -please visit PhysioNet (http://www.physionet.org/). -_______________________________________________________________________________ - -This program implements the VF, AF, and ST episode-by-episode comparison -algorithms described in ANSI/AAMI EC38:1998, the American National Standard for -Ambulatory electrocardiographs and ANSI/AAMI EC57:1998, the American National -Standard for Testing and reporting performance results of cardiac rhythm and -ST segment measurement algorithms; both standards are available from AAMI, -1110 N Glebe Road, Suite 220, Arlington, VA 22201 USA (http://www.aami.org/). -The relevant provisions of these standards are described in file `eval.tex', -and information about using this program is contained in file `epic.1' (both -of these files are included in the 'doc' directory of the WFDB Software -Package). - -The -f and -t options modify the comparison algorithm used by epic in ways -not permitted by these standards. These options are provided for the use of -developers, who may find them useful for obtaining a more detailed -understanding of algorithm errors. -*/ - -#include -#ifndef BSD -#include -#else -#include -#endif -#ifndef __STDC__ -extern void exit(); -#endif - -#include -#define map1 -#define map2 -#define ammap -#define mamap -#define annpos -#include - -/* Episode types */ -#define AFE 0 /* atrial fibrillation */ -#define VFE 1 /* ventricular flutter or fibrillation */ -#define ST0E 2 /* ischemic ST in signal 0 */ -#define ST1E 3 /* ischemic ST in signal 1 */ -#define STE 4 /* ischemic ST in either signal */ -#define AFLE 5 /* atrial flutter */ - -#define MAXEXCL 10 /* maximum number of intervals excluded from - comparison */ - -int aflag, sflag, s0flag, s1flag, vflag; - -main(argc, argv) -int argc; -char *argv[]; -{ - void epic(), init(), print_results(), stdc(); - - /* Read and interpret command-line arguments. */ - init(argc, argv); - - if (aflag) { - epic(0, AFE); /* check AF Se */ - epic(1, AFE); /* check AF +P */ - print_results(AFE); /* print AF statistics */ - } - - if (vflag) { - epic(0, VFE); /* check VF Se */ - epic(1, VFE); /* check VF +P */ - print_results(VFE); /* print VF statistics */ - } - - if (s0flag) { - epic(0, ST0E); /* check signal 0 ischemic ST Se */ - epic(1, ST0E); /* check signal 0 ischemic ST +P */ - stdc(0); /* check signal 0 ST deviation measurements */ - print_results(ST0E); /* print signal 0 ischemic ST statistics */ - } - - if (s1flag) { - epic(0, ST1E); /* check signal 1 ischemic ST Se */ - epic(1, ST1E); /* check signal 1 ischemic ST +P */ - stdc(1); /* check signal 1 ST deviation measurements */ - print_results(ST1E); /* print signal 1 ischemic ST statistics */ - } - - if (sflag) { - epic(0, STE); /* check two-signal ischemic ST Se */ - epic(1, STE); /* check two-signal ischemic ST +P */ - stdc(2); /* check all ST deviation measurements */ - print_results(STE); /* print two-signal ischemic ST statistics */ - } - - exit(0); /*NOTREACHED*/ -} - -char *pname; /* name by which this program was invoked */ -char *record; -char *afname, *sfname, *s0fname, *s1fname, *vfname; -int match, mismatch, nexcl, overlap_ex0, overlap_ex1; -long start_time, end_time, min_length, total_duration, total_overlap; -long ep_start[2], ep_ex0[2], ep_ex1[2], ep_end[2]; -long ex_start[MAXEXCL], ex_end[MAXEXCL]; -long ref_duration, test_duration, STP, FN, PTP, FP; -WFDB_Anninfo an[2]; - -/* Perform an episode-by-episode comparison. */ -void epic(stat, type) -unsigned int stat, type; -{ - int i; - unsigned int a, b; - long duration, overlap, find_overlap(); - void find_episode(), find_exclusions(); - - /* Find and mark any intervals to be excluded from the comparison. */ - find_exclusions(stat, type); - - /* Return to the beginning of the annotation files. */ - if (iannsettime(0L) < 0) exit(2); - - /* If stat is 0, check sensitivity; in this case, annotator 0 defines the - location of episodes. */ - if (stat == 0) { - a = 0; - b = 1; - ref_duration = 0L; - STP = FN = 0L; - } - /* Otherwise, check positive predictivity; in this case, annotator 1 - defines the location of episodes. */ - else { - a = 1; - b = 0; - test_duration = 0L; - PTP = FP = 0L; - } - - /* Initialize state variables. */ - match = mismatch = 0; - total_duration = total_overlap = 0L; - ep_start[0] = ep_start[1] = ep_end[0] = ep_end[1] = 0L; - ep_ex0[0] = ep_ex0[1] = ep_ex1[0] = ep_ex1[1] = 0L; - - /* Find the first annotator a episode which ends during the test period. */ - do { - find_episode(a, type); - } while (0L < ep_end[a] && ep_end[a] < start_time); - - /* Quit immediately if there are no such episodes. */ - if (ep_end[a] == 0L) return; - - /* Adjust the starting time of the annotator a episode if it begins during - the learning period. */ - if (ep_start[a] < start_time) ep_start[a] = start_time; - - /* Find the first annotator b episode. */ - find_episode(b, type); - - /* Process an annotator a episode for each iteration of this loop. */ - while (ep_end[a] && (end_time == 0L || ep_start[a] < end_time)) { - /* For ST comparisons only, check if each extremum occurs during the - test period; if not, disable checking of the extremum by setting - its time to 0. */ - if (type == ST0E || type == ST1E || type == STE) { - if (ep_ex0[a] <= start_time || ep_ex0[a] >= end_time) - ep_ex0[a] = 0L; - if (ep_ex1[a] <= start_time || ep_ex1[a] >= end_time) - ep_ex1[a] = 0L; - } - - /* Adjust the episode ending time if it ends after the end of the - test period. */ - if (end_time > 0L && ep_end[a] > end_time) ep_end[a] = end_time; - - duration = ep_end[a] - ep_start[a]; - - /* Adjust the episode start, end, and duration if it overlaps an - exclusion. */ - for (i = 0; i < nexcl; i++) { - if (ep_end[a] <= ex_start[i]) - break; /* no more overlaps possible */ - if (ex_start[i] <= ep_start[a] && ep_start[a] <= ex_end[i]) { - /* episode begins during an exclusion */ - if (ep_end[a] <= ex_end[i]) { - /* entire episode is contained in the exclusion */ - duration = -1L; /* ignore it */ - break; - } - else { - /* only the beginning of the episode is excluded -- - adjust duration and start */ - duration -= ep_start[a] - ex_end[i]; - ep_start[a] = ex_end[i]; - } - } - else if (ep_start[a] <= ex_start[i] && ex_start[i] <= ep_end[a]) { - /* exclusion begins during an episode */ - if (ex_end[i] < ep_end[a]) - /* entire exclusion is contained in the episode -- - adjust duration but leave start and end alone */ - duration -= ex_end[i] - ex_start[i]; - else { - /* the end of the episode is excluded -- adjust duration - and end */ - duration -= ep_end[a] - ex_start[i]; - ep_end[a] = ex_start[i]; - } - } - } - - /* If the episode is too short, ignore it. */ - if (duration < min_length) { - find_episode(a, type); - continue; - } - - /* Add the duration of this episode to the tally. */ - total_duration += duration; - - /* Get the duration of overlap; update the count of matching - episodes if appropriate, and update the overlap tally. */ - if ((overlap = find_overlap(b, type)) > 0L) { - switch (type) { - case AFE: /* AF */ - case VFE: /* VF */ - match++; - break; - case ST0E: /* ST, signal 0 */ - if (overlap_ex0 || overlap * 2L >= duration) - match++; - else - mismatch++; - break; - case ST1E: /* ST, signal 1 */ - if (overlap_ex1 || overlap * 2L >= duration) - match++; - else - mismatch++; - break; - case STE: - if (overlap_ex0 || overlap_ex1 || overlap * 2L >= duration) - match++; - else - mismatch++; - break; - } - total_overlap += overlap; - } - /* If there was no overlap, update the count of mismatched episodes. */ - else - mismatch++; - - /* Get the next episode. */ - find_episode(a, type); - } - - if (a == 0) { - STP = match; - FN = mismatch; - ref_duration = total_duration; - } - else { - PTP = match; - FP = mismatch; - test_duration = total_duration; - } -} - -int lflag; -long min_length; - -void find_episode(annotator, type) -unsigned int annotator, type; -{ - int stat, stcount = 0; - long tt; - static WFDB_Annotation annot; - - ep_start[annotator] = ep_ex0[annotator] = ep_ex1[annotator] = - ep_end[annotator] = 0L; - - /* Find beginning of episode. */ - while ((stat = getann(annotator, &annot)) == 0) { - if (type == AFE) { /* atrial fibrillation */ - if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFIB",5) == 0) { - ep_start[annotator] = annot.time; - break; - } - } - else if (type == VFE) { /* VF */ - if (annot.anntyp == VFON) { - ep_start[annotator] = annot.time; - break; - } - } - else if (type == ST0E) {/* ST episode, signal 0 */ - if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST0",4) == 0) { - ep_start[annotator] = annot.time; - break; - } - } - else if (type == ST1E) {/* ST episode, signal 1 */ - if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST1",4) == 0) { - ep_start[annotator] = annot.time; - break; - } - } - else if (type == STE) { /* ST episode, either signal */ - if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST",3) == 0) { - ep_start[annotator] = annot.time; - stcount = 1; - break; - } - } - else if (type == AFLE) {/* atrial flutter */ - if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFL",4) == 0) { - ep_start[annotator] = annot.time; - break; - } - } - } - - /* Quit if at end of annotation file. */ - if (stat != 0) return; - tt = annot.time; - - /* Find end of episode. */ - while ((stat = getann(annotator, &annot)) == 0) { - tt = annot.time; - if (type == AFE) { /* atrial fibrillation */ - if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFIB",5) != 0) { - ep_end[annotator] = annot.time; - break; - } - } - else if (type == VFE) { /* VF */ - if (annot.anntyp == VFOFF) { - ep_end[annotator] = annot.time; - break; - } - } - else if (type == ST0E) {/* ST episode, signal 0 */ - if (annot.anntyp == STCH) { - if (strncmp(annot.aux+1, "ST0", 3) == 0) { - ep_end[annotator] = annot.time; - break; - } - else if (strncmp(annot.aux+1, "AST0", 4) == 0) - ep_ex0[annotator] = annot.time; - } - } - else if (type == ST1E) {/* ST episode, signal 1 */ - if (annot.anntyp == STCH) { - if (strncmp(annot.aux+1, "ST1", 3) == 0) { - ep_end[annotator] = annot.time; - break; - } - else if (strncmp(annot.aux+1, "AST1", 4) == 0) - ep_ex1[annotator] = annot.time; - } - } - else if (type == STE) { /* ST episode, either signal */ - if (annot.anntyp == STCH) { - if (strncmp(annot.aux+1, "(ST", 3) == 0) - stcount++; - else if (strncmp(annot.aux+1, "AST0", 4) == 0) - ep_ex0[annotator] = annot.time; - else if (strncmp(annot.aux+1, "AST1", 4) == 0) - ep_ex1[annotator] = annot.time; - else if (strncmp(annot.aux+1, "ST", 2) == 0 && --stcount==0) { - ep_end[annotator] = annot.time; - break; - } - } - } - else if (type == AFLE) {/* atrial flutter */ - if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFL",4) != 0) { - ep_end[annotator] = annot.time; - break; - } - } - } - - /* If end of annotation file was reached, episode did not terminate -- - assume that it ended at the greater of tt (the time of the previous - annotation) and end_time. */ - if (stat != 0) - ep_end[annotator] = (end_time > tt) ? end_time : tt; -} - -/* This function finds and marks (in the ex_start and ex_end arrays) any - intervals which are to be excluded from the comparison. The only case - in which such intervals are currently defined is that of atrial fibrillation - positive predictivity comparisons, from which intervals of reference-marked - atrial flutter are excluded. */ - -void find_exclusions(stat, type) -unsigned int stat, type; -{ - nexcl = 0; - if (stat == 1 && type == AFE) { - if (iannsettime(0L) < 0) exit(2); - - /* Find the first exclusion which ends after the beginning of the test - period. */ - do { - find_episode(0, AFLE); - } while (0L < ep_end[0] && ep_end[0] < start_time); - - /* If there is no such exclusion, return immediately. */ - if (ep_end[0] == 0L) return; - - /* Mark one exclusion on each iteration of this loop. */ - while (0L < ep_end[0] && (end_time == 0L || ep_start[0] < end_time)) { - if (nexcl > MAXEXCL) { - (void)fprintf(stderr, - "%s: (warning) too many exclusions in record %s\n", pname, record); - (void)fprintf(stderr, -" Use the -f and -t options to process this record in segments, or recompile"); - (void)fprintf(stderr, - "%s with a larger value of MAXEXCL.\n", pname); - return; - } - ex_start[nexcl] = ep_start[0]; - ex_end[nexcl++] = ep_end[0]; - find_episode(0, AFLE); - } - } -} - -/* This function determines the duration of any episodes of the specified - type according to the specified annotator within a window defined by - ep_start[1-annotator] and ep_end[1-annotator]. It also sets the flags - overlap_ex0 and overlap_ex1 if the period of overlap includes the times - ep_ex0[1-annotator] and ep_ex1[1-annotator]. */ - -long find_overlap(annotator, type) -unsigned int annotator, type; -{ - long overlap = 0L, o_start, o_end; - - overlap_ex0 = overlap_ex1 = 0; - - /* Return immediately if there are no more episodes. */ - if (ep_end[annotator] == 0L) return (overlap); - - /* If the current episode ended before the beginning of the window, get - another. */ - while (ep_end[annotator] < ep_start[1-annotator]) { - find_episode(annotator, type); - if (ep_start[annotator] == 0L) return (overlap); - } - - /* If the current episode starts after the end of the window, return - immediately. */ - if (ep_start[annotator] > ep_end[1-annotator]) return (overlap); - - /* There is at least some overlap -- determine its extent. */ - do { - /* Ignore any portion of the current episode which precedes the - beginning of the window. */ - if (ep_start[annotator] < ep_start[1-annotator]) - o_start = ep_start[1-annotator]; - else - o_start = ep_start[annotator]; - - /* Ignore any portion of the current episode which follows the end of - the window. */ - if (ep_end[annotator] > ep_end[1-annotator]) - o_end = ep_end[1-annotator]; - else - o_end = ep_end[annotator]; - - /* Tally the overlap. */ - overlap += o_end - o_start; - - /* If the definition of exclusions is ever changed, it may be necessary - to check explicitly here to see if the interval from o_start to - o_end includes any periods which are to be excluded from the - comparison; in such a case, the duration of such periods must be - subtracted from the overlap tally. Given the current definition of - exclusions, this case should never happen. */ - - /* Check if overlap includes extrema. */ - if (o_start <= ep_ex0[1-annotator] && ep_ex0[1-annotator] <= o_end) - overlap_ex0 = 1; - if (o_start <= ep_ex1[1-annotator] && ep_ex1[1-annotator] <= o_end) - overlap_ex1 = 1; - - /* If the current episode ends after the end of the window, stop. */ - if (ep_end[annotator] >= ep_end[1-annotator]) - break; - /* Otherwise, get the next episode and see if it also falls in the - window. */ - find_episode(annotator, type); - } while (0L < ep_start[annotator] && - ep_start[annotator] < ep_end[1-annotator]); - return (overlap); -} - -FILE *ofile; -long tref; /* time of the most recent reference ST extremum */ -int sigref, stref; /* signal number and ST deviation for the most recent - reference ST extremum */ - -/* This function finds the next reference ST extremum annotation and sets the - variables tref, sigref, and stref appropriately. */ - -int find_reference_extremum(mode) -int mode; /* 0: signal 0 only, 1: signal 1 only, 2: both signals */ -{ - WFDB_Annotation refann; - - while (getann(0, &refann) == 0) { - if (refann.anntyp == STCH && refann.aux != NULL && - strncmp(refann.aux+1, "AST", 3) == 0) { - switch (*(refann.aux+4)) { - case '0': /* signal 0 extremum */ - if (mode != 1) { - tref = refann.time; - sigref = 0; - stref = atoi(refann.aux+5); - return (1); - } - break; - case '1': /* signal 1 extremum */ - if (mode != 0) { - tref = refann.time; - sigref = 1; - stref = atoi(refann.aux+5); - return (1); - } - break; - case '+': /* extremum in single-lead record */ - case '-': - if (mode != 1) { - tref = refann.time; - sigref = 0; - stref = atoi(refann.aux+4); - return (1); - } - break; - } - } - } - return (0); -} - -char *sd0fname, *sd1fname, *sdfname; - -/* This function compares ST measurements. Since reference measurements are - only available at the extremum of each episode, stdc finds the test - measurement which is nearest in time to each reference measurement. - Each pair of measurements is recorded in the output file. */ - -void stdc(mode) -int mode; /* 0: signal 0 only, 1: signal 1 only, 2: both signals */ -{ - char *ofname; - WFDB_Annotation testann; - static int pst0, pst1, stat, st0, st1, sttest; - static long pttest; - - /* Return to the beginning of the annotation files. */ - if (iannsettime(0L) < 0) exit(2); - - switch (mode) { - case 0: ofname = sd0fname; break; - case 1: ofname = sd1fname; break; - case 2: ofname = sdfname; break; - } - - /* Open the output file. */ - if (strcmp(ofname, "-")) { - if ((ofile = fopen(ofname, "r")) == NULL) { - if ((ofile = fopen(ofname, "w")) == NULL) { - (void)fprintf(stderr, "%s: can't create %s\n", - pname, ofname); - exit(3); - } - (void)fprintf(ofile, "(ST measurements)\n"); - (void)fprintf(ofile, "Record Time Signal Reference Test\n"); - } - else { - (void)fclose(ofile); - if ((ofile = fopen(ofname, "a")) == NULL) { - (void)fprintf(stderr, "%s: can't modify %s\n", - pname, ofname); - exit(3); - } - } - } - else ofile = stdout; - - /* Check one reference ST measurement on each iteration. */ - while (find_reference_extremum(mode)) { - /* Find the first test beat annotation after tref. */ - while ((stat = getann(1, &testann)) == 0) { - /* Ignore non-beat annotations. */ - if (!isqrs(testann.anntyp)) continue; - pst0 = st0; - pst1 = st1; - /* Read test ST measurements (assumed to be the first two - numbers in the aux field of the test beat annotation). - If measurements are absent, assume they were unchanged - since the previous beat annotation (initially zero). */ - if (testann.aux != NULL) - (void)sscanf(testann.aux+1, "%d%d", &st0, &st1); - if (testann.time > tref) - break; - } - if (stat != 0 || tref - pttest >= testann.time - tref) - sttest = sigref ? st1 : st0; /* current annotation is closer */ - else - sttest = sigref ? pst1 : pst0; /* previous annotation was closer */ - (void)fprintf(ofile, "%6s %s %7d %10d %5d", record, - timstr(tref), sigref, stref, sttest); - if (stref - sttest > 100 || sttest - stref > 100) - (void)fprintf(ofile, " *"); - (void)fprintf(ofile, "\n"); - pttest = testann.time; - } - - if (ofile != stdout) - (void)fclose(ofile); -} - -/* `pstat' prints a statistic described by s, defined as the quotient of a and - b expressed in percentage units. Undefined values are indicated by `-'. */ - -void pstat(s, a, b) -char *s; -long a, b; -{ - if (!lflag) { - (void)fprintf(ofile, "%s:", s); - if (b <= 0) (void)fprintf(ofile, " - "); - else (void)fprintf(ofile, " %3d%%", (int)((100.*a)/b + 0.5)); - (void)fprintf(ofile, " (%ld/%ld)\n", a, b); - } - else if (b <= 0) (void)fprintf(ofile, " -"); - else (void)fprintf(ofile, " %3d", (int)((100.*a)/b + 0.5)); -} - - -/* `tstat' prints a statistic as above, but prints the numerator and - denominator as times. */ - -void tstat(s, a, b) -char *s; -long a, b; -{ - char *lmstimstr(); - - if (!lflag) { - (void)fprintf(ofile, "%s:", s); - if (b <= 0) (void)fprintf(ofile, " - "); - else (void)fprintf(ofile, " %3d%%", (int)((100.*a)/b + 0.5)); - (void)fprintf(ofile, " (%s", lmstimstr(a)); - (void)fprintf(ofile, "/%s)\n", lmstimstr(b)); - } - else if (b <= 0) (void)fprintf(ofile, " -"); - else (void)fprintf(ofile, " %3d", (int)((100.*a)/b + 0.5)); -} - -char *lmstimstr(t) -long t; -{ - char *p = mstimstr(t); - - while (*p == ' ') - p++; - return (p); -} - -void print_results(type) -int type; -{ - char *ofname; - - switch (type) { - case AFE: ofname = afname; break; - case VFE: ofname = vfname; break; - case ST0E:ofname = s0fname; break; - case ST1E:ofname = s1fname; break; - case STE: ofname = sfname; break; - } - - /* Open output file. If line-format output was selected, write column - headings only if the file must be created from scratch. */ - if (strcmp(ofname, "-")) { - if ((ofile = fopen(ofname, "r")) == NULL) { - if ((ofile = fopen(ofname, "w")) == NULL) { - (void)fprintf(stderr, "%s: can't create %s\n", - pname, ofname); - exit(3); - } - if (lflag) { - switch (type) { - case AFE: - (void)fprintf(ofile, "(AF detection)\n"); - break; - case VFE: - (void)fprintf(ofile, "(VF detection)\n"); - break; - case ST0E: - (void)fprintf(ofile,"(Ischemic ST detection, signal 0)\n"); - break; - case ST1E: - (void)fprintf(ofile,"(Ischemic ST detection, signal 1)\n"); - break; - case STE: - (void)fprintf(ofile, - "(Ischemic ST detection, both signals)\n"); - break; - } - (void)fprintf(ofile, "Record TPs FN TPp FP"); - (void)fprintf(ofile, - " ESe E+P DSe D+P Ref duration Test duration \n"); - } - } - else { - (void)fclose(ofile); - if ((ofile = fopen(ofname, "a")) == NULL) { - (void)fprintf(stderr, "%s: can't modify %s\n", - pname, ofname); - exit(3); - } - } - } - else ofile = stdout; - - if (lflag) - (void)fprintf(ofile, "%6s %4ld %4ld %4ld %4ld ", - record, STP, FN, PTP, FP); - else { - switch (type) { - case AFE: - (void)fprintf(ofile, - "AF episode-by-episode comparison results for record %s\n", - record); - break; - case VFE: - (void)fprintf(ofile, - "VF episode-by-episode comparison results for record %s\n", - record); - break; - case ST0E: - (void)fprintf(ofile, - "ST episode-by-episode comparison results for record %s, signal 0\n", - record); - break; - case ST1E: - (void)fprintf(ofile, - "ST episode-by-episode comparison results for record %s, signal 1\n", - record); - break; - case STE: - (void)fprintf(ofile, - "ST episode-by-episode comparison results for record %s, both signals\n", - record); - break; - default: - break; - } - (void)fprintf(ofile, "Reference annotator: %s\n", an[0].name); - (void)fprintf(ofile, " Test annotator: %s\n\n", an[1].name); - } - pstat(" Episode sensitivity", STP, STP + FN); - pstat(" Episode positive predictivity", PTP, PTP + FP); - tstat(" Duration sensitivity", total_overlap, ref_duration); - tstat("Duration positive predictivity", total_overlap, test_duration); - if (!lflag) - (void)fprintf(ofile, "Duration of reference episodes:"); - (void)fprintf(ofile, " %s", mstimstr(ref_duration)); - if (!lflag) - (void)fprintf(ofile, "\n Duration of test episodes:"); - else - (void)fprintf(ofile, " "); - (void)fprintf(ofile, " %s\n", mstimstr(test_duration)); - - if (ofile != stdout) - (void)fclose(ofile); -} - -void init(argc, argv) -int argc; -char *argv[]; -{ - int i; - char *prog_name(); - void help(); - - pname = prog_name(argv[0]); - for (i = 1; i < argc; i++) { - if (*argv[i] == '-') switch (*(argv[i]+1)) { - case 'a': /* annotator names follow */ - if (++i >= argc-1) { - (void)fprintf(stderr, - "%s: reference and test annotator names must follow -a\n", - pname); - exit(1); - } - an[0].name = argv[i]; - an[1].name = argv[++i]; - break; - case 'A': /* perform AF comparison */ - if (++i >= argc) { - (void)fprintf(stderr, "%s: output file name must follow -A\n", - pname); - exit(1); - } - afname = argv[i]; - aflag = 1; - break; - case 'f': /* start time follows */ - if (++i >= argc) { - (void)fprintf(stderr,"%s: start time must follow -f\n", pname); - exit(1); - } - start_time = i; /* save arg index, convert to samples later, - when record has been opened and sampling - frequency is known */ - break; - case 'h': /* print usage summary */ - help(); - exit(1); - break; - case 'i': /* minimum episode length follows */ - if (++i >= argc) { - (void)fprintf(stderr, - "%s: minimum episode length must follow -i\n", pname); - exit(1); - } - min_length = i; - break; - case 'l': /* line-format output */ - case 'L': /* treat -L and -l the same way, for - consistency with `bxb' and `rxr' usage */ - lflag = 1; - break; - case 'r': /* record name follows */ - if (++i >= argc) { - (void)fprintf(stderr, - "%s: record name must follow -r\n", pname); - exit(1); - } - record = argv[i]; - break; - case 'S': /* perform ST comparison */ - if (++i >= argc-1) { - (void)fprintf(stderr, - "%s: two output file names must follow %s\n", - pname, argv[i-1]); - exit(1); - } - switch (argv[i-1][2]) { - case '0': - s0fname = argv[i++]; - sd0fname = argv[i]; - s0flag = 1; - break; - case '1': - s1fname = argv[i++]; - sd1fname = argv[i]; - s1flag = 1; - break; - case '\0': - sfname = argv[i++]; - sdfname = argv[i]; - sflag = 1; - break; - default: - (void)fprintf(stderr, - "%s: unrecognized option %s\n", pname, argv[i-1]); - exit(1); - } - break; - case 't': /* end time follows */ - if (++i >= argc) { - (void)fprintf(stderr, "%s: end time must follow -t\n", pname); - exit(1); - } - end_time = i; - break; - case 'V': /* perform VF comparison */ - if (++i >= argc) { - (void)fprintf(stderr, "%s: output file name must follow -V\n", - pname); - exit(1); - } - vfname = argv[i]; - 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 || !an[0].name) { - help(); - exit(1); - } - - if (start_time != 0L || end_time != 0L || min_length != 0) - (void)fprintf(stderr,"%s: (warning) nonstandard comparison selected\n", - pname); - - if (sampfreq(record) <= 0) { - (void)fprintf(stderr, - "%s: (warning) %g Hz sampling frequency assumed\n", - pname, WFDB_DEFFREQ); - (void)setsampfreq(WFDB_DEFFREQ); - } - - /* Set the minimum episode length and the times of the start and end of - the test period. */ - if (min_length) - min_length = strtim(argv[min_length]); - if (start_time) { - start_time = strtim(argv[(int)start_time]); - if (start_time < (WFDB_Time)0) start_time = -start_time; - } - else - start_time = strtim("5:0"); /* 5 minutes */ - if (end_time) { - end_time = strtim(argv[(int)end_time]); - if (end_time < (WFDB_Time)0) end_time = -end_time; - } - else if ((end_time = strtim("e")) == 0L) - end_time = -1L; /* record length unavailable -- go to end of - reference annotation file */ - if (end_time > 0L && end_time < start_time) { - (void)fprintf(stderr, "%s: improper interval specified\n", pname); - exit(1); - } - an[0].stat = an[1].stat = WFDB_READ; - - /* Open annotation files. */ - if (annopen(record, an, 2) < 0) exit(2); -} - -static char *help_strings[] = { - "usage: %s -r RECORD -a REF TEST [OPTIONS ...]\n", - "where RECORD is the record name; REF is reference annotator name; TEST is", - "the test annotator name; and OPTIONS may include any of:", - " -A FILE append AF reports to FILE", - " -f TIME begin comparison at specified TIME (default: 5 minutes", - " after beginning of record)", - " -h print this usage summary", - " -i TIME ignore episodes shorter than TIME (default: 0 seconds)", - " -l write reports in line format (default: matrix format)", - " -L same as -l", - " -S FILE FILE2 append ST reports for both signals to FILE, and ST", - " measurements to FILE2", - " -S0 FILE FILE2 append ST reports for signal 0 to FILE, and ST measurements", - " to FILE2", - " -S1 FILE FILE2 append ST reports for signal 1 to FILE, and ST measurements", - " to FILE2", - " -t TIME stop comparison at specified TIME (default: end of record", - " if defined, end of reference annotation file otherwise;", - " if TIME is 0, the comparison ends when the end of either", - " annotation file is reached)", - " -V FILE append VF reports to FILE", -NULL -}; - -void help() -{ - int i; - - (void)fprintf(stderr, help_strings[0], pname); - for (i = 1; help_strings[i] != NULL; i++) - (void)fprintf(stderr, "%s\n", help_strings[i]); -} - -char *prog_name(s) -char *s; -{ - char *p = s + strlen(s); - -#ifdef MSDOS - while (p >= s && *p != '\\' && *p != ':') { - if (*p == '.') - *p = '\0'; /* strip off extension */ - if ('A' <= *p && *p <= 'Z') - *p += 'a' - 'A'; /* convert to lower case */ - p--; - } -#else - while (p >= s && *p != '/') - p--; -#endif - return (p+1); -} diff -Naur wfdb-10.2.9/app/epicmp.c wfdb-10.3.0/app/epicmp.c --- wfdb-10.2.9/app/epicmp.c Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/app/epicmp.c Fri Nov 22 14:32:02 2002 @@ -0,0 +1,1016 @@ +/* file: epicmp.c G. Moody 3 March 1992 + Last revised: 14 November 2002 + +------------------------------------------------------------------------------- +epicmp: ANSI/AAMI-standard episode-by-episode annotation file comparator +Copyright (C) 2002 George B. Moody + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (george@mit.edu) or postal mail +(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +_______________________________________________________________________________ + +This program (formerly known as 'epic') implements the VF, AF, and ST episode- +by-episode comparison algorithms described in ANSI/AAMI EC38:1998, the American +National Standard for Ambulatory electrocardiographs and ANSI/AAMI EC57:1998, +the American National Standard for Testing and reporting performance results of +cardiac rhythm and ST segment measurement algorithms; both standards are +available from AAMI, 1110 N Glebe Road, Suite 220, Arlington, VA 22201 USA +(http://www.aami.org/). The relevant provisions of these standards are +described in file `eval.tex', and information about using this program is +contained in file `epicmp.1' (both of these files are included in the +'doc/wag-src/' directory of the WFDB Software Package). + +The -f and -t options modify the comparison algorithm used by epicmp in ways +not permitted by these standards. These options are provided for the use of +developers, who may find them useful for obtaining a more detailed +understanding of algorithm errors. +*/ + +#include +#include +#define map1 +#define map2 +#define ammap +#define mamap +#define annpos +#include + +/* Episode types */ +#define AFE 0 /* atrial fibrillation */ +#define VFE 1 /* ventricular flutter or fibrillation */ +#define ST0E 2 /* ischemic ST in signal 0 */ +#define ST1E 3 /* ischemic ST in signal 1 */ +#define STE 4 /* ischemic ST in either signal */ +#define AFLE 5 /* atrial flutter */ + +#define MAXEXCL 10 /* maximum number of intervals excluded from + comparison */ + +int aflag, sflag, s0flag, s1flag, vflag; + +main(argc, argv) +int argc; +char *argv[]; +{ + void epicmp(), init(), print_results(), stdc(); + + /* Read and interpret command-line arguments. */ + init(argc, argv); + + if (aflag) { + epicmp(0, AFE); /* check AF Se */ + epicmp(1, AFE); /* check AF +P */ + print_results(AFE); /* print AF statistics */ + } + + if (vflag) { + epicmp(0, VFE); /* check VF Se */ + epicmp(1, VFE); /* check VF +P */ + print_results(VFE); /* print VF statistics */ + } + + if (s0flag) { + epicmp(0, ST0E); /* check signal 0 ischemic ST Se */ + epicmp(1, ST0E); /* check signal 0 ischemic ST +P */ + stdc(0); /* check signal 0 ST deviation measurements */ + print_results(ST0E); /* print signal 0 ischemic ST statistics */ + } + + if (s1flag) { + epicmp(0, ST1E); /* check signal 1 ischemic ST Se */ + epicmp(1, ST1E); /* check signal 1 ischemic ST +P */ + stdc(1); /* check signal 1 ST deviation measurements */ + print_results(ST1E); /* print signal 1 ischemic ST statistics */ + } + + if (sflag) { + epicmp(0, STE); /* check two-signal ischemic ST Se */ + epicmp(1, STE); /* check two-signal ischemic ST +P */ + stdc(2); /* check all ST deviation measurements */ + print_results(STE); /* print two-signal ischemic ST statistics */ + } + + exit(0); /*NOTREACHED*/ +} + +char *pname; /* name by which this program was invoked */ +char *record; +char *afname, *sfname, *s0fname, *s1fname, *vfname; +int match, mismatch, nexcl, overlap_ex0, overlap_ex1; +long start_time, end_time, min_length, total_duration, total_overlap; +long ep_start[2], ep_ex0[2], ep_ex1[2], ep_end[2]; +long ex_start[MAXEXCL], ex_end[MAXEXCL]; +long ref_duration, test_duration, STP, FN, PTP, FP; +WFDB_Anninfo an[2]; + +/* Perform an episode-by-episode comparison. */ +void epicmp(stat, type) +unsigned int stat, type; +{ + int i; + unsigned int a, b; + long duration, overlap, find_overlap(); + void find_episode(), find_exclusions(); + + /* Find and mark any intervals to be excluded from the comparison. */ + find_exclusions(stat, type); + + /* Return to the beginning of the annotation files. */ + if (iannsettime(0L) < 0) exit(2); + + /* If stat is 0, check sensitivity; in this case, annotator 0 defines the + location of episodes. */ + if (stat == 0) { + a = 0; + b = 1; + ref_duration = 0L; + STP = FN = 0L; + } + /* Otherwise, check positive predictivity; in this case, annotator 1 + defines the location of episodes. */ + else { + a = 1; + b = 0; + test_duration = 0L; + PTP = FP = 0L; + } + + /* Initialize state variables. */ + match = mismatch = 0; + total_duration = total_overlap = 0L; + ep_start[0] = ep_start[1] = ep_end[0] = ep_end[1] = 0L; + ep_ex0[0] = ep_ex0[1] = ep_ex1[0] = ep_ex1[1] = 0L; + + /* Find the first annotator a episode which ends during the test period. */ + do { + find_episode(a, type); + } while (0L < ep_end[a] && ep_end[a] < start_time); + + /* Quit immediately if there are no such episodes. */ + if (ep_end[a] == 0L) return; + + /* Adjust the starting time of the annotator a episode if it begins during + the learning period. */ + if (ep_start[a] < start_time) ep_start[a] = start_time; + + /* Find the first annotator b episode. */ + find_episode(b, type); + + /* Process an annotator a episode for each iteration of this loop. */ + while (ep_end[a] && (end_time == 0L || ep_start[a] < end_time)) { + /* For ST comparisons only, check if each extremum occurs during the + test period; if not, disable checking of the extremum by setting + its time to 0. */ + if (type == ST0E || type == ST1E || type == STE) { + if (ep_ex0[a] <= start_time || ep_ex0[a] >= end_time) + ep_ex0[a] = 0L; + if (ep_ex1[a] <= start_time || ep_ex1[a] >= end_time) + ep_ex1[a] = 0L; + } + + /* Adjust the episode ending time if it ends after the end of the + test period. */ + if (end_time > 0L && ep_end[a] > end_time) ep_end[a] = end_time; + + duration = ep_end[a] - ep_start[a]; + + /* Adjust the episode start, end, and duration if it overlaps an + exclusion. */ + for (i = 0; i < nexcl; i++) { + if (ep_end[a] <= ex_start[i]) + break; /* no more overlaps possible */ + if (ex_start[i] <= ep_start[a] && ep_start[a] <= ex_end[i]) { + /* episode begins during an exclusion */ + if (ep_end[a] <= ex_end[i]) { + /* entire episode is contained in the exclusion */ + duration = -1L; /* ignore it */ + break; + } + else { + /* only the beginning of the episode is excluded -- + adjust duration and start */ + duration -= ep_start[a] - ex_end[i]; + ep_start[a] = ex_end[i]; + } + } + else if (ep_start[a] <= ex_start[i] && ex_start[i] <= ep_end[a]) { + /* exclusion begins during an episode */ + if (ex_end[i] < ep_end[a]) + /* entire exclusion is contained in the episode -- + adjust duration but leave start and end alone */ + duration -= ex_end[i] - ex_start[i]; + else { + /* the end of the episode is excluded -- adjust duration + and end */ + duration -= ep_end[a] - ex_start[i]; + ep_end[a] = ex_start[i]; + } + } + } + + /* If the episode is too short, ignore it. */ + if (duration < min_length) { + find_episode(a, type); + continue; + } + + /* Add the duration of this episode to the tally. */ + total_duration += duration; + + /* Get the duration of overlap; update the count of matching + episodes if appropriate, and update the overlap tally. */ + if ((overlap = find_overlap(b, type)) > 0L) { + switch (type) { + case AFE: /* AF */ + case VFE: /* VF */ + match++; + break; + case ST0E: /* ST, signal 0 */ + if (overlap_ex0 || overlap * 2L >= duration) + match++; + else + mismatch++; + break; + case ST1E: /* ST, signal 1 */ + if (overlap_ex1 || overlap * 2L >= duration) + match++; + else + mismatch++; + break; + case STE: + if (overlap_ex0 || overlap_ex1 || overlap * 2L >= duration) + match++; + else + mismatch++; + break; + } + total_overlap += overlap; + } + /* If there was no overlap, update the count of mismatched episodes. */ + else + mismatch++; + + /* Get the next episode. */ + find_episode(a, type); + } + + if (a == 0) { + STP = match; + FN = mismatch; + ref_duration = total_duration; + } + else { + PTP = match; + FP = mismatch; + test_duration = total_duration; + } +} + +int lflag; +long min_length; + +void find_episode(annotator, type) +unsigned int annotator, type; +{ + int stat, stcount = 0; + long tt; + static WFDB_Annotation annot; + + ep_start[annotator] = ep_ex0[annotator] = ep_ex1[annotator] = + ep_end[annotator] = 0L; + + /* Find beginning of episode. */ + while ((stat = getann(annotator, &annot)) == 0) { + if (type == AFE) { /* atrial fibrillation */ + if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFIB",5) == 0) { + ep_start[annotator] = annot.time; + break; + } + } + else if (type == VFE) { /* VF */ + if (annot.anntyp == VFON) { + ep_start[annotator] = annot.time; + break; + } + } + else if (type == ST0E) {/* ST episode, signal 0 */ + if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST0",4) == 0) { + ep_start[annotator] = annot.time; + break; + } + } + else if (type == ST1E) {/* ST episode, signal 1 */ + if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST1",4) == 0) { + ep_start[annotator] = annot.time; + break; + } + } + else if (type == STE) { /* ST episode, either signal */ + if (annot.anntyp == STCH && strncmp(annot.aux+1,"(ST",3) == 0) { + ep_start[annotator] = annot.time; + stcount = 1; + break; + } + } + else if (type == AFLE) {/* atrial flutter */ + if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFL",4) == 0) { + ep_start[annotator] = annot.time; + break; + } + } + } + + /* Quit if at end of annotation file. */ + if (stat != 0) return; + tt = annot.time; + + /* Find end of episode. */ + while ((stat = getann(annotator, &annot)) == 0) { + tt = annot.time; + if (type == AFE) { /* atrial fibrillation */ + if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFIB",5) != 0) { + ep_end[annotator] = annot.time; + break; + } + } + else if (type == VFE) { /* VF */ + if (annot.anntyp == VFOFF) { + ep_end[annotator] = annot.time; + break; + } + } + else if (type == ST0E) {/* ST episode, signal 0 */ + if (annot.anntyp == STCH) { + if (strncmp(annot.aux+1, "ST0", 3) == 0) { + ep_end[annotator] = annot.time; + break; + } + else if (strncmp(annot.aux+1, "AST0", 4) == 0) + ep_ex0[annotator] = annot.time; + } + } + else if (type == ST1E) {/* ST episode, signal 1 */ + if (annot.anntyp == STCH) { + if (strncmp(annot.aux+1, "ST1", 3) == 0) { + ep_end[annotator] = annot.time; + break; + } + else if (strncmp(annot.aux+1, "AST1", 4) == 0) + ep_ex1[annotator] = annot.time; + } + } + else if (type == STE) { /* ST episode, either signal */ + if (annot.anntyp == STCH) { + if (strncmp(annot.aux+1, "(ST", 3) == 0) + stcount++; + else if (strncmp(annot.aux+1, "AST0", 4) == 0) + ep_ex0[annotator] = annot.time; + else if (strncmp(annot.aux+1, "AST1", 4) == 0) + ep_ex1[annotator] = annot.time; + else if (strncmp(annot.aux+1, "ST", 2) == 0 && --stcount==0) { + ep_end[annotator] = annot.time; + break; + } + } + } + else if (type == AFLE) {/* atrial flutter */ + if (annot.anntyp==RHYTHM && strncmp(annot.aux+1,"(AFL",4) != 0) { + ep_end[annotator] = annot.time; + break; + } + } + } + + /* If end of annotation file was reached, episode did not terminate -- + assume that it ended at the greater of tt (the time of the previous + annotation) and end_time. */ + if (stat != 0) + ep_end[annotator] = (end_time > tt) ? end_time : tt; +} + +/* This function finds and marks (in the ex_start and ex_end arrays) any + intervals which are to be excluded from the comparison. The only case + in which such intervals are currently defined is that of atrial fibrillation + positive predictivity comparisons, from which intervals of reference-marked + atrial flutter are excluded. */ + +void find_exclusions(stat, type) +unsigned int stat, type; +{ + nexcl = 0; + if (stat == 1 && type == AFE) { + if (iannsettime(0L) < 0) exit(2); + + /* Find the first exclusion which ends after the beginning of the test + period. */ + do { + find_episode(0, AFLE); + } while (0L < ep_end[0] && ep_end[0] < start_time); + + /* If there is no such exclusion, return immediately. */ + if (ep_end[0] == 0L) return; + + /* Mark one exclusion on each iteration of this loop. */ + while (0L < ep_end[0] && (end_time == 0L || ep_start[0] < end_time)) { + if (nexcl > MAXEXCL) { + (void)fprintf(stderr, + "%s: (warning) too many exclusions in record %s\n", pname, record); + (void)fprintf(stderr, +" Use the -f and -t options to process this record in segments, or recompile"); + (void)fprintf(stderr, + "%s with a larger value of MAXEXCL.\n", pname); + return; + } + ex_start[nexcl] = ep_start[0]; + ex_end[nexcl++] = ep_end[0]; + find_episode(0, AFLE); + } + } +} + +/* This function determines the duration of any episodes of the specified + type according to the specified annotator within a window defined by + ep_start[1-annotator] and ep_end[1-annotator]. It also sets the flags + overlap_ex0 and overlap_ex1 if the period of overlap includes the times + ep_ex0[1-annotator] and ep_ex1[1-annotator]. */ + +long find_overlap(annotator, type) +unsigned int annotator, type; +{ + long overlap = 0L, o_start, o_end; + + overlap_ex0 = overlap_ex1 = 0; + + /* Return immediately if there are no more episodes. */ + if (ep_end[annotator] == 0L) return (overlap); + + /* If the current episode ended before the beginning of the window, get + another. */ + while (ep_end[annotator] < ep_start[1-annotator]) { + find_episode(annotator, type); + if (ep_start[annotator] == 0L) return (overlap); + } + + /* If the current episode starts after the end of the window, return + immediately. */ + if (ep_start[annotator] > ep_end[1-annotator]) return (overlap); + + /* There is at least some overlap -- determine its extent. */ + do { + /* Ignore any portion of the current episode which precedes the + beginning of the window. */ + if (ep_start[annotator] < ep_start[1-annotator]) + o_start = ep_start[1-annotator]; + else + o_start = ep_start[annotator]; + + /* Ignore any portion of the current episode which follows the end of + the window. */ + if (ep_end[annotator] > ep_end[1-annotator]) + o_end = ep_end[1-annotator]; + else + o_end = ep_end[annotator]; + + /* Tally the overlap. */ + overlap += o_end - o_start; + + /* If the definition of exclusions is ever changed, it may be necessary + to check explicitly here to see if the interval from o_start to + o_end includes any periods which are to be excluded from the + comparison; in such a case, the duration of such periods must be + subtracted from the overlap tally. Given the current definition of + exclusions, this case should never happen. */ + + /* Check if overlap includes extrema. */ + if (o_start <= ep_ex0[1-annotator] && ep_ex0[1-annotator] <= o_end) + overlap_ex0 = 1; + if (o_start <= ep_ex1[1-annotator] && ep_ex1[1-annotator] <= o_end) + overlap_ex1 = 1; + + /* If the current episode ends after the end of the window, stop. */ + if (ep_end[annotator] >= ep_end[1-annotator]) + break; + /* Otherwise, get the next episode and see if it also falls in the + window. */ + find_episode(annotator, type); + } while (0L < ep_start[annotator] && + ep_start[annotator] < ep_end[1-annotator]); + return (overlap); +} + +FILE *ofile; +long tref; /* time of the most recent reference ST extremum */ +int sigref, stref; /* signal number and ST deviation for the most recent + reference ST extremum */ + +/* This function finds the next reference ST extremum annotation and sets the + variables tref, sigref, and stref appropriately. */ + +int find_reference_extremum(mode) +int mode; /* 0: signal 0 only, 1: signal 1 only, 2: both signals */ +{ + WFDB_Annotation refann; + + while (getann(0, &refann) == 0) { + if (refann.anntyp == STCH && refann.aux != NULL && + strncmp(refann.aux+1, "AST", 3) == 0) { + switch (*(refann.aux+4)) { + case '0': /* signal 0 extremum */ + if (mode != 1) { + tref = refann.time; + sigref = 0; + stref = atoi(refann.aux+5); + return (1); + } + break; + case '1': /* signal 1 extremum */ + if (mode != 0) { + tref = refann.time; + sigref = 1; + stref = atoi(refann.aux+5); + return (1); + } + break; + case '+': /* extremum in single-lead record */ + case '-': + if (mode != 1) { + tref = refann.time; + sigref = 0; + stref = atoi(refann.aux+4); + return (1); + } + break; + } + } + } + return (0); +} + +char *sd0fname, *sd1fname, *sdfname; + +/* This function compares ST measurements. Since reference measurements are + only available at the extremum of each episode, stdc finds the test + measurement which is nearest in time to each reference measurement. + Each pair of measurements is recorded in the output file. */ + +void stdc(mode) +int mode; /* 0: signal 0 only, 1: signal 1 only, 2: both signals */ +{ + char *ofname; + WFDB_Annotation testann; + static int pst0, pst1, stat, st0, st1, sttest; + static long pttest; + + /* Return to the beginning of the annotation files. */ + if (iannsettime(0L) < 0) exit(2); + + switch (mode) { + case 0: ofname = sd0fname; break; + case 1: ofname = sd1fname; break; + case 2: ofname = sdfname; break; + } + + /* Open the output file. */ + if (strcmp(ofname, "-")) { + if ((ofile = fopen(ofname, "r")) == NULL) { + if ((ofile = fopen(ofname, "w")) == NULL) { + (void)fprintf(stderr, "%s: can't create %s\n", + pname, ofname); + exit(3); + } + (void)fprintf(ofile, "(ST measurements)\n"); + (void)fprintf(ofile, "Record Time Signal Reference Test\n"); + } + else { + (void)fclose(ofile); + if ((ofile = fopen(ofname, "a")) == NULL) { + (void)fprintf(stderr, "%s: can't modify %s\n", + pname, ofname); + exit(3); + } + } + } + else ofile = stdout; + + /* Check one reference ST measurement on each iteration. */ + while (find_reference_extremum(mode)) { + /* Find the first test beat annotation after tref. */ + while ((stat = getann(1, &testann)) == 0) { + /* Ignore non-beat annotations. */ + if (!isqrs(testann.anntyp)) continue; + pst0 = st0; + pst1 = st1; + /* Read test ST measurements (assumed to be the first two + numbers in the aux field of the test beat annotation). + If measurements are absent, assume they were unchanged + since the previous beat annotation (initially zero). */ + if (testann.aux != NULL) + (void)sscanf(testann.aux+1, "%d%d", &st0, &st1); + if (testann.time > tref) + break; + } + if (stat != 0 || tref - pttest >= testann.time - tref) + sttest = sigref ? st1 : st0; /* current annotation is closer */ + else + sttest = sigref ? pst1 : pst0; /* previous annotation was closer */ + (void)fprintf(ofile, "%6s %s %7d %10d %5d", record, + timstr(tref), sigref, stref, sttest); + if (stref - sttest > 100 || sttest - stref > 100) + (void)fprintf(ofile, " *"); + (void)fprintf(ofile, "\n"); + pttest = testann.time; + } + + if (ofile != stdout) + (void)fclose(ofile); +} + +/* `pstat' prints a statistic described by s, defined as the quotient of a and + b expressed in percentage units. Undefined values are indicated by `-'. */ + +void pstat(s, a, b) +char *s; +long a, b; +{ + if (!lflag) { + (void)fprintf(ofile, "%s:", s); + if (b <= 0) (void)fprintf(ofile, " - "); + else (void)fprintf(ofile, " %3d%%", (int)((100.*a)/b + 0.5)); + (void)fprintf(ofile, " (%ld/%ld)\n", a, b); + } + else if (b <= 0) (void)fprintf(ofile, " -"); + else (void)fprintf(ofile, " %3d", (int)((100.*a)/b + 0.5)); +} + + +/* `tstat' prints a statistic as above, but prints the numerator and + denominator as times. */ + +void tstat(s, a, b) +char *s; +long a, b; +{ + char *lmstimstr(); + + if (!lflag) { + (void)fprintf(ofile, "%s:", s); + if (b <= 0) (void)fprintf(ofile, " - "); + else (void)fprintf(ofile, " %3d%%", (int)((100.*a)/b + 0.5)); + (void)fprintf(ofile, " (%s", lmstimstr(a)); + (void)fprintf(ofile, "/%s)\n", lmstimstr(b)); + } + else if (b <= 0) (void)fprintf(ofile, " -"); + else (void)fprintf(ofile, " %3d", (int)((100.*a)/b + 0.5)); +} + +char *lmstimstr(t) +long t; +{ + char *p = mstimstr(t); + + while (*p == ' ') + p++; + return (p); +} + +void print_results(type) +int type; +{ + char *ofname; + + switch (type) { + case AFE: ofname = afname; break; + case VFE: ofname = vfname; break; + case ST0E:ofname = s0fname; break; + case ST1E:ofname = s1fname; break; + case STE: ofname = sfname; break; + } + + /* Open output file. If line-format output was selected, write column + headings only if the file must be created from scratch. */ + if (strcmp(ofname, "-")) { + if ((ofile = fopen(ofname, "r")) == NULL) { + if ((ofile = fopen(ofname, "w")) == NULL) { + (void)fprintf(stderr, "%s: can't create %s\n", + pname, ofname); + exit(3); + } + if (lflag) { + switch (type) { + case AFE: + (void)fprintf(ofile, "(AF detection)\n"); + break; + case VFE: + (void)fprintf(ofile, "(VF detection)\n"); + break; + case ST0E: + (void)fprintf(ofile,"(Ischemic ST detection, signal 0)\n"); + break; + case ST1E: + (void)fprintf(ofile,"(Ischemic ST detection, signal 1)\n"); + break; + case STE: + (void)fprintf(ofile, + "(Ischemic ST detection, both signals)\n"); + break; + } + (void)fprintf(ofile, "Record TPs FN TPp FP"); + (void)fprintf(ofile, + " ESe E+P DSe D+P Ref duration Test duration \n"); + } + } + else { + (void)fclose(ofile); + if ((ofile = fopen(ofname, "a")) == NULL) { + (void)fprintf(stderr, "%s: can't modify %s\n", + pname, ofname); + exit(3); + } + } + } + else ofile = stdout; + + if (lflag) + (void)fprintf(ofile, "%6s %4ld %4ld %4ld %4ld ", + record, STP, FN, PTP, FP); + else { + switch (type) { + case AFE: + (void)fprintf(ofile, + "AF episode-by-episode comparison results for record %s\n", + record); + break; + case VFE: + (void)fprintf(ofile, + "VF episode-by-episode comparison results for record %s\n", + record); + break; + case ST0E: + (void)fprintf(ofile, + "ST episode-by-episode comparison results for record %s, signal 0\n", + record); + break; + case ST1E: + (void)fprintf(ofile, + "ST episode-by-episode comparison results for record %s, signal 1\n", + record); + break; + case STE: + (void)fprintf(ofile, + "ST episode-by-episode comparison results for record %s, both signals\n", + record); + break; + default: + break; + } + (void)fprintf(ofile, "Reference annotator: %s\n", an[0].name); + (void)fprintf(ofile, " Test annotator: %s\n\n", an[1].name); + } + pstat(" Episode sensitivity", STP, STP + FN); + pstat(" Episode positive predictivity", PTP, PTP + FP); + tstat(" Duration sensitivity", total_overlap, ref_duration); + tstat("Duration positive predictivity", total_overlap, test_duration); + if (!lflag) + (void)fprintf(ofile, "Duration of reference episodes:"); + (void)fprintf(ofile, " %s", mstimstr(ref_duration)); + if (!lflag) + (void)fprintf(ofile, "\n Duration of test episodes:"); + else + (void)fprintf(ofile, " "); + (void)fprintf(ofile, " %s\n", mstimstr(test_duration)); + + if (ofile != stdout) + (void)fclose(ofile); +} + +void init(argc, argv) +int argc; +char *argv[]; +{ + int i; + char *prog_name(); + void help(); + + pname = prog_name(argv[0]); + for (i = 1; i < argc; i++) { + if (*argv[i] == '-') switch (*(argv[i]+1)) { + case 'a': /* annotator names follow */ + if (++i >= argc-1) { + (void)fprintf(stderr, + "%s: reference and test annotator names must follow -a\n", + pname); + exit(1); + } + an[0].name = argv[i]; + an[1].name = argv[++i]; + break; + case 'A': /* perform AF comparison */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: output file name must follow -A\n", + pname); + exit(1); + } + afname = argv[i]; + aflag = 1; + break; + case 'f': /* start time follows */ + if (++i >= argc) { + (void)fprintf(stderr,"%s: start time must follow -f\n", pname); + exit(1); + } + start_time = i; /* save arg index, convert to samples later, + when record has been opened and sampling + frequency is known */ + break; + case 'h': /* print usage summary */ + help(); + exit(1); + break; + case 'i': /* minimum episode length follows */ + if (++i >= argc) { + (void)fprintf(stderr, + "%s: minimum episode length must follow -i\n", pname); + exit(1); + } + min_length = i; + break; + case 'l': /* line-format output */ + case 'L': /* treat -L and -l the same way, for + consistency with `bxb' and `rxr' usage */ + lflag = 1; + break; + case 'r': /* record name follows */ + if (++i >= argc) { + (void)fprintf(stderr, + "%s: record name must follow -r\n", pname); + exit(1); + } + record = argv[i]; + break; + case 'S': /* perform ST comparison */ + if (++i >= argc-1) { + (void)fprintf(stderr, + "%s: two output file names must follow %s\n", + pname, argv[i-1]); + exit(1); + } + switch (argv[i-1][2]) { + case '0': + s0fname = argv[i++]; + sd0fname = argv[i]; + s0flag = 1; + break; + case '1': + s1fname = argv[i++]; + sd1fname = argv[i]; + s1flag = 1; + break; + case '\0': + sfname = argv[i++]; + sdfname = argv[i]; + sflag = 1; + break; + default: + (void)fprintf(stderr, + "%s: unrecognized option %s\n", pname, argv[i-1]); + exit(1); + } + break; + case 't': /* end time follows */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: end time must follow -t\n", pname); + exit(1); + } + end_time = i; + break; + case 'V': /* perform VF comparison */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: output file name must follow -V\n", + pname); + exit(1); + } + vfname = argv[i]; + 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 || !an[0].name) { + help(); + exit(1); + } + + if (start_time != 0L || end_time != 0L || min_length != 0) + (void)fprintf(stderr,"%s: (warning) nonstandard comparison selected\n", + pname); + + if (sampfreq(record) <= 0) { + (void)fprintf(stderr, + "%s: (warning) %g Hz sampling frequency assumed\n", + pname, WFDB_DEFFREQ); + (void)setsampfreq(WFDB_DEFFREQ); + } + + /* Set the minimum episode length and the times of the start and end of + the test period. */ + if (min_length) + min_length = strtim(argv[min_length]); + if (start_time) { + start_time = strtim(argv[(int)start_time]); + if (start_time < (WFDB_Time)0) start_time = -start_time; + } + else + start_time = strtim("5:0"); /* 5 minutes */ + if (end_time) { + end_time = strtim(argv[(int)end_time]); + if (end_time < (WFDB_Time)0) end_time = -end_time; + } + else if ((end_time = strtim("e")) == 0L) + end_time = -1L; /* record length unavailable -- go to end of + reference annotation file */ + if (end_time > 0L && end_time < start_time) { + (void)fprintf(stderr, "%s: improper interval specified\n", pname); + exit(1); + } + an[0].stat = an[1].stat = WFDB_READ; + + /* Open annotation files. */ + if (annopen(record, an, 2) < 0) exit(2); +} + +static char *help_strings[] = { + "usage: %s -r RECORD -a REF TEST [OPTIONS ...]\n", + "where RECORD is the record name; REF is reference annotator name; TEST is", + "the test annotator name; and OPTIONS may include any of:", + " -A FILE append AF reports to FILE", + " -f TIME begin comparison at specified TIME (default: 5 minutes", + " after beginning of record)", + " -h print this usage summary", + " -i TIME ignore episodes shorter than TIME (default: 0 seconds)", + " -l write reports in line format (default: matrix format)", + " -L same as -l", + " -S FILE FILE2 append ST reports for both signals to FILE, and ST", + " measurements to FILE2", + " -S0 FILE FILE2 append ST reports for signal 0 to FILE, and ST measurements", + " to FILE2", + " -S1 FILE FILE2 append ST reports for signal 1 to FILE, and ST measurements", + " to FILE2", + " -t TIME stop comparison at specified TIME (default: end of record", + " if defined, end of reference annotation file otherwise;", + " if TIME is 0, the comparison ends when the end of either", + " annotation file is reached)", + " -V FILE append VF reports to FILE", +NULL +}; + +void help() +{ + int i; + + (void)fprintf(stderr, help_strings[0], pname); + for (i = 1; help_strings[i] != NULL; i++) + (void)fprintf(stderr, "%s\n", help_strings[i]); +} + +char *prog_name(s) +char *s; +{ + char *p = s + strlen(s); + +#ifdef MSDOS + while (p >= s && *p != '\\' && *p != ':') { + if (*p == '.') + *p = '\0'; /* strip off extension */ + if ('A' <= *p && *p <= 'Z') + *p += 'a' - 'A'; /* convert to lower case */ + p--; + } +#else + while (p >= s && *p != '/') + p--; +#endif + return (p+1); +} diff -Naur wfdb-10.2.9/app/fir.c wfdb-10.3.0/app/fir.c --- wfdb-10.2.9/app/fir.c Mon May 20 17:57:17 2002 +++ wfdb-10.3.0/app/fir.c Thu Nov 14 17:17:46 2002 @@ -1,5 +1,5 @@ /* file: fir.c G. Moody 5 January 1987 - Last revised: 20 May 2002 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- fir: General-purpose FIR filter for database records @@ -27,15 +27,6 @@ #include #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(), *calloc(), *realloc(); -#endif - #include char *pname; /* name by which this program was invoked */ diff -Naur wfdb-10.2.9/app/ihr.c wfdb-10.3.0/app/ihr.c --- wfdb-10.2.9/app/ihr.c Mon May 20 17:58:39 2002 +++ wfdb-10.3.0/app/ihr.c Sun Nov 17 15:17:14 2002 @@ -1,5 +1,5 @@ /* file ihr.c G. Moody 12 November 1992 - Last revised: 20 May 2002 + Last revised: 17 November 2002 ------------------------------------------------------------------------------- ihr: Generate instantaneous heart rate data from annotation file @@ -242,8 +242,8 @@ " * Elapsed time (in seconds) from the beginning of the record to the", " beginning of the interval (may be modified by -v or -V options below)", " * Instantaneous heart rate (in beats per minute)", - " * Interval type (1 if the interval was bounded by normal beats, otherwise - 0 (this column does not appear in the output if the -x option is used)", + " * Interval type (1 if the interval was bounded by normal beats, otherwise", + " 0 (this column does not appear in the output if the -x option is used)", "Use one of the following options to modify the format of the first column:", " -v print times of beginnings of intervals as sample numbers", " -vh same as -v, but print times in hours", diff -Naur wfdb-10.2.9/app/mfilt.c wfdb-10.3.0/app/mfilt.c --- wfdb-10.2.9/app/mfilt.c Tue Oct 9 12:44:02 2001 +++ wfdb-10.3.0/app/mfilt.c Thu Nov 14 17:18:42 2002 @@ -1,9 +1,9 @@ -/* file: mfilt.c G. Moody 27 June 1993 - Last revised: 9 October 2001 +/* file: mfilt.c G. Moody 27 June 1993 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- mfilt: General-purpose median filter for database records -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,14 +26,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(), *calloc(), *realloc(); -#endif #include char *pname; /* name by which this program was invoked */ diff -Naur wfdb-10.2.9/app/mxm.c wfdb-10.3.0/app/mxm.c --- wfdb-10.2.9/app/mxm.c Mon May 20 18:00:44 2002 +++ wfdb-10.3.0/app/mxm.c Thu Nov 14 17:19:21 2002 @@ -1,5 +1,5 @@ /* file: mxm.c G. Moody 20 March 1992 - Last revised: 20 May 2002 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- mxm: ANSI/AAMI-standard measurement-by-measurement annotation file comparator @@ -42,18 +42,6 @@ #include #include /* for declaration of sqrt() */ -#ifndef BSD -#include -#else -#include -#endif -#ifndef __STDC__ -extern double atof(); -extern void exit(); -#else -#include -#endif - #include #include diff -Naur wfdb-10.2.9/app/nst.c wfdb-10.3.0/app/nst.c --- wfdb-10.2.9/app/nst.c Mon Dec 17 21:50:37 2001 +++ wfdb-10.3.0/app/nst.c Thu Nov 14 17:25:20 2002 @@ -1,9 +1,9 @@ /* file: nst.c G. Moody 8 December 1983 - Last revised: 17 December 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- nst: Noise stress test -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -27,31 +27,12 @@ #include #include /* declarations of pow(), sqrt() */ -#ifndef BSD -#include -#else -#include -#endif +#include +#include + #ifdef NOMKSTEMP #define mkstemp mktemp #endif -#ifdef __STDC__ -# include -# if _MSC_VER >= 700 -# define mkstemp _mktemp -# define unlink _unlink -# endif -#else -extern double atof(); -extern void exit(); -# ifdef NOMALLOC_H -extern char *calloc(), *malloc(), *realloc(); -# else -# include -# endif -#endif -#include -#include /* Define the WFDB path component separator (OS-dependent). */ #ifdef MSDOS /* for MS-DOS, OS/2, etc. */ @@ -163,7 +144,7 @@ the protocol file it generates). */ wfdbp = getwfdb(); if (*wfdbp != PSEP && - !(*wfdbp = '.' && ((*wfdbp+1) == PSEP || *(wfdbp+1) == ' '))) { + !(*wfdbp == '.' && ((*wfdbp+1) == PSEP || *(wfdbp+1) == ' '))) { char *nwfdbp; if ((nwfdbp = (char *)malloc(strlen(wfdbp+2))) == NULL) { diff -Naur wfdb-10.2.9/app/pschart.c wfdb-10.3.0/app/pschart.c --- wfdb-10.2.9/app/pschart.c Mon Dec 17 21:50:53 2001 +++ wfdb-10.3.0/app/pschart.c Thu Nov 14 17:29:07 2002 @@ -1,9 +1,9 @@ /* file: pschart.c G. Moody 15 March 1988 - Last revised: 17 December 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- pschart: Produce annotated `chart recordings' on a PostScript device -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -24,7 +24,7 @@ _______________________________________________________________________________ Note: This program necessarily deals with several different coordinate -systems, principally the natural DB coordinates (time in sample intervals +systems, principally the natural WFDB coordinates (time in sample intervals or seconds, amplitude in adus or millivolts), the printer coordinates (pixels), and the page coordinates (mostly metric, with occasional English dimensions and printer's points added for entertainment). If you change @@ -38,26 +38,7 @@ #include #include -#ifdef __STDC__ -# include -#else -extern double atof(); -extern void exit(); -typedef long time_t; -# ifndef NOMALLOC_H -# include -# else -extern char *calloc(), *malloc(), *realloc(); -# endif -#endif -#ifndef BSD -#include -#else -#include -#define strchr index -#endif #include - #include #include diff -Naur wfdb-10.2.9/app/psfd.c wfdb-10.3.0/app/psfd.c --- wfdb-10.2.9/app/psfd.c Mon Dec 17 21:51:11 2001 +++ wfdb-10.3.0/app/psfd.c Fri Nov 22 12:39:11 2002 @@ -1,9 +1,9 @@ /* file: psfd.c G. Moody 9 August 1988 - Last revised: 17 December 2001 + Last revised: 21 November 2002 ------------------------------------------------------------------------------- psfd: Produces annotated full-disclosure ECG plots on a PostScript device -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -24,7 +24,7 @@ _______________________________________________________________________________ Note: This program necessarily deals with several different coordinate -systems, principally the natural DB coordinates (time in sample intervals +systems, principally the natural WFDB coordinates (time in sample intervals or seconds, amplitude in adus or millivolts), the printer coordinates (pixels), and the page coordinates (mostly metric, with occasional English dimensions and printer's points added for entertainment). If you change @@ -45,26 +45,7 @@ #include #include -#ifdef __STDC__ -# include -#else -extern double atof(); -extern void exit(); -typedef long time_t; -# ifndef NOMALLOC_H -# include -# else -extern char *calloc(), *malloc(), *realloc(); -# endif -#endif -#ifndef BSD -#include -#else -#include -#define strchr index -#endif #include - #include #include @@ -654,8 +635,9 @@ } } +static double __mt; /* temporary variable for adu macro */ +#define adu(A) ((__mt=(A)*dpadu), (int)(__mt>=0 ? __mt+0.5 : __mt-0.5)) #define si(A) ((int)((A)*dpsi)) /* convert sample intervals to pixels */ -#define adu(A) ((int)((A)*dpadu)) /* convert adus to pixels */ #define pt(A) ((int)((A)*dppt)) /* convert PostScript points to pixels */ double dpadu; /* pixels per adu. This quantity must be recalculated for each diff -Naur wfdb-10.2.9/app/rdsamp.c wfdb-10.3.0/app/rdsamp.c --- wfdb-10.2.9/app/rdsamp.c Fri Oct 5 00:44:12 2001 +++ wfdb-10.3.0/app/rdsamp.c Thu Nov 14 19:23:14 2002 @@ -1,9 +1,9 @@ -/* file: rdsamp.c G. Moody 23 June 1983 - Last revised: 5 October 2001 +/* file: rdsamp.c G. Moody 23 June 1983 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- rdsamp: Print an arbitrary number of samples from each signal -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,16 +26,6 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif #include /* Define the default WFDB path for CD-ROM versions of this program (the MS-DOS @@ -136,7 +126,7 @@ record = argv[i]; break; case 'p': /* output in physical units specified */ - pflag = 1; + ++pflag; break; case 's': /* signal list follows */ isiglist = i+1; /* index of first argument containing a signal # */ @@ -245,14 +235,14 @@ l = strlen(p); if (l > 7) p += l - 7; /* Print the last 7 characters of each signal description. */ - (void)printf("\t%s", p); + (void)printf("\t%s%s", pflag > 1 ? " " : "", p); } (void)printf("\n"); } /* Print data in physical units if '-p' option selected. */ if (pflag) { - char *p; + char *p, *fmt = pflag > 1 ? "\t%15.8lf" : "\t%7.3f"; double freq = sampfreq(NULL); /* Print units as a second line of column headers if '-v' selected. */ @@ -263,7 +253,7 @@ if (p == NULL) p = "mV"; if ((int)strlen(p) > 5) p[5] = '\0'; /* Print the first 5 characters of each signal units string. */ - (void)printf("\t(%s)", p); + (void)printf("\t%s(%s)", pflag > 1 ? " " : "", p); } (void)printf("\n"); } @@ -271,7 +261,7 @@ while ((to == 0L || from < to) && getvec(v) >= 0) { (void)printf("%7.3lf", (double)(from++)/freq); for (i = 0; i < nsig; i++) - (void)printf("\t%7.3lf", + (void)printf(fmt, (double)(v[sig[i]] - si[sig[i]].baseline)/si[sig[i]].gain); (void)printf("\n"); } @@ -317,6 +307,7 @@ " -H read multifrequency signals in high resolution mode", " -l INTERVAL truncate output after the specified time interval (hh:mm:ss)", " -p print times and samples in physical units (default: raw units)", + " (use -p -p for greater precision)", " -s SIGNAL [SIGNAL ...] print only the specified signal(s)", " -t TIME stop at specified time", " -v print column headings", diff -Naur wfdb-10.2.9/app/rr2ann.c wfdb-10.3.0/app/rr2ann.c --- wfdb-10.2.9/app/rr2ann.c Wed Dec 6 16:29:42 2000 +++ wfdb-10.3.0/app/rr2ann.c Fri Nov 1 07:23:22 2002 @@ -59,7 +59,7 @@ double rr, t = 0.0, xfactor = 1.0; static char line[MAXLINELEN]; char annstr[10], *p, *record = NULL, *prog_name(); - int i, Tflag = 0; + int i, Tflag = 0, wflag = 0; void help(); extern double atof(); @@ -108,6 +108,9 @@ exit(1); } break; + case 'w': /* copy annotation types from second column of input */ + wflag = 1; + break; default: (void)fprintf(stderr, "%s: unrecognized option %s\n", pname, argv[i]); @@ -150,7 +153,15 @@ /* Read input, write an annotation for each line beginning with a positive number. */ while (fgets(line, sizeof(line), stdin) != NULL) { - if (sscanf(line, "%lf", &rr) == 0) continue; + if (!wflag) { /* -w option not used, write all annotations as NORMAL */ + if (sscanf(line, "%lf", &rr) == 0) continue; + } + else { /* -w option used, copy annotation type from input */ + static char astring[MAXLINELEN]; + + if (sscanf(line, "%lf%s", &rr, astring) < 2) continue; + if ((annot.anntyp = strann(astring)) == NOTQRS) continue; + } if (rr <= 0.0) continue; else if (Tflag) t = rr * xfactor; else t += rr * xfactor; @@ -192,15 +203,17 @@ " -T TEXT-FILE contains times of occurrence, not RR intervals", " -x N multiply input by N to obtain RR in sample intervals", " (default: N = 1)", + " -w copy annotation types from second column of input", "TEXT-FILE should contain a column of RR intervals (or times of occurrence,", "if the -T option is specified), in units of sample intervals (unless the", - "-x option is used to specify a conversion factor). Only the first token on", - "each line is taken as an RR interval; anything else on the same line is", - "ignored, as are empty lines, spaces and tabs at the beginning of a line,", - "non-numeric tokens and anything following them on the same line, negative", - "intervals, and zero intervals. The output consists of a binary annotation", - "file (RECORD.ANNOTATOR), and (if it does not exist already) a text header", - "file (RECORD.hea).", + "-x option is used to specify a conversion factor). The first token on", + "each line is taken as an RR interval, and (if the -w option is specified)", + "the second token is taken as an annotation mnemonic (N, V, etc.); anything", + "else on the same line is ignored, as are empty lines, spaces and tabs at", + "the beginning of a line non-numeric tokens and anything following them on", + "the same line, negative intervals, and zero intervals. The output consists", + "of a binary annotation file (RECORD.ANNOTATOR), and (if it does not exist", + "already) a text header file (RECORD.hea).", NULL }; diff -Naur wfdb-10.2.9/app/sample.c wfdb-10.3.0/app/sample.c --- wfdb-10.2.9/app/sample.c Wed Jul 31 14:42:44 2002 +++ wfdb-10.3.0/app/sample.c Thu Nov 14 19:22:41 2002 @@ -1,5 +1,5 @@ /* file: sample.c G. Moody 10 January 1991 - Last revised: 30 April 1999 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sample: digitize or play back signals on a PC using a Microstar DAP board @@ -88,16 +88,6 @@ #define fileno(file) ((file)->fd) #endif #endif -#endif - -#ifdef __STDC__ -# include -#else -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif #endif #include diff -Naur wfdb-10.2.9/app/setwfdb wfdb-10.3.0/app/setwfdb --- wfdb-10.2.9/app/setwfdb Sat Mar 11 21:24:12 2000 +++ wfdb-10.3.0/app/setwfdb Fri Nov 22 21:58:19 2002 @@ -1,4 +1,5 @@ -WFDB=:${HOME}/database:${HOME}/database/%3r:/usr/local/database:/usr/local/database/%3r:/cdrom:/cdrom/mimicdb:/cdrom/mimicdb/%3r:/cdrom/mitdb:/cdrom/cudb:/cdrom/nstdb:/cdrom/stdb:/cdrom/vfdb:/cdrom/afdb:/cdrom/cdb:/cdrom/svdb:/cdrom/ltdb:/cdrom/odb:/cdrom/udb:/cdrom/edb:/cdrom/valedb:/cdrom/slpdb:/cdrom/mghdb:/cdrom/database:/cdrom/database/%3r:/usr/local/ahadb; export WFDB +WFDB=". ${HOME}/database /usr/local/database /cdrom http://www.physionet.org/physiobank/database"; export WFDB +: Change www.physionet.org above to your favorite mirror if you wish WFDBCAL=wfdbcal; export WFDBCAL : For compatibility with older applications only diff -Naur wfdb-10.2.9/app/setwfdb.bat wfdb-10.3.0/app/setwfdb.bat --- wfdb-10.2.9/app/setwfdb.bat Thu Jun 24 11:38:28 1999 +++ wfdb-10.3.0/app/setwfdb.bat Fri Nov 22 21:54:06 2002 @@ -1,14 +1,9 @@ @echo off : file: setwfdb.bat G. Moody 11 September 1989 -: Last revised: 30 April 1999 +: Last revised: 22 November 2002 : This script sets environment variables used by WFDB applications. -: Note: the MS-DOS/MS-Windows installation program, software\install.exe, -: creates a customized version of this batch file for your system. In most -: cases you should use the version created by install.exe rather than this -: one, which is included here for reference only. - : If you are already near the limit of your available environment space, you : may not be able to set these variables successfully. You may get an error : while executing this script, or you may find that environment variables @@ -19,10 +14,9 @@ : the environment in bytes. See your MS-DOS manual for further information. : If you use the WFDB Software Package regularly, you will find it easiest to -: invoke this batch file -- most likely the version of it created by install -- -: from your autoexec.bat, so that the WFDB environment is set automatically -: whenever you reboot your PC. In modern versions of MS-DOS, and under any -: version of MS-Windows, do this by adding +: invoke this batch file from your autoexec.bat, so that the WFDB environment +: is set automatically whenever you reboot your PC. In modern versions of +: MS-DOS, and under any version of MS-Windows, do this by adding : call c:\bin\setwfdb : to your autoexec.bat. Do not omit the _call_ from this command, or any : commands that follow setwfdb in your autoexec.bat will not be executed. @@ -32,7 +26,10 @@ : The WFDB path, by analogy to the MS-DOS PATH variable, is a list of : directories in which WFDB applications search for their input files. You may : define it directly, as the value of the WFDB environment variable, or -: indirectly, within a file named by the WFDB environment variable. +: indirectly, within a file named by the WFDB environment variable. If you +: do none of these, the WFDB path is given by the value of DEFWFDB, which is +: defined in wfdblib.h at the time the WFDB library is compiled. For most +: users, the default value may not need to be changed. : Here is a simple example of a direct definition of the WFDB path: :set WFDB=;c:\database diff -Naur wfdb-10.2.9/app/sigamp.c wfdb-10.3.0/app/sigamp.c --- wfdb-10.2.9/app/sigamp.c Tue Oct 9 10:20:14 2001 +++ wfdb-10.3.0/app/sigamp.c Thu Nov 14 17:30:48 2002 @@ -1,9 +1,9 @@ /* file: sigamp.c G. Moody 30 November 1991 - Last revised: 9 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sigamp: Measure signal amplitudes -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -25,18 +25,8 @@ */ - #include #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif - #include #define isqrs #define map2 diff -Naur wfdb-10.2.9/app/sigavg.c wfdb-10.3.0/app/sigavg.c --- wfdb-10.2.9/app/sigavg.c Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/app/sigavg.c Mon Nov 25 23:52:12 2002 @@ -0,0 +1,285 @@ +/* file: sigavg.c G. Moody 25 November 2002 + +------------------------------------------------------------------------------- +sigavg: Calculate averages of annotated waveforms +Copyright (C) 2002 George B. Moody + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (george@mit.edu) or postal mail +(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +_______________________________________________________________________________ + +This program is based on Example 9 in the WFDB Programmer's Guide. +*/ + +#include +#include +#include + +char *irec; /* input record name */ +char *pname; /* name by which this program was invoked */ +double sps; /* sampling frequency (Hz) */ +double **sum; +int dt1 = 0, dt2 = 0, flag[ACMAX+1], Hflag, nsig, vflag = 0, zflag = 0; +WFDB_Anninfo ai; +WFDB_Sample *v, *vb; +WFDB_Siginfo *s; +WFDB_Time from = 0L, to = 0L; + +char *prog_name(); +void help(), init(), memerr(); + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, j, nbeats = 0; + WFDB_Annotation annot; + + init(argc, argv); /* read and interpret command line */ + + while (getann(0, &annot) == 0 && annot.time < from) + ; + do { + if (flag[annot.anntyp] == 0) continue; + isigsettime(annot.time + dt1 - 1); + getvec(vb); + for (j = dt1; j <= dt2 && getvec(v) > 0; j++) { + if (zflag) + for (i = 0; i < nsig; i++) + sum[i][j-dt1] += v[i] - vb[i]; + else + for (i = 0; i < nsig; i++) + sum[i][j-dt1] += v[i]; + } + nbeats++; + } while (getann(0, &annot) == 0 && + (to == 0L || annot.time < to)); + if (nbeats < 1) { + fprintf(stderr, "%s: no beats found\n", pname); + exit(4); + } + if (vflag) { + printf("# Average of %d beats:\n", nbeats); + printf("# Time\t"); + for (i = 0; i < nsig; i++) + printf("%10s%c", s[i].desc, (i == nsig-1) ? '\n' : '\t'); + printf("# sec\t"); + for (i = 0; i < nsig; i++) { + if (s[i].units == NULL) s[i].units = "mV"; + printf("%10s%c", s[i].units, (i == nsig-1) ? '\n' : '\t'); + } + } + for (j = dt1; j < dt2; j++) { + printf("%10.5lf\t", (double)j/sps); + for (i = 0; i < nsig; i++) { + double m; + + m = sum[i][j-dt1]/nbeats; + if (!zflag) m -= s[i].baseline; + m /= s[i].gain; + printf("%10.5lf%c", m, (i == nsig-1) ? '\n' : '\t'); + } + } + exit(0); +} + +void init(int argc, char **argv) +{ + int i, j; + + pname = prog_name(argv[0]); + for (i = 1; i < ACMAX; i++) + flag[i] = isqrs(i); + for (i = 1; i < argc; i++) { + if (*argv[i] == '-') switch (*(argv[i]+1)) { + case 'a': /* annotator follows */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: annotator must follow -a\n", + pname); + exit(1); + } + ai.name = argv[i]; + ai.stat = WFDB_READ; + break; + case 'd': + if (++i >= argc-1) { + (void)fprintf(stderr, "%s: window offsets must follow -w\n", + pname); + exit(1); + } + /* save arg list indices, convert argument to samples later */ + dt1 = i; + dt2 = ++i; + 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': /* read multifrequency records in high resolution mode */ + Hflag = 1; + break; + case 'p': /* annotation mnemonic(s) follow */ + for (j = 1; j < ACMAX; j++) + flag[j] = 0; + if (++i >= argc || !isann(j = strann(argv[i]))) { + (void)fprintf(stderr, + "%s: annotation mnemonic(s) must follow -p\n", + pname); + exit(1); + } + flag[j] = 1; + /* The code above not only checks that there is a mnemonic where + there should be one, but also allows for the possibility that + there might be a (user-defined) mnemonic beginning with `-'. + The following lines pick up any other mnemonics, but assume + that arguments beginning with `-' are options, not mnemonics. */ + while (++i < argc && argv[i][0] != '-') + if (isann(j = strann(argv[i]))) flag[j] = 1; + if (i == argc || argv[i][0] == '-') i--; + flag[0] = 0; + break; + case 'r': /* record name */ + if (++i >= argc) { + (void)fprintf(stderr, "%s: record name must follow -r\n", + pname); + exit(1); + } + irec = argv[i]; + 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; + case 'z': /* set the baseline to zero */ + zflag = 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 (irec == NULL || ai.name == NULL) { + help(); + exit(1); + } + if (Hflag) + setgvmode(WFDB_HIGHRES); + if ((nsig = isigopen(irec, NULL, 0)) <= 0) + exit(2); + s = malloc((size_t)nsig * sizeof(WFDB_Siginfo)); + v = (WFDB_Sample *)malloc((size_t)nsig * sizeof(WFDB_Sample)); + vb = (WFDB_Sample *)malloc((size_t)nsig * sizeof(WFDB_Sample)); + sum = (double **)malloc(nsig * sizeof(double *)); + if (s == NULL || v == NULL || vb == NULL || sum == NULL) + memerr(); + if (wfdbinit(irec, &ai, 1, s, nsig) != nsig) + exit(2); + sps = sampfreq(NULL); + dt1 = strtim(dt1 ? argv[dt1] : "-.05"); + dt2 = strtim(dt2 ? argv[dt2] : ".05"); + if (dt1 > dt2) { + int tmp; + tmp = dt1; dt1 = dt2; dt2 = tmp; + } + else if (dt1 == dt2) + dt2 += strtim(".1"); + for (i = 0; i < nsig; i++) + if ((sum[i]=(double *)calloc(dt2-dt1+1,sizeof(double))) == NULL) { + wfdbquit(); + memerr(); + } + if (from > 0L) { + from = strtim(argv[from]); + if (from < (WFDB_Time)0) from = -from; + (void)isigsettime(from); + } + if (to > 0L) { + to = strtim(argv[to]); + if (to < (WFDB_Time)0) to = -to; + } +} + +void memerr() +{ + (void)fprintf(stderr, "%s: insufficient memory\n", pname); + exit(2); +} + +char *prog_name(s) +char *s; +{ + char *p = s + strlen(s); + +#ifdef MSDOS + while (p >= s && *p != '\\' && *p != ':') { + if (*p == '.') + *p = '\0'; /* strip off extension */ + if ('A' <= *p && *p <= 'Z') + *p += 'a' - 'A'; /* convert to lower case */ + p--; + } +#else + while (p >= s && *p != '/') + p--; +#endif + return (p+1); +} + +static char *help_strings[] = { + "usage: %s -r RECORD -a ANNOTATOR [OPTIONS ...]\n", + "where RECORD and ANNOTATOR specify the input, and OPTIONS may include:", + " -d DT1 DT2 calculate the average over a window defined by offsets", + " DT1 and DT2 from the input annotations (defaults:", + " DT1 = -0.05, DT2 = 0.05 (seconds from annotations)", + " -f TIME begin at specified time (default: beginning of RECORD)", + " -h print this usage summary", + " -H read multifrequency records in high resolution mode", + " -p TYPE [TYPE ...] include annotations of specified TYPEs only (default:", + " include all QRS annotations", + " -t TIME stop at specified time (default: end of RECORD)", + " -v verbose mode", + " -z set the baseline to zero before averaging", +NULL +}; + +void help() +{ + int i; + + (void)fprintf(stderr, help_strings[0], pname); + for (i = 1; help_strings[i] != NULL; i++) + (void)fprintf(stderr, "%s\n", help_strings[i]); +} diff -Naur wfdb-10.2.9/app/skewedit.c wfdb-10.3.0/app/skewedit.c --- wfdb-10.2.9/app/skewedit.c Mon Oct 8 22:24:54 2001 +++ wfdb-10.3.0/app/skewedit.c Thu Nov 14 17:31:39 2002 @@ -1,9 +1,9 @@ /* file: skewedit.c G. Moody 10 August 1994 - Last revised: 8 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- skewedit: Edit skew fields of header file(s) -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,14 +26,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif #include static int nskews, *skew; diff -Naur wfdb-10.2.9/app/snip.c wfdb-10.3.0/app/snip.c --- wfdb-10.2.9/app/snip.c Thu Oct 4 13:48:22 2001 +++ wfdb-10.3.0/app/snip.c Thu Nov 14 17:32:48 2002 @@ -1,8 +1,8 @@ /* file: snip.c G. Moody 30 July 1989 - Last revised: 4 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- snip: Copy an excerpt of a database record -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -25,14 +25,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif #include char *pname; diff -Naur wfdb-10.2.9/app/sqrs.c wfdb-10.3.0/app/sqrs.c --- wfdb-10.2.9/app/sqrs.c Tue May 28 11:22:10 2002 +++ wfdb-10.3.0/app/sqrs.c Thu Nov 14 18:57:50 2002 @@ -1,5 +1,5 @@ /* file: sqrs.c G. Moody 27 October 1990 - Last revised: 28 May 2002 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sqrs: Single-channel QRS detector @@ -70,14 +70,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif #include #include diff -Naur wfdb-10.2.9/app/sqrs125.c wfdb-10.3.0/app/sqrs125.c --- wfdb-10.2.9/app/sqrs125.c Tue May 28 11:59:42 2002 +++ wfdb-10.3.0/app/sqrs125.c Thu Nov 14 17:34:51 2002 @@ -1,5 +1,5 @@ /* file: sqrs125.c G. Moody 27 October 1990 - Last revised: 28 May 2002 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sqrs125: Single-channel QRS detector for data sampled at 100 - 150 Hz @@ -78,14 +78,6 @@ */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif #include #include diff -Naur wfdb-10.2.9/app/sumann.c wfdb-10.3.0/app/sumann.c --- wfdb-10.2.9/app/sumann.c Thu Oct 3 15:09:29 2002 +++ wfdb-10.3.0/app/sumann.c Thu Nov 14 19:21:01 2002 @@ -1,5 +1,5 @@ -/* file: sumann.c G. Moody 5 February 1982 - Last revised: 3 October 2002 +/* file: sumann.c G. Moody 5 February 1982 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sumann: Tabulates annotations @@ -26,22 +26,6 @@ */ #include -#ifndef BSD -# include -#else -# include -#endif -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif - #include #include #include diff -Naur wfdb-10.2.9/app/sumstats.c wfdb-10.3.0/app/sumstats.c --- wfdb-10.2.9/app/sumstats.c Wed Nov 7 10:59:34 2001 +++ wfdb-10.3.0/app/sumstats.c Thu Nov 14 18:59:02 2002 @@ -1,8 +1,8 @@ /* file: sumstats.c G. Moody 17 August 1989 - Last revised: 7 November 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- sumstats: Derive aggregate statistics from bxb, rxr, or epic line-format output -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -32,13 +32,6 @@ */ #include -#ifdef __STDC__ -#include -#else -extern double atof(); -extern void exit(); -#endif - #include static int nrec, NQS, NQP, NVS, NVP, NVF, NSVS, NSVP; diff -Naur wfdb-10.2.9/app/tach.c wfdb-10.3.0/app/tach.c --- wfdb-10.2.9/app/tach.c Sun Jan 30 04:13:17 2000 +++ wfdb-10.3.0/app/tach.c Thu Nov 14 19:00:00 2002 @@ -1,9 +1,9 @@ /* file: tach.c G. Moody 18 April 1985 - Last revised: 4 May 1999 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- tach: Generate heart rate vs. time signal with evenly spaced samples -Copyright (C) 1999 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -49,13 +49,6 @@ #include #include -#ifndef __STDC__ -extern double atof(); -extern void exit(); -#else -#include -#endif - #include #define map1 #define map2 diff -Naur wfdb-10.2.9/app/wfdbcollate.c wfdb-10.3.0/app/wfdbcollate.c --- wfdb-10.2.9/app/wfdbcollate.c Tue Oct 9 09:43:35 2001 +++ wfdb-10.3.0/app/wfdbcollate.c Thu Nov 14 19:02:58 2002 @@ -1,9 +1,9 @@ /* file: wfdbcollate.c G. Moody 28 April 1994 - Last revised: 9 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- wfdbcollate: Collate WFDB records into a multi-segment record -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -80,14 +80,6 @@ library. */ #include -#ifndef __STDC__ -extern void exit(); -#endif -#ifndef NOMALLOC_H -#include -#else -extern char *malloc(); -#endif #include #define DEFSEGLEN "10:0" /* segments are 10 minutes long by default */ diff -Naur wfdb-10.2.9/app/wfdbdesc.c wfdb-10.3.0/app/wfdbdesc.c --- wfdb-10.2.9/app/wfdbdesc.c Fri Oct 5 01:00:13 2001 +++ wfdb-10.3.0/app/wfdbdesc.c Thu Nov 14 19:15:56 2002 @@ -1,9 +1,9 @@ -/* file: wfdbdesc.c G. Moody June 1989 - Last revised: 5 October 2001 +/* file: wfdbdesc.c G. Moody June 1989 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- wfdbdesc: Describe signal specifications -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -29,16 +29,6 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif #include main(argc, argv) diff -Naur wfdb-10.2.9/app/wqrs.c wfdb-10.3.0/app/wqrs.c --- wfdb-10.2.9/app/wqrs.c Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/app/wqrs.c Tue Nov 26 13:45:25 2002 @@ -0,0 +1,476 @@ +/* file: wqrs.c Wei Zong 23 October 1998 + Last revised: 22 November 2002 (by W.Zong and G. Moody) +----------------------------------------------------------------------------- +wqrs: Single-lead QRS detector based on length transform +Copyright (C) 2002 Wei Zong + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (wzong@mit.edu) or postal mail +(MIT Room E25-505, Cambridge, MA 02139, USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +------------------------------------------------------------------------------ + +This program analyzes an ECG signal, detecting QRS onsets and J-points, using +a nonlinearly-scaled ECG curve length feature. This version has been optimized +for ECGs sampled at 125 Hz, but it can analyze ECGs sampled at any frequency +using on-the-fly resampling provided by the WFDB library. + +`wqrs' can process records containing any number of signals, but it uses only +one signal for QRS detection (signal 0 by default; this can be changed using +the `-s' option, see below). 'wqrs' has been optimized for adult human ECGs. +For other ECGs, it may be necessary to experiment with the input sampling +frequency and the time constants indicated below. + +To compile this program under GNU/Linux, MacOS/X, MS-Windows, or Unix, use gcc: + gcc -o wqrs wqrs.c -lwfdb -lm +You must have installed the WFDB library, available at + http://www.physionet.org/physiotools/wfdb.shtml +gcc is standard with GNU/Linux and is available for other platforms from: + http://www.gnu.org/ (sources and Unix binaries) + http://fink.sourceforge.net (Mac OS/X only) + http://www.cygwin.com/ (MS-Windows only) + +For a usage summary, see the help text at the end of this file. The input +record may be in any of the formats readable by the WFDB library, and it may +be anywhere in the WFDB path (in a local directory or on a remote web or ftp +server). The output of 'wqrs' is an annotation file named RECORD.wqrs (where +RECORD is replaced by the name of the input record). Within the output +annotation file, the time of each NORMAL annotation marks a QRS onset; if +the '-j' option is used, additional JPT annotations mark the J points (the +ends of the QRS complexes). During the learning period (the first LPERIOD +samples), LEARN annotations are used instead of NORMAL annotations, and there +are no JPT annotations. + +For example, to mark QRS complexes in record 100 beginning 5 minutes from the +start, ending 10 minutes and 35 seconds from the start, and using signal 1, use +the command: + wqrs -r 100 -f 5:0 -t 10:35 -s 1 +The output may be read using (for example): + rdann -a wqrs -r 100 +To evaluate the performance of this program, run it on the entire record, by: + wqrs -r 100 +and then compare its output with the reference annotations by: + bxb -r 100 -a atr wqrs +*/ + +#include +#include +#include +#include +#include + +#define BUFLN 4096 /* must be a power of 2, see ltsamp() */ +#define EYE_CLS 0.25 /* eye-closing period is set to 0.25 sec (250 ms) */ +#define LPERIOD 1000 /* learning period is the first LPERIOD samples */ +#define MaxQRSw 0.13 /* maximum QRS width (130ms) */ +#define NDP 2.5 /* adjust threshold if no QRS found in NDP seconds */ +#define PWFreqDEF 60 /* power line (mains) frequency, in Hz (default) */ +#define TmDEF 100 /* minimum threshold value (default) */ + +char *pname; /* the name by which this program was invoked */ +double lfsc; /* length function scale constant */ +int *ebuf; +int nsig; /* number of input signals */ +int LPn, LP2n; /* filter parameters (dependent on sampling rate) */ +int LTwindow; /* LT window size */ +int PWFreq = PWFreqDEF; /* power line (mains) frequency, in Hz */ +int signal = 0; /* signal number of signal to be analyzed */ +int Tm = TmDEF; /* minimum threshold value */ +WFDB_Sample *lbuf = NULL; + +/* ltsamp() returns a sample of the length transform of the input at time t. + Since this program analyzes only one signal, ltsamp() does not have an + input argument for specifying a signal number; rather, it always filters + and returns samples from the signal designated by the global variable + 'signal'. The caller must never "rewind" by more than BUFLN samples (the + length of ltsamp()'s buffers). */ + +WFDB_Sample ltsamp(WFDB_Time t) +{ + int dy; + static int Yn, Yn1, Yn2; + static WFDB_Time tt = (WFDB_Time)-1L; + + if (lbuf == NULL) { + lbuf = (WFDB_Sample *)malloc((unsigned)BUFLN*sizeof(WFDB_Sample)); + ebuf = (int *)malloc((unsigned)BUFLN * sizeof(int)); + if (lbuf && ebuf) { + for (ebuf[0] = sqrt(lfsc), tt = 1L; tt < BUFLN; tt++) + ebuf[tt] = ebuf[0]; + if (t > BUFLN) tt = (WFDB_Time)(t - BUFLN); + else tt = (WFDB_Time)-1L; + Yn = Yn1 = Yn2 = 0; + } + else { + (void)fprintf(stderr, "%s: insufficient memory\n", pname); + exit(2); + } + } + if (t < tt - BUFLN) { + fprintf(stderr, "%s: ltsamp buffer too short\n", pname); + exit(2); + } + while (t > tt) { + static int aet = 0, et; + + Yn2 = Yn1; + Yn1 = Yn; + Yn = 2*Yn1 - Yn2 + sample(signal, tt) - + 2*sample(signal, tt-LPn) + sample(signal, tt-LP2n); + dy = (Yn - Yn1) / LP2n; /* lowpass derivative of input */ + et = ebuf[(++tt)&(BUFLN-1)] = sqrt(lfsc +dy*dy); /* length transform */ + lbuf[(tt)&(BUFLN-1)] = aet += et - ebuf[(tt-LTwindow)&(BUFLN-1)]; + /* lbuf contains the average of the length-transformed samples over + the interval from tt-LTwindow+1 to tt */ + } + return (lbuf[t&(BUFLN-1)]); +} + +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 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 */ + int Ta, T0; /* high and low detection thresholds */ + WFDB_Anninfo a; + WFDB_Annotation annot; + WFDB_Sample *v; + WFDB_Siginfo *s; + WFDB_Time from = 0L, next_minute, now, spm, t, tj, tpq, to = 0L, tt, t1; + 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 '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 must follow -s\n", + pname); + exit(1); + } + signal = atoi(argv[i]); + 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 ((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 = "wqrs"; a.stat = WFDB_WRITE; + if ((nsig = wfdbinit(record, &a, 1, s, nsig)) < 1) exit(2); + if (signal < 0 || signal >= nsig) signal = 0; + sps = sampfreq((char *)NULL); + 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; + } + + annot.subtyp = annot.num = 0; + annot.chan = signal; + annot.aux = NULL; + Tm = muvadu((unsigned)signal, Tm); + samplingInterval = 1000.0/sps; + lfsc = 5.0e6/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(signal, 0L); + if (dflag) { + for (t = from; (to == 0L || t < to) && sample_valid(); t++) + printf("%6d\t%6d\n", sample(signal, 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", signal); + printf("Eye-closing period: %d samples (%.0f ms)\n", + EyeClosing, EyeClosing*samplingInterval); + printf("Minimum threshold: %d A/D units (%d microvolts)\n", + Tm, adumuv(signal, 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 */ + t1 = from + strtim("8"); + for (T0 = 0, t = from; t < t1 && sample_valid(); t++) + T0 += ltsamp(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; + } + + /* 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+1); /* account for phase shift */ + break; + } + } + + if (!learning) { + /* Check that we haven't reached the end of the record. */ + (void)sample(signal, 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 - (LPn + 1) + LPn; + break; + } + } + (void)sample(signal, 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; + T0 = 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--; + T0 = 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.wqrs\n\n\n", + record); + } + exit(0); +} + +char *prog_name(s) +char *s; +{ + char *p = s + strlen(s); + +#ifdef MSDOS + while (p >= s && *p != '\\' && *p != ':') { + if (*p == '.') + *p = '\0'; /* strip off extension */ + if ('A' <= *p && *p <= 'Z') + *p += 'a' - 'A'; /* convert to lower case */ + p--; + } +#else + while (p >= s && *p != '/') + p--; +#endif + return (p+1); +} + +static char *help_strings[] = { + "usage: %s -r RECORD [OPTIONS ...]\n", + "where RECORD is the name of the record to be analyzed, and OPTIONS may", + "include any of:", + " -d dump unfiltered and filtered samples on standard output;", + " do not annotate", + " -f TIME begin at specified time (default: beginning of the record)", + " -h print this usage summary", + " -j find and annotate J-points (QRS ends) as well as QRS onsets", + " -m THRESH set detector threshold to THRESH (default: 100)", /* TmDEF */ + " -p FREQ specify power line (mains) frequency (default: 60)", + /* PWFreqDEF */ + " -R resample input at 120 or 150 Hz, depending on power line", + " frequency (default: do not resample)", + " -s SIGNAL analyze specified signal (default: 0)", + " -t TIME stop at specified time (default: end of the record)", + " -v verbose mode", + "If too many beats are missed, decrease THRESH; if there are too many extra", + "detections, increase THRESH.", +NULL +}; + +void help() +{ + int i; + + (void)fprintf(stderr, help_strings[0], pname); + for (i = 1; help_strings[i] != NULL; i++) + (void)fprintf(stderr, "%s\n", help_strings[i]); +} diff -Naur wfdb-10.2.9/app/wrsamp.c wfdb-10.3.0/app/wrsamp.c --- wfdb-10.2.9/app/wrsamp.c Fri Oct 5 00:43:57 2001 +++ wfdb-10.3.0/app/wrsamp.c Fri Nov 22 12:14:55 2002 @@ -1,8 +1,8 @@ /* file: wrsamp.c G. Moody 10 August 1993 - Last revised: 5 October 2001 + Last revised: 21 November 2002 ------------------------------------------------------------------------------- wrsamp: Select fields or columns from a file and generate a WFDB record -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -27,17 +27,8 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *calloc(); -# endif -#endif #include + #define isfsep(c) ((fsep && ((c)==fsep)) || ((c)==' ' || (c)=='\t')) char *pname; @@ -263,8 +254,11 @@ pname, t, fv[i]); vout[i] = 0; } - else - vout[i] = (int)(scale * v); + else { + v *= scale; + if (v >= 0) vout[i] = (int)(v + 0.5); + else vout[i] = (int)(v - 0.5); + } } if (putvec(vout) < 0) break; for (i = 0; i <= nf; i++) diff -Naur wfdb-10.2.9/app/xform.c wfdb-10.3.0/app/xform.c --- wfdb-10.2.9/app/xform.c Fri Sep 13 10:21:48 2002 +++ wfdb-10.3.0/app/xform.c Thu Nov 14 19:17:33 2002 @@ -1,5 +1,5 @@ -/* file: xform.c G. Moody 8 December 1983 - Last revised: 13 September 2002 +/* file: xform.c G. Moody 8 December 1983 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- xform: Sampling frequency, amplitude, and format conversion for WFDB records @@ -26,22 +26,6 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif -#ifndef BSD -# include -#else -# include -#endif - #include char *pname, *prog_name(); diff -Naur wfdb-10.2.9/check-manifest wfdb-10.3.0/check-manifest --- wfdb-10.2.9/check-manifest Fri Dec 14 14:19:31 2001 +++ wfdb-10.3.0/check-manifest Fri Nov 1 06:54:38 2002 @@ -1,4 +1,7 @@ #!/bin/sh +# file: check-manifest G. Moody 14 December 2001 +# Last revised: 1 November 2002 +# Verify tarball contents PACKAGE=$1 sort <../${PACKAGE}-MANIFEST >../sort.$$ @@ -16,19 +19,17 @@ Oops! The MANIFEST does not match the contents of ${PACKAGE}! The 'diff' output above indicates which file(s) do not match. -There are five possible reasons for this problem: - 1. The package version given in the MANIFEST is out-of-date. If this is - the problem, update the package version in MANIFEST (in each line). - 2. A file belonging to the package is missing; find it! +There are four possible reasons for this problem: + 1. A file belonging to the package is missing; find it! Look in previous versions of the package for the missing file. - 3. A file that does not belong to the package is present within this + 2. A file that does not belong to the package is present within this directory or one of its subdirectories; remove it! - 4. A new file in the package is not mentioned in the MANIFEST; in this + 3. A new file in the package is not mentioned in the MANIFEST; in this case, replace MANIFEST with ../${PACKAGE}-MANIFEST. - 5. A file formerly belonging to the package has been removed; in this + 4. A file formerly belonging to the package has been removed; in this case, replace MANIFEST with ../${PACKAGE}-MANIFEST. Read the 'diff' output above to identify which reason(s) apply. Be careful -not to replace MANIFEST unless all errors related to reasons 1, 2, and 3 have +not to replace MANIFEST unless all errors related to reasons 1 and 2 have been corrected. In any case, rerun 'make tarballs' after correcting the problem(s). diff -Naur wfdb-10.2.9/checkpkg/Makefile wfdb-10.3.0/checkpkg/Makefile --- wfdb-10.2.9/checkpkg/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/checkpkg/Makefile Tue Nov 26 13:40:19 2002 @@ -31,12 +31,12 @@ # directory). To print a set of source listings, type `make listing'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -53,13 +53,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -169,6 +169,40 @@ # uncomment the next line. # STRIP = : +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... + # `make' (with no target specified) will be equivalent to `make all'. make-all: all @@ -182,10 +216,10 @@ all: @rm -f lcheck @make lcheck - @./libcheck + @./libcheck $(DBDIR) @../conf/prompt "Press to continue ... " @read a - @./appcheck + @./appcheck $(INCDIR) lcheck: lcheck.c @echo Compiling WFDB library test application ... diff -Naur wfdb-10.2.9/checkpkg/Makefile.tpl wfdb-10.3.0/checkpkg/Makefile.tpl --- wfdb-10.2.9/checkpkg/Makefile.tpl Tue Dec 11 12:55:26 2001 +++ wfdb-10.3.0/checkpkg/Makefile.tpl Tue Nov 26 10:12:47 2002 @@ -1,10 +1,10 @@ all: @rm -f lcheck @make lcheck - @./libcheck + @./libcheck $(DBDIR) @../conf/prompt "Press to continue ... " @read a - @./appcheck + @./appcheck $(INCDIR) lcheck: lcheck.c @echo Compiling WFDB library test application ... diff -Naur wfdb-10.2.9/checkpkg/appcheck wfdb-10.3.0/checkpkg/appcheck --- wfdb-10.2.9/checkpkg/appcheck Thu May 23 20:22:15 2002 +++ wfdb-10.3.0/checkpkg/appcheck Tue Nov 26 10:12:43 2002 @@ -1,6 +1,6 @@ #!/bin/sh -# file: appcheck G. Moody 7 September 2001 -# Last revised: 23 May 2002 +# file: appcheck G. Moody 7 September 2001 +# Last revised: 26 November 2002 # # This script checks the functionality of the WFDB applications in the 'app' # directory. @@ -11,6 +11,8 @@ WFDB=". ../data http://www.physionet.org/physiobank/database" export WFDB +INCDIR=$1 + PASS=0 FAIL=0 TESTS=0 @@ -131,12 +133,12 @@ echo Testing sqrs ... F=100s.qrs -sqrs -r 100s 2>/dev/null +sqrs -r 100s 2>sqrs.log if ( ./checkfile $F ) then PASS=`expr $PASS + 1` cp $F 100s.ann - rm -f $F + rm -f $F sqrs.log else FAIL=`expr $FAIL + 1` cp expected/$F 100s.ann @@ -210,13 +212,13 @@ TESTS=`expr $TESTS + 1` echo Testing mfilt ... -mfilt -l 5 -i 100s -n mfilt -f 10 -t 15 2>/dev/null +mfilt -l 5 -i 100s -n mfilt -f 10 -t 15 2>mfilt.log for F in mfilt.dat mfilt.hea do if ( ./checkfile $F ) then PASS=`expr $PASS + 1` - rm -f $F + rm -f $F mfilt.log else FAIL=`expr $FAIL + 1` fi @@ -292,14 +294,14 @@ echo Testing sortann ... rdann -r 100s -a atr -f 30 >foo rdann -r 100s -a atr -t 30 >>foo -( WFDBANNSORT=0; export WFDBANNSORT; wrann -r 100s -a mix /dev/null ) +( WFDBANNSORT=0; export WFDBANNSORT; wrann -r 100s -a mix wrann.log ) rm -f foo sortann -r 100s -a mix F=100s.mix if ( ./checkfile $F ) then PASS=`expr $PASS + 1` - rm -f $F + rm -f $F wrann.log else FAIL=`expr $FAIL + 1` fi @@ -342,13 +344,13 @@ TESTS=`expr $TESTS + 1` echo Testing wfdbcollate ... -wfdbcollate -s 100s -o wfd -l 30 2>/dev/null +wfdbcollate -s 100s -o wfd -l 30 2>wfdbcollate.log for F in wfd*hea wfd*dat do if ( ./checkfile $F ) then PASS=`expr $PASS + 1` - rm -f $F + rm -f $F wfdbcollate.log else FAIL=`expr $FAIL + 1` fi @@ -367,6 +369,18 @@ fi TESTS=`expr $TESTS + 1` +echo Testing wqrs ... +F=100s.wqrs +wqrs -r 100s -j 2>wqrs.log +if ( ./checkfile $F ) +then + PASS=`expr $PASS + 1` + rm -f $F wqrs.log +else + FAIL=`expr $FAIL + 1` +fi +TESTS=`expr $TESTS + 1` + echo Testing xform ... xform -i 100s -a atr -n 100x -o input/100x >xform-1.out 2>&1 for F in xform-1.out 100x.atr 100x.dat 100x.hea @@ -381,7 +395,7 @@ TESTS=`expr $TESTS + 1` done -if ( grep "WFDB_NETFILES 1" /usr/include/wfdb/wfdb.h >/dev/null 2>&1 ) +if ( grep "WFDB_NETFILES 1" $INCDIR/wfdb/wfdb.h >grep.out 2>&1 ) then echo "Testing xform (with NETFILES) ..." xform -i mimicdb/237/237 -s 1 2 0 3 -f 9:19:45 -t "[22:01:23 20/07/1995]" \ @@ -398,13 +412,14 @@ TESTS=`expr $TESTS + 1` done fi +rm -f grep.out cat <>qrs-mit-evaluation diff -Naur wfdb-10.2.9/checkpkg/expected/psfd.ps wfdb-10.3.0/checkpkg/expected/psfd.ps --- wfdb-10.2.9/checkpkg/expected/psfd.ps Wed Sep 12 14:33:45 2001 +++ wfdb-10.3.0/checkpkg/expected/psfd.ps Fri Nov 22 14:23:32 2002 @@ -80,28 +80,28 @@ (MLII)b 2135 2915 m (MLII)t -346 2929 m -(OONPPL`BPPPPPPPPRPPPNPPPPRPNPN^HJPPPPPPPRPPPPPPPPPRPNNP^BPPPPPPPQPPPPPPPPRPNNN\\JLPPPPPPRRNPPPPPPRPPNPN^BPPPPPPPPRPPPPPPPRPPNPN^BOPPPPPPRPRNPPPPPRPPNPN^FLPPPPPPPRRPPPPNPPN`@PPPPPPPPRPPPPPPPPPPOPPRPNNPR^@PPPPPPNPRRPPPPPPPPRPNNNb@PPPPPPPPRRNPPPPPPRPNPN) z -(^FLPPPQNPRRPPPNPPPRRNNPN`@RPPPPPPPRPPNPPPRPPNPN`@PPPPPPPPRRNPPPPPPRPPMPPZJLPPPPPPPRPPPPNPPPRPPPNPLd>RPPPPPNRRPPNPPPPPRPPNPPZDPPPPPPPPQPPPPPPPPRPNPNVTFPPPPPPNRRPPPPPPPPRPNPN`BNPPPPPPRRPPNPPPPRPPNPN_@RNRPPPPPRPNPPPPPRPPNPNf:PPPPPPPPRPPPPPPPRPPNPP\\BPPP) z -(PPPPRPRNPPPOPRPPNPN\\JLNRNPRNPRRPPNPPPPPRPPNPNZLLNPPPRNPRRNPPPPPPRPPNPLb@PPOPPPNRRPPPPPPPRPNPNR\\BPPPPPPPRRPPNPPPRPPNPN^NFNRNRPNRRPPNPPPPRPPMPPZDPPPPPPPRPPPPPPPRPPNPN^DNPPPPPNRRPPPPNRPPRPNNPR\\BPPPPPPPPRPOPNPPPRPPNPN`@PPPPPPPPRPPPPPPPPRPPNNNb@PPPPPPP) z -(PRPPPPPPPPRPPNNP^DMPPPPPPPRPPPPPPPRPPPNPZPDPRPPPNRRPPPNRNRPRNPNP\\DPPPPPPPRPPPPNPPQPRNNPPZFPNRPPNPRRPPNPPPRPPNPN\\JLNPPRPNPRRPPPNRPNRRPNNPLf>PPPPPPOPRPPPPNPPPRRNPNN\\JLPPPPPPPPRPPNPPPPRPPNPN`@PRNRPNPRRPPPNPPPRRPKPNb@PPPPPPNRRPPPPPPPPPRPNPNb@NPPPPPPRP) z -(PPPPPPPRPPNNN`BPPPPPPPRPPONPPPRPPNPNTZBPPPPPPPRPPPPPPPPRPPNPN`BNPPPPPPPRRNPPPPPPRPPPNPRZCNPPRNPPRRPPPPNPPPRPRNNPLd>RPPPPPPPPRPPNPPPPRPPNPP\\DPPPPPNPRRPPPOPPPRPNPLb>RPPPPPPRPPPPPPPPRPPNPLb@PPPPPPPPRPPPPPPPPRPPNNXLLPPPOPPPPRNPPPPPPRPNPNZJLPPPPPPPRRPNPP) z -(PPPRPPNPPXNJPPPPPPPRPPPPPPPPRPONPN\\HLPPPPPPPRPPPPPPPPRPPNPLb@PPPPPPPPRPPPPPPPPRPNNPXNJPPPPPNRQPPPPPPPPRPNPLfPPPRPPPPRPPNPOPPPRRNNPPf8RPPPPPNRPPPPPPPPR) z -(PPLPN`BPPPPPNPRRPPNPPPRPPPNN\\LJPPPPONRRPPPPPPPPRPLPN^FNPPPPPPPRPPNPPPRPPPNPP^BPPPPPNPRRPPNPPPPRPNPOTTFRPPPPNPRRPPPPPPPPRPPNPNb@NPRPPPPPPRPPPPNRPPRPNNPVVDPPPPPPPRPOPPPPPPPRPNNP\\DPPPPPPNRRPPPNPPPRRNNPP^BPPPPPNRRPPPPPPPPRPNPN\\HLOPPPPPRRPNPPPPPRPPNPN`) z -(BPPPPPPNRRPPNPPPPRPPNPNXNJPPPPPPPRPPPPPPPPQPPNPN`@PPPPPPPPRRPN) z +346 2930 m +(OMPNPN`@PRPNPPPPRRNPPPPPPRPNNP^HJPPPPPNPRRPPPNPPPRRNNPP^BPPPPPPPQPPNPPPPRPPNPNZLLPPPPPPPRPPPPNPPRRNNPN`@RPPPPNPRRPPPPPPPRPNNPP\\DOPPPPPNRRPPPPPPPPRPNNP^DNPPPPPPPRPPPPRNNPN`BPPPPPPPPRPPNPPPPPPPOPPRPPNPP^@PPPPRNPPRRPPNPPPPRPPNPNb>RPPPPPPPRPPPPNPRPRPNNP) z +(\\FNPPPOPPPRPPPPPPPPRPNPN^BPPPPPPPRPPPPPPPPRPNNP^BPPPPPPNRRPPPPPPPPPRPMPNZLJPPPPPPPRRNPPPPPPPRPNPNNb@PPPPPPPPRPPPPPPPPRPNNPRXFPPPPPPNRQPPPNPPPRPPNPPTVFPNRNRNPRRPPNPPPPRRNNPN`BPPPPPPPPRPPPPPPPRPPNNN_BPPPPPPPPRPPPPPPPPRNNPPdRPOPPNPRRPPPNPPRPPPNPRZDPPPPPPPRPPPPPPPPRPNNP\\PDPPPPPPPRPPPPPPPRPPMNRZDPPPPPPPPRPPPNPPRRNNPP^BPNPPPPPPRRPNPPPPPRPNPNTZBPPPPPPPRPPOPPPPPPRPNNNb@PPPPPPPPRPPPPNPPPRPPNPN`@PPPPPRN) z +(PRRPPNPPPPRRNNPN^FMPPPPNPRRPPPPNRPPRPNPN\\NFPPPPPPPRRNPPPPPRPPNPP\\DPNRPPNRPRPNPPPPORPNPNRZDPPPPPPPRPPPPPPPPRPNNP\\HLPPPPPPPRRNPPPPPPPRPPNPLd>PPPPPPOPRPRNPPPPPPRPNPN\\JJPPPPPPPRPPPPPPPPPRPNNN`BPPPPPPPPRPPPPPPPPRPMPN`@PPPPPPPPRRPPPNPPPRPPNPNb@NPPPPPPR) z +(RPNPPPPPRPPNPN^BRPPPPPPPRNOPPPPPRPNNPR\\BPPPPPNPRRPPPNPPPRRNNPN`BPPPPPPNRRPPPPPPPPPRPNPNTZAPPPPPPPPRPPPPPPPPPRPNPNNb@PPPPPPPPRPPPPPPPPRPNPPPZDPPPPPPPRPPPPOPPRPRLPNb>RPPPPPNRRPPPNRNRPRPNNNb>RPPPPPPPRPPPPNPPRRNPNPXLJPPPOPPPRPPPPPPPPRPNNPZJLPPPPPNRRPPPP) z +(PPPPRPPNPNXPHPPPPPPPRRPPPNPPPRROLPN\\HNPPPPPPPRPPPPNPPRPRPLPN`@RPPNRPNPRRPNPPPPPRPNPPVPJNPPPPPPQRPNPPPPRPPNPNfRPPPPPNRRPPP) z 328 2825 m (V5)b 2135 2825 m (V5)t 346 2839 m -(OOPNPPVJPPPPNPNRRPPPPNPPPRPNPPZDRPPPPNNPTRPPPNPPPPRPNPTRJPPPNPNRQRPNPPPPPRPNPN^DPPPPPNNTPRNPPPPPPRNPPNXHPRPNPNPRRPPPPPPPPPPPPRRLOPPPPNPRRPPPPPPPPRPNPP\\DPPPPNPNRRRPPPNPPPRVHPPPPNPNRRPPPPPPPPPPONPRPPNPTPLPPPPPNPPRRPPNRNPRPPPPPPXFPPPPPNPRRPPPPPPPPPPPPN) z -(\\DPPPPONPRRPPPPPPPPPRNPPXHPPPPNNPTPPPNPPPPRPNPPVHRPPPNPNRRPPPPPPPPPRPMPP\\DPPPPPNNRTPPPPNPPPPRPPNPPZFPPPPNPNRRRNPPPPPPPPPPNVNLPPPPPNPRQPNPPPPPPPPPPPXJNPPPPPNPRRPPPPPPPPPPPPN^DNPRNPNPRRPPPPPPPPRPNPPYFPPPPNPNRRPPPPPPPPPPNPRXFPPPPNPNRRPPPPPPPPRNPPTPLPP) z -(PPNPPRRPPNPROPPPPPPN^DNPPPPPNPRRPPPPPPPPPRPNPN^DPPPPNPNPTPPPPNRNPRPPNPPXHPPOPPNNTRPPNPRPPPRNPPVNLPPPPNNRRRPPNPPRPPPPPN`DLPPPNPNRRPPPPPPPRPPMPTNNPPPNPNPRRPPPNPPRPPNPPXHPPPPPNPPTPPPPPPPPPRPNPXNJPPPPNNPTRPMPPPPPPRPNPP\\DPPPPPNNRRRNPPPPPPPRPNPPVHPPPPPPNP) z -(RRPNPPPPPPRPNPPZDQPPPPNPRRPPPPPPPPRPPNP^DNPPPNPNRRRNPPPPPPRPNPTPLPPPPNNRRPPPPPPPOPPPPNTPLPPPPPNPRRPNPPPPPRPNPN\\FPPPPPPNPTPPPPPPPPPPRNPPP\\DNPPPPNOPRRPPPNPPRNRPPPN\\DPPPPPPNPRRPPPNPPPRPPNPPXHPPPPPNPPRRPNPPPPRPPOPNZFRPPPNPNRRRPPNPPPPPRPPPN`@PPPPNPPRRP) z -(PNPPRPPPPPPNZFPPPPPNPRRPMPPPPPPRNPNVNLPPPPNNRRPPPPPPPPPRPNPPZFPPPPPNPPRRPPPPPPPPPPPPNZLIPPPPPNPPTPPPPPPPPPPRNPPPZFPPPPPNPPRPPPPPPPPPRNPPTNNPPPPNPPRRPPPOPPPRPPNPZFPPPPPNPRRPPPPPPPPRPNPP\\DPPPPNPNRRPPPPPPPPPRNPNZFPPPPONPPRPPPPPPPPPPPPNXHPPPPPNPPTPPPPPP) z -(PPPRPNPN\\FPPPNPPNPTPPPPPPPPPPQNPN\\DPPPPPNPPRRPPPPPPPPPPPNPXHPPPPNPNRRPPPPPPPPPPPPNZFPPRPNPNRQPPPPPPPPRPNPP^@PPRNPNPRRRNPPPPPPRPNPZJLPPPPNNRRPPPPPPPPPPPPNTPLOPPPPNPPRRPPNPPPPRPPPPPVHRPPPNPNRRRNPPPPPPPRPPNPZFPPPPPNNRTPPPNOPPPRPPPNTXDPPPPPNPRPPPPPPPPP) z -(PPPNPXHPPPPPNPRRPPNPPRPPPPPN\\DPPRPNONRRPPPPPPPPRPNPN^DPPPNPNPRRPPPPPPPPRNPNVPJPPPPPNPRPPPPPPPPPPPPOVJNPPRPNPNTRPPPPNRPPPPPPPN^DPPPNPPNPTPPPPPPPPPRPPNPZJLPPPPNNRRPQNPPPPPPRPNPNZFRPPPNPNRRPPPPPPPPPPPPRRLPPPPNNRTPPPPPPPPRPNPP\\DPOPPNNPRRRNPPPRPPPPPPPXF) z -(PPPPPNPRRPPPNPRPPPPPNPXHPPPPNPNPRRPPPPPPNQPPNPTRJPRPPNPNRRPPP) z +(OONPPPVHPPPPPNPPRRNPPPPPPPPPPN\\BRPPPPPNPTPPPPPPPPPPPPPTRHPPPPNPPSPPPPPPPPPPPPN\\FNPPPPNPRRPPPPPPPPPPPNPXHPPPPPNPRRPNPPPPPRPPNPTRJORPPNPNTRPPPNPRPPPPPPN^BPPPPPPNPTPPPPPNRPPVJNPPPPNPRPRPPNPPPPPPOPPPRNPPTPJPRPNPPNPTPPPPPPPPPRPNPPXHPPPPPNNRRRPNPPPPPRPPN) z +(P\\DPPPPMPNRRRPNPPPRPPPPPNXHPPPPPNPRPPPPPPPPPPPPNXHPPPPPNPPTPPPPPPPPPPPOPN\\FNPRPNPNRRPPPPPPPPPPRNPPN\\DPPPPPNPRRPPPPPPNPRPNPPTNNPPPPNPNRQPPPPNRNRPPPPNXJPPPPNPNPTRPNPPPPPPRPPPN\\DPPPPPNPRRPPPPPPPPPPPPNYFPPPPPNPRRPNPPPPPPPPPPRVFPPPPPNPRRPPNPPPPRPPPPTP) z +(JPRNPPNPTPPPPPPOPPRPPPN^BPPPPPNPNTPPPPPPPPPRPPPPN\\DPPPPPNPPRPPPPPPPPPPPPPNZFRPOPNNPRRPPPPPPPRPPPNVNLPRPNPNPTPPPPPPPPPRNPN`DLPPPPNPRRPPPPPPPPPPONVNLPPPPNPPRPPPPPPPPPPPPNZFRPPPNPNRRRPPPNRPPPPPPNZLJPPPPPNPRRPOPPPPPPPPPPN\\DPPPPPNPRRPPPPPPPPPPPPNPVJPPPP) z +(PNNRRPPPPPPPPPPPPPNZFORPPPNNRTPPPPPPPPPRNPN^DNPPPPNPRRPPPPPPPPPPPNVPJPPPPPNPTPPPPNPPORPNPPTNNPPPPNPPRPPPPPPPPPPPPNZFRPPPPNPPRRPPPNPRPPPPPPNP\\DPPPPNPMPTPRNPPPPPPPRNPN^BPRPPPNNPTPPPPPPPPPPPPPPVHPRPPNPNRRPPPPPPPPPRMPPZFPPPPPNPPTPPPPPPPPPRPNPN`BPPPNPNPT) z +(PPPPPPPPPRPNPPXHPPPPNNRRPPOPPPPPPPNPPVNLPPPNPNPTPPPPPPPPPPPPPN\\DRPPPNPNPTRNPPPPPPPRPPNPXNIPPPPNNPRRPPPPPPPRPPPPPNRXFPRPNPPNPTPPPPPPPPPPPPPTNLPRPNPNPTPPPPORPPPRNPPXFRPPPNPNTRPPNPPRPPPRNPN\\DPPPPPNPPTPPPPPPPPPPPPNXHPPPPMPNRRPPNPPPPPPRNPNZFRPPPPNNRRRPP) z +(NPPRPPPPPPN\\DPPPPPNNRRRPPPNPPPPROPNP\\DPPPPNPNRRPPPPPPPPPRPNPNXHPPPPPPNPRRPNPPPPPRPNPPXHPPPPPNPPSPPPPPPPPPPPPP\\@RPPPPNNTRPPPPPPPPPPPN\\HLPPPPPNPTPPPNPPPPRPNPPRRLOPPPNPNRRPPPPPPPPPRNPPPXHPPPPPNPRRPPPPPPPPPPPPPPZDPPPPPNPRRPPPPOPPPPRNPPRZDPPPPNNPRRPPN) z +(PPPPPRNPPPVJPPPPNPNTPPPPPPPPRPNPN^DPPPPPMNTRPPPNPPPRPPPPN\\DPPPPPNNTRPPNPPPPRPPNPTRJPPPPNNPTPPPPNPPPRPPNOXHPPPPPPNPRRPPPPPPPPPRPNRN^BPPPPPNNRRRPPPPPPPPPRNPN\\JJPRPNPNPTPOPPPPPPPPPPPNZFPPPPPNPPRRPNPPPPRPPPNRRLPPPPPNRRPPPPPPPRPPPPN^BPOPPPNPRRPPPPPPPPRN) z +(PPPXHPPPPNNPRRPPPPPPPPRNPPNXHPPPPPPNPRRNPPPPPPORNPPRRLPPPPPNPPRRPP) z 4.5 S 2873 Ay 347 2853 m diff -Naur wfdb-10.2.9/checkpkg/lcheck.c wfdb-10.3.0/checkpkg/lcheck.c --- wfdb-10.2.9/checkpkg/lcheck.c Mon Jun 17 18:10:07 2002 +++ wfdb-10.3.0/checkpkg/lcheck.c Tue Nov 26 10:17:47 2002 @@ -1,5 +1,5 @@ -/* file: lcheck.c G. Moody 7 September 2001 - Last revised: 17 June 2002 +/* file: lcheck.c G. Moody 7 September 2001 + Last revised: 26 November 2002 ------------------------------------------------------------------------------- wfdbcheck: test WFDB library Copyright (C) 2002 George B. Moody @@ -25,26 +25,10 @@ */ #include -#ifdef __STDC__ -# include -#else -extern void exit(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -#endif -#ifndef BSD -# include -#else -# include -#endif - #include char *info, *pname, *prog_name(); -int n, nsig, i, j, framelen, errors = 0, stat, vflag = 0; +int n, nsig, i, j, framelen, errors = 0, istat, vflag = 0; char headerversion[40]; char *libversion; char *p, *q, *defpath, *dbpath; @@ -268,8 +252,8 @@ printf("[OK]: sampfreq(NULL) returned %g\n", f); /* *** setsampfreq *** */ - if (stat = setsampfreq(100.0)) { - printf("Error: setsampfreq returned %d (should have been 0)\n", stat); + if (istat = setsampfreq(100.0)) { + printf("Error: setsampfreq returned %d (should have been 0)\n", istat); errors++; } if (sampfreq(NULL) != 100.0) { @@ -289,19 +273,19 @@ printf("[OK]: sampfreq(%s) returned %g\n", record, f); /* *** annopen *** */ - stat = annopen(record, aiarray, 1); - if (stat) { + istat = annopen(record, aiarray, 1); + if (istat) { fprintf(stderr, - "Error: annopen of 1 file returned %d (should have been 0)\n", stat); + "Error: annopen of 1 file returned %d (should have been 0)\n", istat); errors++; } else if (vflag) printf("[OK]: annopen of 1 file succeeded\n"); - stat = annopen(record, aiarray, 2); - if (stat) { + istat = annopen(record, aiarray, 2); + if (istat) { fprintf(stderr, - "Error: annopen of 2 files returned %d (should have been 0)\n", stat); + "Error: annopen of 2 files returned %d (should have been 0)\n", istat); errors++; } else if (vflag) @@ -415,10 +399,10 @@ printf("[OK]: datstr returned '%s'\n", p); /* *** iannsettime *** */ - stat = iannsettime(t); - if (stat) { + istat = iannsettime(t); + if (istat) { printf("Error: iannsettime returned %d (should have been 0)\n", - stat); + istat); errors++; } else if (vflag) @@ -427,10 +411,10 @@ /* *** getann, stimstr *** */ for (i = 0; i < 5; i++) { - stat = getann(0, &annot); - if (stat != 0 && stat != -1) { + istat = getann(0, &annot); + if (istat != 0 && istat != -1) { printf("Error: getann returned %d (should have been 0 or -1)\n", - stat); + istat); errors++; } else if (vflag) @@ -440,10 +424,10 @@ } /* *** iannsettime, again *** */ - stat = iannsettime(0L); - if (stat) { + istat = iannsettime(0L); + if (istat) { printf("Error: iannsettime returned %d (should have been 0)\n", - stat); + istat); errors++; } else if (vflag) @@ -451,20 +435,20 @@ timstr(0L)); /* *** getann, putann *** */ - i = j = stat = 0; - while (stat == 0) { - stat = getann(0, &annot); - if (stat != 0 && stat != -1) { + i = j = istat = 0; + while (istat == 0) { + istat = getann(0, &annot); + if (istat != 0 && istat != -1) { printf("Error: getann returned %d (should have been 0 or -1)\n", - stat); + istat); errors++; } - else if (stat == 0) { + else if (istat == 0) { i++; - stat = putann(0, &annot); - if (stat != 0) { + istat = putann(0, &annot); + if (istat != 0) { printf("Error: putann returned %d (should have been 0)\n", - stat); + istat); errors++; } else j++; @@ -572,10 +556,10 @@ printf("[OK]: timstr returned '%s'\n", p); /* *** isigsettime *** */ - stat = isigsettime(t); - if (stat) { + istat = isigsettime(t); + if (istat) { printf("Error: isigsettime returned %d (should have been 0)\n", - stat); + istat); errors++; } else if (vflag) @@ -601,10 +585,10 @@ /* *** isigsettime *** */ t = tt-1; /* try a backward skip, to one sample before the previous set */ - stat = isigsettime(t); - if (stat) { + istat = isigsettime(t); + if (istat) { printf("Error: isigsettime returned %d (should have been 0)\n", - stat); + istat); errors++; } else if (vflag) @@ -627,10 +611,10 @@ } /* Now return to the beginning of the record and copy it. */ - stat = isigsettime(t = 0L); - if (stat) { + istat = isigsettime(t = 0L); + if (istat) { printf("Error: isigsettime returned %d (should have been 0)\n", - stat); + istat); errors++; } else if (vflag) @@ -642,21 +626,21 @@ si[i].fname = realloc(si[i].fname, strlen(orec) + 5); sprintf(si[i].fname, "%s.dat", orec); } - stat = osigfopen(si, nsig); - if (stat != nsig) { + istat = osigfopen(si, nsig); + if (istat != nsig) { printf("Error: osigfopen returned %d (should have been %d)\n", - stat, nsig); + istat, nsig); errors++; } else if (vflag) - printf("[OK]: osigfopen returned %d\n", stat); + printf("[OK]: osigfopen returned %d\n", istat); /* *** getframe (again), putvec *** */ while ((n = getframe(vector)) == nsig) { t++; - if ((stat = putvec(vector)) != nsig) { + if ((istat = putvec(vector)) != nsig) { printf("Error: putvec returned %d (should have been %d)\n", - stat, nsig); + istat, nsig); errors++; break; } @@ -668,18 +652,18 @@ } else if (vflag) /* getframe reached EOF, checksums OK */ printf("[OK]: getframe read %ld samples\n", t); - if (stat != nsig) { /* some error occurred while writing samples */ + if (istat != nsig) { /* some error occurred while writing samples */ printf("Error: putvec returned %d (should have been %d) at %s\n", - stat, nsig, mstimstr(t)); + istat, nsig, mstimstr(t)); errors++; } else if (vflag) /* putvec wrote all samples without apparent error */ printf("[OK]: putvec wrote %ld samples\n", t); /* *** newheader *** */ - stat = newheader(orec); - if (stat) { /* some error occurred while writing the header */ - printf("Error: newheader returned %d (should have been 0)\n", stat); + istat = newheader(orec); + if (istat) { /* some error occurred while writing the header */ + printf("Error: newheader returned %d (should have been 0)\n", istat); errors++; } else if (vflag) /* putvec wrote all samples without apparent error */ @@ -689,9 +673,9 @@ n = 0; if (info = getinfo(record)) { do { - stat = putinfo(info); - if (stat) { - printf("Error: putinfo returned %d (should have been 0)\n", stat); + istat = putinfo(info); + if (istat) { + printf("Error: putinfo returned %d (should have been 0)\n", istat); errors++; } else diff -Naur wfdb-10.2.9/checkpkg/libcheck wfdb-10.3.0/checkpkg/libcheck --- wfdb-10.2.9/checkpkg/libcheck Mon Jun 17 18:42:10 2002 +++ wfdb-10.3.0/checkpkg/libcheck Fri Nov 22 15:23:53 2002 @@ -1,6 +1,6 @@ #!/bin/sh -# file: libcheck G. Moody 8 September 2001 -# Last revised: 17 June 2002 +# file: libcheck G. Moody 8 September 2001 +# Last revised: 22 November 2002 # # This script checks the functionality of the WFDB library by comparing the # outputs of 'lcheck' with expected outputs. See 'lcheck.c' for details of @@ -8,6 +8,10 @@ # 'lcheck' must be run within this directory to ensure that its local input # files (in ../data) are available. # +# 'make check' invokes this script with DBDIR as a command-line argument; +# this is used to edit the expected lcheck.log to reflect the installation +# directory. +# # Suggestions for additional checks are welcome; please send them to the # author (george@mit.edu). @@ -34,9 +38,9 @@ CF="$CF udb/100s.chk udb/100z.dat udb/100z.hea" cp ../data/100s.atr expected/udb/100s.chk cp ../data/100s.dat expected/udb/100z.dat - cp expected/lcheck.log-NETFILES expected/lcheck.log + sed s+/usr/database+$1+ expected/lcheck.log else - cp expected/lcheck.log-no-NETFILES expected/lcheck.log + sed s+/usr/database+$1+ expected/lcheck.log fi PASS=0 diff -Naur wfdb-10.2.9/conf/cygwin-slib.def wfdb-10.3.0/conf/cygwin-slib.def --- wfdb-10.2.9/conf/cygwin-slib.def Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/conf/cygwin-slib.def Thu Nov 21 21:36:13 2002 @@ -0,0 +1,132 @@ +# file: cygwin-slib.def I. Henry and G. Moody 19 November 2002 +# Last revised: 21 November 2002 + +# This section contains settings suitable for generating a DLL (shared library) +# under MS Windows using the free Cygwin/gcc ANSI C compiler, available from +# http://www.cygwin.com/. To use this successfully, you need to have installed +# Cygwin 1.x or later. + +# Choose a value for WFDBROOT to determine where the WFDB Software Package will +# be installed. One of the following is usually a reasonable choice. +# Installing in /usr generally requires root permissions, but will be easiest +# for future software development (no special -I or -L options will be needed +# to compile software with the WFDB library, since the *.h files and the +# library will be installed in the standard directories). +WFDBROOT = /usr +# Installing in /usr/local usually requires root permissions. On a multi-user +# system where it is desirable to keep the OS vendor's software separate from +# other software, this is a good choice. Another common choice in such cases +# is /opt . +# WFDBROOT = /usr/local +# To install without root permissions, a good choice is to set WFDBROOT to the +# name of your home directory, as in the example below (change as needed). +# WFDBROOT = /home/frodo + +# If the W3C's libwww library of HTTP and FTP client code is available, and +# you wish to compile a WFDB library with NETFILES support, set LWC +# to 'libwww-config' (a utility supplied with libwww). Otherwise set +# LWC to ':' (a program that does nothing, successfully). +LWC = libwww-config + +# INCDIR specifies the name of a directory in which to install the WFDB +# library's #include <...> files. +INCDIR = $(WFDBROOT)/include + +# LIBDIR specifies the name of a directory in which to install the WFDB +# library. +LIBDIR = $(WFDBROOT)/lib + +# BINDIR specifies the name of a directory in which to install the WFDB +# DLL. +BINDIR = $(WFDBROOT)/bin + +# CC is the name of your C compiler. +CC = gcc + +# CCDEFS is the set of C compiler options needed to set preprocessor variables +# while compiling the WFDB Software Package. CCDEFS should always include +# VDEFS. +CCDEFS = $(VDEFS) -DNOVALUES_H + +# CFLAGS is the set of C compiler options used when compiling the shared +# library. CFLAGS should always include CCDEFS. +CFLAGS = -g -O $(CCDEFS) `$(LWC) --cflags` -I$(INCDIR) + +# WFDBLIB_BASENAME is the name, without version numbers, of the alternate +# library. WFDBLIB_SONAME is the shared object name ("soname") of the +# alternate library; normally, this includes the base name and the major +# version number only. WFDBLIB is the complete name, including the minor +# version number. Symbolic links from WFDBLIB to WFDBLIB_BASENAME and +# WFDBLIB_SONAME will be created as the final step in building the alternate +# library. +WFDBLIB_DLLNAME = wfdb-cyg-$(MAJOR)-$(MINOR).dll +WFDBLIB_BASENAME = libwfdb.dll.a +WFDBLIB_SONAME = $(WFDBLIB_BASENAME).$(MAJOR) +WFDBLIB = $(WFDBLIB_SONAME).$(MINOR) +# For a shared library, the soname is significant for proper run-time binding. +# If you change function interfaces in the library, change its soname by +# incrementing the major version number; when you do this, set the minor +# version number to zero. If you change the library without changing the +# function interfaces, increment the minor version number; this allows existing +# binaries to use the new version without recompilation, since the soname is +# unchanged in this case. + +# BUILDLIB is the command that creates the shared WFDB library once its +# components have been compiled separately; the list of *.o files that +# make up the library will be appended to BUILDLIB. +BUILDLIB = gcc -shared -o $(WFDBLIB_DLLNAME) \ + -Wl,--out-implib=$(WFDBLIB) \ + -Wl,--export-all-symbols \ + -Wl,--enable-auto-import + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files. +BUILDLIB_LDFLAGS = `$(LWC) --libs` `$(LWC) --libs` `$(LWC) --libs` + +# LDCONFIG is the name of the program needed to refresh the system's cached +# index of shared libraries. +LDCONFIG = /sbin/ldconfig + +# PRINT is the name of the program used to produce listings (including any +# options for the desired formatting). +PRINT = lpr + +# SETPERMISSIONS is the command needed to make the installed files accessible +# to those who will use them. The value given below makes them readable by +# everyone, and writeable by the owner only. (If you perform the installation +# as `root', `root' is the owner of the installed files.) +SETPERMISSIONS = chmod 644 + +# SETDPERMISSIONS is similarly used to make directories created during the +# installation accessible. +SETDPERMISSIONS = chmod 755 + +# SETLPERMISSIONS is the command needed to make the WFDB library usable by +# programs linked to it. +SETLPERMISSIONS = chmod 755 + +# `make' (with no target specified) will be equivalent to `make all'. +make-all: all + +# `make lib-post-install' should be run after installing the WFDB library. +lib-post-install: + cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_BASENAME) + cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_SONAME) + cp $(WFDBLIB_DLLNAME) $(BINDIR) + +lib-post-uninstall: + rm -f $(LIBDIR)/$(WFDBLIB_BASENAME) + rm -f $(LIBDIR)/$(WFDBLIB_SONAME) + rm -f $(BINDIR)/$(WFDBLIB_DLLNAME) + +#______________________________________________________________________________ + + + + + + + + + + diff -Naur wfdb-10.2.9/conf/cygwin.def wfdb-10.3.0/conf/cygwin.def --- wfdb-10.2.9/conf/cygwin.def Thu Dec 13 22:35:53 2001 +++ wfdb-10.3.0/conf/cygwin.def Thu Nov 21 21:42:46 2002 @@ -1,13 +1,10 @@ # file: cygwin.def G. Moody 6 June 2000 -# Last revised: 13 December 2001 +# Last revised: 21 November 2002 # # This file contains default 'make' definitions for compiling the WFDB Software # Package under MS Windows using the free Cygwin/gcc ANSI C compiler, available -# from http://www.cygnus.com/cygwin/. -# -# To use this successfully, you need to have installed Cygwin B20 or later, -# as well as `which.exe' (which should be installed somewhere in your PATH; -# get it from http://www.physionet.org/physiotools/utilities/which/which.exe). +# from http://www.cygwin.com/. To use this successfully, you need to have +# installed Cygwin 1.x or later. # # Choose a value for WFDBROOT to determine where the WFDB Software Package will # be installed. One of the following is usually a reasonable choice. @@ -153,6 +150,36 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/darwin-slib.def wfdb-10.3.0/conf/darwin-slib.def --- wfdb-10.2.9/conf/darwin-slib.def Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/conf/darwin-slib.def Thu Nov 21 21:37:28 2002 @@ -0,0 +1,111 @@ +# file: darwin-slib.def I. Henry and G. Moody 14 November 2002 +# Last revised: 21 November 2002 +# Based on 'freebsd-slib.def'. + +# This section contains settings suitable for generating a shared library under +# Darwin (MacOS/X). + +# Choose a value for WFDBROOT to determine where the WFDB Software Package will +# be installed. One of the following is usually a reasonable choice. +# Installing in /usr generally requires root permissions, but will be easiest +# for future software development (no special -I or -L options will be needed +# to compile software with the WFDB library, since the *.h files and the +# library will be installed in the standard directories). +WFDBROOT = /usr +# Installing in /usr/local usually requires root permissions. On a multi-user +# system where it is desirable to keep the OS vendor's software separate from +# other software, this is a good choice. Another common choice in such cases +# is /opt . +# WFDBROOT = /usr/local +# To install without root permissions, a good choice is to set WFDBROOT to the +# name of your home directory, as in the example below (change as needed). +# WFDBROOT = /Users/frodo + +# If the W3C's libwww library of HTTP and FTP client code is available, and +# you wish to compile a WFDB library with NETFILES support, set LWC +# to 'libwww-config' (a utility supplied with libwww). Otherwise set +# LWC to ':' (a program that does nothing, successfully). +LWC = libwww-config + +# INCDIR specifies the name of a directory in which to install the WFDB +# library's #include <...> files. +INCDIR = $(WFDBROOT)/include + +# LIBDIR specifies the name of a directory in which to install the WFDB +# library. +LIBDIR = $(WFDBROOT)/lib + +# CC is the name of your C compiler. +CC = gcc + +# CCDEFS is the set of C compiler options needed to set preprocessor variables +# while compiling the WFDB Software Package. CCDEFS should always include +# VDEFS. +CCDEFS = $(VDEFS) -DNOVALUES_H + +# CFLAGS is the set of C compiler options used when compiling the shared +# library. CFLAGS should always include CCDEFS. +CFLAGS = -fPIC -fno-common -g -O $(CCDEFS) `$(LWC) --cflags` -I$(INCDIR) + +# WFDBLIB_BASENAME is the name, without version numbers, of the alternate +# library. WFDBLIB_SONAME is the shared object name ("soname") of the +# alternate library; normally, this includes the base name and the major +# version number only. WFDBLIB is the complete name, including the minor +# version number. Symbolic links from WFDBLIB to WFDBLIB_BASENAME and +# WFDBLIB_SONAME will be created as the final step in building the alternate +# library. +WFDBLIB_ROOT = libwfdb +WFDBLIB_BASENAME = $(WFDBLIB_ROOT).dylib +WFDBLIB_SONAME = $(WFDBLIB_ROOT).$(MAJOR).dylib +WFDBLIB = $(WFDBLIB_ROOT).$(MAJOR).$(MINOR).$(RELEASE).dylib +# For a shared library, the soname is significant for proper run-time binding. +# If you change function interfaces in the library, change its soname by +# incrementing the major version number; when you do this, set the minor +# version number to zero. If you change the library without changing the +# function interfaces, increment the minor version number; this allows existing +# binaries to use the new version without recompilation, since the soname is +# unchanged in this case. + +# BUILDLIB is the command that creates the shared WFDB library once its +# components have been compiled separately; the list of *.o files that +# make up the library will be appended to BUILDLIB. +BUILDLIB = gcc -dynamiclib -install_name $(LIBDIR)/$(WFDBLIB_SONAME) \ + -compatibility_version $(MAJOR).$(MINOR) \ + -current_version $(MAJOR).$(MINOR).$(RELEASE) \ + `$(LWC) --libs` -o $(WFDBLIB) + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = + +# PRINT is the name of the program used to produce listings (including any +# options for the desired formatting). +PRINT = lpr + +# SETPERMISSIONS is the command needed to make the installed files accessible +# to those who will use them. The value given below makes them readable by +# everyone, and writeable by the owner only. (If you perform the installation +# as `root', `root' is the owner of the installed files.) +SETPERMISSIONS = chmod 644 + +# SETDPERMISSIONS is similarly used to make directories created during the +# installation accessible. +SETDPERMISSIONS = chmod 755 + +# SETLPERMISSIONS is the command needed to make the WFDB library usable by +# programs linked to it. +SETLPERMISSIONS = chmod 755 + +# `make' (with no target specified) will be equivalent to `make all'. +make-all: all + +# `make lib-post-install' should be run after installing the WFDB library. +lib-post-install: + cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_BASENAME) + cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_SONAME) + +lib-post-uninstall: + rm -f $(LIBDIR)/$(WFDBLIB_BASENAME) + rm -f $(LIBDIR)/$(WFDBLIB_SONAME) + +#______________________________________________________________________________ diff -Naur wfdb-10.2.9/conf/darwin.def wfdb-10.3.0/conf/darwin.def --- wfdb-10.2.9/conf/darwin.def Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/conf/darwin.def Thu Nov 21 21:11:38 2002 @@ -0,0 +1,153 @@ +# file: darwin.def G. Moody and I. Henry 14 November 2002 +# Last revised: 21 November 2002 +# 'make' definitions for compiling the WFDB Software Package under Darwin +# +# Based on 'freebsd.def'. +# +# Choose a value for WFDBROOT to determine where the WFDB Software Package will +# be installed. One of the following is usually a reasonable choice. +# Installing in /usr generally requires root permissions, but will be easiest +# for future software development (no special -I or -L options will be needed +# to compile software with the WFDB library, since the *.h files and the +# library will be installed in the standard directories). +WFDBROOT = /usr +# Installing in /usr/local usually requires root permissions. On a multi-user +# system where it is desirable to keep the OS vendor's software separate from +# other software, this is a good choice. Another common choice in such cases +# is /opt . +# WFDBROOT = /usr/local +# To install without root permissions, a good choice is to set WFDBROOT to the +# name of your home directory, as in the example below (change as needed). +# WFDBROOT = /Users/frodo + +# If the W3C's libwww library of HTTP and FTP client code is available, and +# you wish to compile a WFDB library with NETFILES support, set LWC to +# 'libwww-config' (a utility supplied with libwww). Otherwise set LWC to ':' +# (a program that does nothing, successfully). +LWC = libwww-config + +# LDLIBWWW, which is appended to LDFLAGS below, is the set of options needed +# to link with libwww. If libwww is not installed, or if libwfdb is a shared +# library, LDLIBWWW can be empty (if there is a '#' immediately after the '=' +# below, the remainder of the line is ignored, so LDLIBWWW is empty in this +# case). Otherwise, it is generated from the output of LWC. Note that up to +# three passes through the option list are necessary to satisfy all +# dependencies when linking to the static libwww libraries. +LDLIBWWW = # `$(LWC) --libs` `$(LWC) --libs` `$(LWC) --libs` + +# BINDIR specifies the directory in which the applications will be installed; +# it should be a directory in the PATH of those who will use the applications. +BINDIR = $(WFDBROOT)/bin + +# DBDIR specifies the name of a directory in which to install the contents +# of the `data' directory. +DBDIR = $(WFDBROOT)/database + +# INCDIR specifies the name of a directory in which to install the WFDB +# library's #include <...> files. +INCDIR = $(WFDBROOT)/include + +# INFODIR is the GNU info directory (optional, needed to `make info'). +INFODIR = /usr/local/info + +# LIBDIR specifies the name of a directory in which to install the WFDB +# library. +LIBDIR = $(WFDBROOT)/lib + +# PSPDIR specifies the name of a directory in which to install the PostScript +# prolog (*.pro) files from the 'app' directory. +PSPDIR = $(WFDBROOT)/lib/ps + +# CC is the name of your C compiler. +CC = gcc + +# CCDEFS is the set of C compiler options needed to set preprocessor variables +# while compiling the WFDB Software Package. CCDEFS should always include +# VDEFS. +CCDEFS = $(VDEFS) -DNOVALUES_H + +# CFLAGS is the set of C compiler options. CFLAGS should always include +# CCDEFS. +CFLAGS = -g -O $(CCDEFS) `$(LWC) --cflags` -I$(INCDIR) + +# LDFLAGS is appended to the C compiler command line to specify loading the +# WFDB library. +LDFLAGS = -L$(LIBDIR) -lwfdb $(LDLIBWWW) + +# WFDBLIB is the name of the standard WFDB library. In order to access it via +# `-lwfdb', WFDBLIB should be `libwfdb.a'. +WFDBLIB = libwfdb.a + +# BUILDLIB is the command that creates the static WFDB library once its +# components have been compiled separately; the list of *.o files that +# make up the library will be appended to BUILDLIB. +BUILDLIB = $(AR) $(ARFLAGS) $(WFDBLIB) + +# PRINT is the name of the program used to produce listings (including any +# options for the desired formatting). +PRINT = lpr + +# SETPERMISSIONS is the command needed to make the installed files accessible +# to those who will use them. The value given below makes them readable by +# everyone, and writeable by the owner only. (If you perform the installation +# as `root', `root' is the owner of the installed files.) +SETPERMISSIONS = chmod 644 + +# SETDPERMISSIONS is similarly used to make directories created during the +# installation accessible. +SETDPERMISSIONS = chmod 755 + +# SETLPERMISSIONS is the command needed to make the WFDB library usable by +# programs linked to it. +SETLPERMISSIONS = chmod 644 + +# SETXPERMISSIONS is the command needed to make the applications accessible. +SETXPERMISSIONS = chmod 755 + +# STRIP is the command used to compact the compiled binaries by removing their +# symbol tables. +STRIP = strip +# To retain the symbol tables for debugging, comment out the previous line, and +# uncomment the next line. +# STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... + +# `make' (with no target specified) will be equivalent to `make all'. +make-all: all + +# `make lib-post-install' should be run after installing the WFDB library. +lib-post-install: + ranlib $(LIBDIR)/$(WFDBLIB) + +lib-post-uninstall: + echo "Nothing to be done for lib-post-uninstall" +# _____________________________________________________________________________ diff -Naur wfdb-10.2.9/conf/freebsd-slib.def wfdb-10.3.0/conf/freebsd-slib.def --- wfdb-10.2.9/conf/freebsd-slib.def Tue Mar 5 17:00:13 2002 +++ wfdb-10.3.0/conf/freebsd-slib.def Thu Nov 21 21:38:57 2002 @@ -1,5 +1,5 @@ # file: freebsd-slib.def G. Moody 5 March 2002 -# +# Last revised: 21 November 2002 # Based on 'linux-slib.def'. # This section contains settings suitable for generating an ELF-format shared @@ -70,6 +70,10 @@ # make up the library will be appended to BUILDLIB. BUILDLIB = gcc -shared -Wl,-soname,$(WFDBLIB_SONAME) `$(LWC) --libs` \ -o $(WFDBLIB) + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = # LDCONFIG is the name of the program needed to refresh the system's cached # index of shared libraries. diff -Naur wfdb-10.2.9/conf/freebsd.def wfdb-10.3.0/conf/freebsd.def --- wfdb-10.2.9/conf/freebsd.def Tue Mar 5 16:53:27 2002 +++ wfdb-10.3.0/conf/freebsd.def Thu Nov 21 20:17:29 2002 @@ -1,5 +1,5 @@ # file: freebsd.def G. Moody 5 March 2002 -# +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under FreeBSD # # Based on 'linux.def', with edits for FreeBSD thanks to Giuseppe Pagnoni. @@ -110,6 +110,36 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/generic-slib.def wfdb-10.3.0/conf/generic-slib.def --- wfdb-10.2.9/conf/generic-slib.def Mon Dec 17 22:27:55 2001 +++ wfdb-10.3.0/conf/generic-slib.def Thu Nov 21 21:41:00 2002 @@ -1,5 +1,5 @@ # file: generic-slib.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # This section contains settings suitable for compiling a shared version of the # WFDB library under versions of UNIX that are not otherwise recognized by # 'configure'. Not all versions of UNIX support shared libraries, so you may @@ -91,6 +91,10 @@ # if gcc and the GNU binutils are installed. BUILDLIB = gcc -shared -Wl,-soname,$(SWFDBLIB_SONAME) \ `$(LWC) --libs` -o $(SWFDBLIB) + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = # PRINT is the name of the program used to produce listings (including any # options for the desired formatting). diff -Naur wfdb-10.2.9/conf/generic.def wfdb-10.3.0/conf/generic.def --- wfdb-10.2.9/conf/generic.def Thu Dec 13 23:00:41 2001 +++ wfdb-10.3.0/conf/generic.def Thu Nov 21 20:18:21 2002 @@ -1,5 +1,5 @@ # file: generic.def G. Moody 31 May 2000 -# Last revised: 13 December 2001 +# Last revised: 21 November 2002 # This file contains default 'make' definitions for compiling the WFDB Software # Package under versions of UNIX that are not otherwise recognized by # 'configure'. @@ -161,6 +161,36 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/hpux-slib.def wfdb-10.3.0/conf/hpux-slib.def --- wfdb-10.2.9/conf/hpux-slib.def Mon Dec 17 22:26:02 2001 +++ wfdb-10.3.0/conf/hpux-slib.def Thu Nov 21 21:41:22 2002 @@ -1,5 +1,5 @@ # file: hpux-slib.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # This section contains settings suitable for generating a shared library under # HP-UX. @@ -71,6 +71,10 @@ # components have been compiled separately; the list of *.o files that # make up the library will be appended to BUILDLIB. BUILDLIB = ld -b `$(LWC) --libs` -o $(WFDBLIB) + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = # PRINT is the name of the program used to produce listings (including any # options for the desired formatting). diff -Naur wfdb-10.2.9/conf/hpux.def wfdb-10.3.0/conf/hpux.def --- wfdb-10.2.9/conf/hpux.def Mon Dec 17 22:25:23 2001 +++ wfdb-10.3.0/conf/hpux.def Thu Nov 21 20:19:39 2002 @@ -1,5 +1,5 @@ # file: hpux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2001 # 'make' definitions for compiling the WFDB library under HP-UX # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -131,6 +131,36 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/linux-slib.def wfdb-10.3.0/conf/linux-slib.def --- wfdb-10.2.9/conf/linux-slib.def Mon Dec 17 22:22:14 2001 +++ wfdb-10.3.0/conf/linux-slib.def Thu Nov 21 21:41:44 2002 @@ -1,5 +1,5 @@ # file: linux-slib.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # This section contains settings suitable for generating an ELF-format shared # library under Linux. @@ -68,6 +68,10 @@ # make up the library will be appended to BUILDLIB. BUILDLIB = gcc -shared -Wl,-soname,$(WFDBLIB_SONAME) `$(LWC) --libs` \ -o $(WFDBLIB) + +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = # LDCONFIG is the name of the program needed to refresh the system's cached # index of shared libraries. diff -Naur wfdb-10.2.9/conf/linux.def wfdb-10.3.0/conf/linux.def --- wfdb-10.2.9/conf/linux.def Mon Dec 17 22:21:49 2001 +++ wfdb-10.3.0/conf/linux.def Thu Nov 21 20:14:38 2002 @@ -1,5 +1,5 @@ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -108,6 +108,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/solaris-slib.def wfdb-10.3.0/conf/solaris-slib.def --- wfdb-10.2.9/conf/solaris-slib.def Mon Dec 17 22:24:15 2001 +++ wfdb-10.3.0/conf/solaris-slib.def Thu Nov 21 21:42:04 2002 @@ -1,5 +1,5 @@ # file: solaris-slib.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # This section contains settings suitable for generating a shared library under # Solaris. @@ -19,7 +19,6 @@ # name of your home directory, as in the example below (change as needed). # WFDBROOT = /home/frodo - # If the W3C's libwww library of HTTP and FTP client code is available, and # you wish to compile a WFDB library with NETFILES support, set LWC # to 'libwww-config' (a utility supplied with libwww). Otherwise set @@ -74,6 +73,10 @@ # make up the library will be appended to BUILDLIB. BUILDLIB = ld -o $(WFDBLIB) -G -z text `$(LWC) --libs` +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = + # PRINT is the name of the program used to produce listings (including any # options for the desired formatting). PRINT = lpr @@ -97,8 +100,9 @@ # `make lib-post-install' should be run after installing the WFDB library. lib-post-install: - cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_BASENAME) - cd $(LIBDIR); ln -sf $(WFDBLIB) $(WFDBLIB_SONAME) + cd $(LIBDIR); rm $(WFDBLIB_BASENAME) $(WFDBLIB_SONAME); \ + ln -s $(WFDBLIB) $(WFDBLIB_BASENAME); \ + ln -s $(WFDBLIB) $(WFDBLIB_SONAME) lib-post-uninstall: rm -f $(LIBDIR)/$(WFDBLIB_BASENAME) diff -Naur wfdb-10.2.9/conf/solaris.def wfdb-10.3.0/conf/solaris.def --- wfdb-10.2.9/conf/solaris.def Mon Dec 17 22:24:38 2001 +++ wfdb-10.3.0/conf/solaris.def Thu Nov 21 20:16:15 2002 @@ -1,5 +1,5 @@ # file: solaris.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Solaris # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -116,6 +116,36 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) -DOWTOOLKIT_WARNING_DISABLED + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +# HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/conf/version.def wfdb-10.3.0/conf/version.def --- wfdb-10.2.9/conf/version.def Sat Oct 26 04:46:05 2002 +++ wfdb-10.3.0/conf/version.def Mon Nov 25 22:41:35 2002 @@ -1,10 +1,10 @@ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official diff -Naur wfdb-10.2.9/configure wfdb-10.3.0/configure --- wfdb-10.2.9/configure Thu Jul 18 15:40:36 2002 +++ wfdb-10.3.0/configure Mon Nov 25 10:11:41 2002 @@ -1,6 +1,6 @@ #! /bin/sh -# file: configure G. Moody 24 May 2000 -# Last revised: 18 July 2002 +# file: configure G. Moody 24 May 2000 +# Last revised: 25 November 2002 # Configuration script for the WFDB Software Package # This script was not generated using 'autoconf'. If you can implement @@ -86,7 +86,14 @@ cat conf/hpux.def >>conf/site.def cat conf/version.def conf/hpux-slib.def >conf/site-slib.def ;; CYGWIN*) OS=cygwin - cat conf/cygwin.def >>conf/site.def ;; + cat conf/cygwin.def >>conf/site.def + cat conf/version.def conf/cygwin-slib.def >conf/site-slib.def ;; + Darwin*) OS=Darwin + LIBTYPE=dynamic + cat conf/darwin.def >>conf/site.def + cat conf/version.def conf/darwin-slib.def > conf/site-slib.def + echo "It is normal for Mac OS X to be recognized as Darwin." + echo "Building static libraries is not supported on Darwin." ;; *) OS=generic cat conf/generic.def >>conf/site.def cat conf/version.def conf/generic-slib.def >conf/site-slib.def @@ -102,7 +109,7 @@ echo echo "The WFDB library may be compiled as a static library or as a" echo "dynamically loaded (shared) library (the default). Type S for a" - conf/prompt "static library, or D for a dynamically loaded library: " + conf/prompt "static library, or D for a dynamically loaded library: " " " read LIBTYPE fi else @@ -129,7 +136,7 @@ echo "libraries only may cause compilation to fail if your" echo "system does not have a complete set of static libraries." echo "Type S to link to static libraries only, or D to link to" - conf/prompt "dynamically loaded libraries where available: " + conf/prompt "dynamically loaded libraries where available: " "" read SYSLIBS fi case x$SYSLIBS in @@ -137,13 +144,16 @@ conf/site.tmp mv conf/site.tmp conf/site.def echo "Applications will be linked with static libraries only." + SYSLIBS=static ;; - *) ;; + *) SYSLIBS=dynamic ;; esac +else + SYSLIBS=dynamic fi echo -conf/prompt "Looking for the C compiler ..." +conf/prompt "Looking for the C compiler ..." "" if ( which gcc 2>&1 | grep "no \|not " >/dev/null ) then if (which cc 2>&1 | grep "no \|not " >/dev/null ) @@ -182,7 +192,7 @@ DIR= while [ x$DIR = x ] do - conf/prompt "Choose a location, or press to install in /usr: " + conf/prompt "Choose a location, or press to install in /usr: " "" read DIR case x$DIR in x/usr) ;; diff -Naur wfdb-10.2.9/convert/Makefile wfdb-10.3.0/convert/Makefile --- wfdb-10.2.9/convert/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/convert/Makefile Tue Nov 26 13:40:19 2002 @@ -33,12 +33,12 @@ # type `make listing'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -55,13 +55,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -171,6 +171,40 @@ # uncomment the next line. # STRIP = : +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... + # `make' (with no target specified) will be equivalent to `make all'. make-all: all @@ -182,11 +216,12 @@ echo "Nothing to be done for lib-post-uninstall" # _____________________________________________________________________________ # file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 5 November 2002 # This section of the Makefile should not need to be changed. -CFILES = a2m.c ad2m.c m2a.c md2a.c readid.c makeid.c edf2mit.c revise.c -XFILES = a2m ad2m m2a md2a readid makeid edf2mit revise +CFILES = a2m.c ad2m.c m2a.c md2a.c readid.c makeid.c edf2mit.c mit2edf.c \ + revise.c +XFILES = a2m ad2m m2a md2a readid makeid edf2mit mit2edf revise SCRIPTS = ahaconvert MFILES = Makefile Makefile.dos diff -Naur wfdb-10.2.9/convert/Makefile.dos wfdb-10.3.0/convert/Makefile.dos --- wfdb-10.2.9/convert/Makefile.dos Sat Oct 26 15:25:01 2002 +++ wfdb-10.3.0/convert/Makefile.dos Thu Nov 7 21:05:28 2002 @@ -1,5 +1,5 @@ # file: makefile.dos G. Moody 2 November 1989 -# Last revised: 26 October 2002 +# Last revised: 7 November 2002 # MSDOS `make' description file template for WFDB format converters # # WARNING: NO SUPPORT FOR PROPRIETARY COMPILERS. Previous versions of the WFDB @@ -47,7 +47,8 @@ # anything below this line. # ----------------------------------------------------------------------------- -XFILES = a2m.exe ad2m.exe m2a.exe md2a.exe makeid.exe readid.exe revise.exe +XFILES = a2m.exe ad2m.exe m2a.exe md2a.exe makeid.exe readid.exe \ + edf2mit.exe mit2edf.exe revise.exe # General rule for compiling C sources into executable files .c.exe: diff -Naur wfdb-10.2.9/convert/Makefile.tpl wfdb-10.3.0/convert/Makefile.tpl --- wfdb-10.2.9/convert/Makefile.tpl Sat Oct 26 15:22:06 2002 +++ wfdb-10.3.0/convert/Makefile.tpl Tue Nov 5 12:33:44 2002 @@ -1,9 +1,10 @@ # file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 5 November 2002 # This section of the Makefile should not need to be changed. -CFILES = a2m.c ad2m.c m2a.c md2a.c readid.c makeid.c edf2mit.c revise.c -XFILES = a2m ad2m m2a md2a readid makeid edf2mit revise +CFILES = a2m.c ad2m.c m2a.c md2a.c readid.c makeid.c edf2mit.c mit2edf.c \ + revise.c +XFILES = a2m ad2m m2a md2a readid makeid edf2mit mit2edf revise SCRIPTS = ahaconvert MFILES = Makefile Makefile.dos diff -Naur wfdb-10.2.9/convert/README wfdb-10.3.0/convert/README --- wfdb-10.2.9/convert/README Sat Oct 26 12:02:20 2002 +++ wfdb-10.3.0/convert/README Thu Nov 7 21:11:07 2002 @@ -1,9 +1,9 @@ file: README G. Moody 28 July 1989 - Last revised: 26 October 2002 + Last revised: 7 November 2002 This directory contains sources for WFDB applications which convert database -files in various unsupported formats to and from MIT format, including to and -from AHA DB formats. +files in various unsupported formats to and from MIT format (also known as +WFDB or PhysioBank format), including to and from EDF and AHA DB formats. Note that many commonly used formats are supported by the WFDB library. The program `xform' (in the `app' directory) is a flexible application for @@ -19,6 +19,11 @@ If you need to convert digital data to analog form, or vice versa, see program `sample' (for MS-DOS only) in the `app' directory. +European Data Format (EDF) has been used for storage of multiparameter, +multifrequency data (such as polysomnograms) since 1990. Program `edf2mit' +reads an EDF file and generates MIT-format header and signal files from it. +Program 'mit2edf' performs the inverse conversion. + AHA DB tape distribution format was used for both the AHA DB and the MIT-BIH DB between 1980 and 1990. AHA DB tape distribution format requires more space than the other formats supported by the WFDB library and applications, however, @@ -33,10 +38,6 @@ have a shell utility, such as 'bash' (included with the free Cygwin software package from http://www.cygwin.com/) in order to run 'ahaconvert'. -European Data Format (EDF) has been used for storage of multiparameter, -multifrequency data (such as polysomnograms) since 1990. Program `edf2mit' -reads an EDF file and generates MIT-format header and signal files from it. - This directory also contains the program `revise', which converts obsolete MIT header files into new-format MIT header files. (Unless you have very old header files, made before 1990, you will not need this program.) @@ -80,5 +81,6 @@ makeid.c Makes an AHA-format ID block for a database record edf2mit.c Converts an EDF file to MIT format +mit2edf.c Converts an MIT format record into an EDF file revise.c Converts an obsolete MIT header to a new-format MIT header diff -Naur wfdb-10.2.9/convert/edf2mit.c wfdb-10.3.0/convert/edf2mit.c --- wfdb-10.2.9/convert/edf2mit.c Fri Oct 12 13:13:08 2001 +++ wfdb-10.3.0/convert/edf2mit.c Thu Nov 14 19:20:21 2002 @@ -1,9 +1,9 @@ /* file: edf2mit.c G. Moody 16 October 1996 - Last revised: 12 October 2001 + Last revised: 14 November 2002 ------------------------------------------------------------------------------- Convert EDF (European Data Format) file to MIT format header and signal files -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,11 +26,6 @@ */ #include -#ifndef NOMALLOC_H -# include -#else -extern char *calloc(), *malloc(), *realloc(); -#endif #include char *pname; @@ -288,7 +283,7 @@ continue; } si[i].adczero = (sigdmax[i]+1 + sigdmin[i])/2; - adcrange = sigdmax[i]+1 - sigdmin[i]; + adcrange = sigdmax[i] - sigdmin[i]; si[i].gain = adcrange/(sigpmax[i] - sigpmin[i]); for (j = 0; adcrange > 1; j++) adcrange /= 2; diff -Naur wfdb-10.2.9/convert/mit2edf.c wfdb-10.3.0/convert/mit2edf.c --- wfdb-10.2.9/convert/mit2edf.c Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/convert/mit2edf.c Thu Nov 14 19:19:59 2002 @@ -0,0 +1,419 @@ +/* file: mit2edf.c G. Moody 2 November 2002 + Last revised: 14 November 2002 +------------------------------------------------------------------------------- +Convert MIT format header and signal files to EDF (European Data Format) file +Copyright (C) 2002 George B. Moody + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (george@mit.edu) or postal mail +(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, +please visit PhysioNet (http://www.physionet.org/). +_______________________________________________________________________________ + +*/ + +#include +#include + +#define EDFMAXBLOCK 61440 /* maximum data block length, in bytes */ + +char *pname; + +main(argc, argv) +int argc; +char **argv; +{ + char buf[100]; + char *header, *ofname = NULL, *p, *block, **blockp, *record = NULL; + double *pmax, *pmin, frames_per_second, seconds_per_block; + FILE *ofile = NULL; + int *dmax, *dmin, i, j, k, nsig, samples_per_frame, start_date_recorded, + edfplusflag = 0, vflag = 0, day, month, year, hour, minute, second; + long bytes_per_block, frames_per_block, n, nblocks, blocks_per_minute, + blocks_per_hour; + WFDB_Sample *v, *vp; + WFDB_Siginfo *si; + static char *month_name[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", + "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; + void help(); + + /* Interpret the command line. */ + pname = argv[0]; + for (i = 1; i < argc; i++) { + if (*argv[i] == '-') switch (argv[i][1]) { + case 'h': /* show usage and quit */ + help(); + exit(0); + case 'o': /* output file name follows */ + if (++i < argc) + ofname = argv[i]; + else { + fprintf(stderr, "%s: output file name must follow -o\n",pname); + exit(1); + } + break; + case 'p': /* format output as EDF+ */ + edfplusflag = 1; + break; + case 'r': /* record name follows */ + if (++i < argc) + record = argv[i]; + else { + fprintf(stderr, "%s: record name must follow -r\n", pname); + exit(1); + } + break; + case 'v': /* select verbose mode */ + vflag = 1; + break; + } + } + + /* Construct or validate the name of the output file. */ + if (ofname == NULL) { + for (p = record + strlen(record); p > record; p--) + if (*(p-1) == '/') break; + strncpy(buf, p, WFDB_MAXRNL); + strcat(buf, ".edf"); + ofname = buf; + } + else if (edfplusflag) { + p = ofname + strlen(ofname) - 4; + if (strcmp(p, ".edf") && strcmp(p, ".EDF")) { + (void)fprintf(stderr, "%s: '%s' is not a valid EDF+ file name\n", + pname, ofname); + (void)fprintf(stderr, + " EDF+ file names must end with '.edf' or '.EDF')\n"); + + exit(1); + } + } + + /* Open the input record. */ + if (record == NULL) { + help(); + exit(1); + } + 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(3); + + /* Open the output (EDF) file. */ + if ((ofile = fopen(ofname, "wb")) == NULL) { + (void)fprintf(stderr, "%s: can't create %s\n", pname, ofname); + exit(4); + } + + /* Get start date and time */ + p = timstr(0L); + start_date_recorded = 1; + if (*p != '[') { /* start date/time not recorded -- use current date */ + setbasetime(NULL); + p = timstr(0L); + start_date_recorded = 0; + } + i = sscanf(p, "[%d:%d:%d %d/%d/%d", + &hour, &minute, &second, &day, &month, &year); + if (i != 6) { /* start time, but not date, recorded */ + start_date_recorded = 0; + day = month = 1; + year = 1985; /* beginning of EDF epoch */ + } + + /* Calculate block duration. (In the EDF spec, blocks are called + "records" or "data records", but this would be confusing here + since "record" refers to the entire recording -- so here we say + "blocks". */ + for (i = samples_per_frame = 0; i < nsig; i++) + samples_per_frame += si[i].spf; + frames_per_second = strtim("1"); /* one second */ + frames_per_block = 10 * frames_per_second + 0.5; /* ten seconds */ + bytes_per_block = 2 * samples_per_frame * frames_per_block; + /* EDF specifies 2 bytes per sample */ + while (bytes_per_block > EDFMAXBLOCK) { + /* blocks would be too long -- reduce their length by a factor of 10 */ + frames_per_block /= 10; + bytes_per_block = samples_per_frame * 2 * frames_per_block; + } + seconds_per_block = frames_per_block / frames_per_second; + + /* Calculate the number of blocks to be written. strtim("e") is the frame + number of the last frame in the record, and that of the first frame is + 0, so the number of frames is strtim("e") + 1. The calculation rounds + up so that we don't lose any frames, even if the number of frames is not + an exact multiple of frames_per_block. */ + nblocks = strtim("e") / frames_per_block + 1; + + /* Allocate and initialize arrays and buffers. */ + if ((dmax = malloc(nsig * sizeof(int))) == NULL || + (dmin = malloc(nsig * sizeof(int))) == NULL || + (pmax = malloc(nsig * sizeof(double))) == NULL || + (pmin = malloc(nsig * sizeof(double))) == NULL || + (header = malloc((nsig + 1) * 256)) == NULL || + (v = malloc(samples_per_frame * sizeof(WFDB_Sample))) == NULL || + (block = malloc(bytes_per_block)) == NULL || + (blockp = malloc(nsig * sizeof(char *))) == NULL) { + (void)fprintf(stderr, "%s: insufficient memory\n", pname); + exit(2); + } + for (i = 0; i < (nsig + 1)*256; i++) + header[i] = ' '; + + if (vflag) + printf("Converting record %s to %s (%s mode)\n", record, ofname, + edfplusflag == 1 ? "EDF+" : "EDF"); + + /* Calculate physical and digital extrema. */ + for (i = 0; i < nsig; i++) { + dmax[i] = si[i].adczero + (1 << (si[i].adcres - 1)) - 1; + dmin[i] = si[i].adczero - (1 << (si[i].adcres - 1)); + pmax[i] = aduphys(i, dmax[i]); + pmin[i] = aduphys(i, dmin[i]); + } + + /* Start filling in the header. The first line of comments above each + entry is as given in the EDF technical specification + (http://www.hsr.nl/edf/edf_spec.htm). */ + p = header; + + /* Version of this data format (0). */ + strncpy(p, "0", 1); + p += 8; + + /* Local patient identification. */ + if (strlen(record) > 80) record[79] = '\0'; + strncpy(p, record, strlen(record)); + p += 80; + + /* Local recording identification. + + Bob Kemp recommends using this field to encode the start date including + an abbreviated month name in English and a full (4-digit) year, as is + done here if this information is available in the input record. EDF+ + requires this. */ + + if (start_date_recorded) + sprintf(buf, "Startdate %02d-%s-%d", day, month_name[month-1], year); + else { + sprintf(buf, "Startdate not recorded"); + if (edfplusflag) + fprintf(stderr, + "WARNING (%s): EDF+ requires start date (not specified)\n", + pname); + } + strncpy(p, buf, strlen(buf)); + p += 80; + + /* Start date of recording (dd.mm.yy). */ + sprintf(buf, "%02d.%02d.%02d", day, month, year % 100); + strncpy(p, buf, 8); + p += 8; + + /* Start time of recording (hh.mm.ss). */ + sprintf(buf, "%02d.%02d.%02d", hour, minute, second); + strncpy(p, buf, 8); + p += 8; + + /* Number of bytes in header. */ + sprintf(buf, "%ld", (nsig + 1)*256L); + strncpy(p, buf, strlen(buf)); + p += 8; + + /* Reserved. */ + if (edfplusflag) + strncpy(p, "EDF+C", 5); + p += 44; + + /* Number of blocks (-1 if unknown). */ + sprintf(buf, "%ld", nblocks); + strncpy(p, buf, strlen(buf)); + p += 8; + + /* Duration of a block, in seconds. */ + sprintf(buf, "%g", seconds_per_block); + if (strlen(buf) > 8) buf[8] = '\0'; + strncpy(p, buf, strlen(buf)); + p += 8; + + /* Number of signals. */ + sprintf(buf, "%d", nsig); + strncpy(p, buf, strlen(buf)); + p += 4; + + /* Label (e.g., EEG FpzCz or Body temp). */ + for (i = 0; i < nsig; i++, p += 16) { + if (strlen(si[i].desc) > 16) si[i].desc[16] = '\0'; + strncpy(p, si[i].desc, strlen(si[i].desc)); + } + + /* Transducer type (e.g., AgAgCl electrode). */ + for (i = 0; i < nsig; i++, p += 80) { + strncpy(p, "transducer type not recorded", + strlen("transducer type not recorded")); + } + + /* Physical dimension (e.g., uV or degreeC). */ + for (i = 0; i < nsig; i++, p += 8) { + if (si[i].units == NULL) si[i].units = "mV"; + else if (strlen(si[i].units) > 8) si[i].units[8] = '\0'; + strncpy(p, si[i].units, strlen(si[i].units)); + } + + /* Physical minimum (e.g., -500 or 34). */ + for (i = 0; i < nsig; i++, p += 8) { + sprintf(buf, "%g", pmin[i]); + strncpy(p, buf, strlen(buf)); + } + + /* Physical maximum (e.g., 500 or 40). */ + for (i = 0; i < nsig; i++, p += 8) { + sprintf(buf, "%g", pmax[i]); + strncpy(p, buf, strlen(buf)); + } + + /* Digital minimum (e.g., -2048). */ + for (i = 0; i < nsig; i++, p += 8) { + sprintf(buf, "%d", dmin[i]); + strncpy(p, buf, strlen(buf)); + } + + /* Digital maximum (e.g., 2047). */ + for (i = 0; i < nsig; i++, p += 8) { + sprintf(buf, "%d", dmax[i]); + strncpy(p, buf, strlen(buf)); + } + + /* Prefiltering (e.g., HP:0.1Hz LP:75Hz). */ + for (i = 0; i < nsig; i++, p += 80) { + strncpy(p, "prefiltering not recorded", + strlen("prefiltering not recorded")); + } + + /* Number of samples per block. */ + for (i = 0; i < nsig; i++, p += 8) { + sprintf(buf, "%d", frames_per_block * si[i].spf); + strncpy(p, buf, strlen(buf)); + } + + /* (The last 32*nsig bytes in the header are unused.) */ + + /* Write the header to the output file. */ + fwrite(header, 1, (nsig+1) * 256, ofile); + + /* Check that all characters in the header are valid (printable ASCII + between 32 and 126 inclusive). Note that this test does not prevent + generation of files containing invalid characters; it merely warns + the user if this has happened. */ + for (i = 0; i < (nsig+1) * 256; i++) + if (header[i] < 32 || header[i] > 126) + fprintf(stderr, + "WARNING (%s): output contains an invalid character, %d," + " at byte %ld\n", pname, header[i], i); + + /* In verbose mode, summarize what we've done so far. */ + if (vflag) { + printf(" Header block size: %d bytes\n", (nsig+1) * 256); + printf(" Data block size: %g second%s (%ld frame%s or %ld bytes)\n", + seconds_per_block, seconds_per_block == 1.0 ? "" : "s", + frames_per_block, frames_per_block == 1 ? "" : "s", + bytes_per_block); + for (p = timstr(strtim("e")); *p == ' '; p++) + ; + printf(" Recording length: %s" + " (%ld data blocks, %ld frames, %ld bytes)\n", + p, nblocks, nblocks*frames_per_block, nblocks*bytes_per_block); + printf(" Total length of file to be written: %ld bytes\n", + (nsig+1)*256 + nblocks*bytes_per_block); + + blocks_per_minute = (long)(60 / seconds_per_block); + blocks_per_hour = (long)60 * blocks_per_minute; + } + + /* Write the data blocks. */ + for (n = 1; n <= nblocks; n++) { + blockp[0] = block; + for (j = 1; j < nsig; j++) + blockp[j] = blockp[j-1] + 2 * frames_per_block * si[j].spf; + for (i = 0; i < frames_per_block; i++) { + if (nsig != getframe(v)) { + /* end of input: pad last block with zeroes */ + for (j = 0; j < samples_per_frame; j++) + v[j] = 0; + } + vp = v; + for (j = 0; j < nsig; j++) { + for (k = 0; k < si[j].spf; k++) { + *(blockp[j]++) = (*vp) & 0xff; + *(blockp[j]++) = ((*vp++ >> 8) & 0xff); + } + } + } + fwrite(block, 1, bytes_per_block, ofile); + if (vflag) { + if (n % blocks_per_minute == 0) { printf("."); fflush(stdout); } + if (n % blocks_per_hour == 0) printf("\n"); + } + } + (void)fclose(ofile); + printf("\n"); + + if (edfplusflag) { + fprintf(stderr, +"\nWARNING (%s): EDF+ requires the subject's gender, birthdate, and name, as\n" +" well as additional information about the recording that is not usually\n" +" available. This information is not saved in the output file even if\n" +" available. EDF+ also requires the use of standard names for signals and\n" +" for physical units; these requirements are not enforced by this program.\n" +" To make the output file fully EDF+ compliant, its header must be edited\n" +" manually.\n", + pname); + for (i = nsig-1; i >= 0; i--) + if (strcmp(si[i].desc, "EDF-Annotations") == 0) + break; + if (i < 0) + fprintf(stderr, +"\nWARNING: The output file does not include EDF annotations, which are\n" + " required for EDF+.\n"); + } + + wfdbquit(); + exit(0); +} + +static char *help_strings[] = { + "usage: %s -r RECORD [OPTIONS ...]\n", + "where RECORD is the name of the input record, and OPTIONS may include:", + " -h print this usage summary", + " -o EDFILE write the specified European Data Format file (default:", + " RECORD.edf)", + " -p write the output as an EDF+ file", + " -v select verbose mode", + "This program reads MIT-format signal and header files and writes an EDF", + "file containing the same data.", +NULL +}; + +void help() +{ + int i; + + (void)fprintf(stderr, help_strings[0], pname); + for (i = 1; help_strings[i] != NULL; i++) + (void)fprintf(stderr, "%s\n", help_strings[i]); +} diff -Naur wfdb-10.2.9/data/Makefile wfdb-10.3.0/data/Makefile --- wfdb-10.2.9/data/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/data/Makefile Tue Nov 26 13:40:19 2002 @@ -33,12 +33,12 @@ # listing'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -55,13 +55,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -170,6 +170,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/doc/Makefile wfdb-10.3.0/doc/Makefile --- wfdb-10.2.9/doc/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/doc/Makefile Tue Nov 26 13:40:19 2002 @@ -134,12 +134,12 @@ # `make ug'. To print the WFDB Programmer's Guide, type `make pg'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -156,13 +156,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -271,6 +271,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/doc/wag-src/Makefile wfdb-10.3.0/doc/wag-src/Makefile --- wfdb-10.2.9/doc/wag-src/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/doc/wag-src/Makefile Tue Nov 26 13:40:19 2002 @@ -59,12 +59,12 @@ # PostScript 'make wag.ps' (requires troff, tbl, latex, and dvips) # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -81,13 +81,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -197,6 +197,40 @@ # uncomment the next line. # STRIP = : +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... + # `make' (with no target specified) will be equivalent to `make all'. make-all: all @@ -207,8 +241,8 @@ lib-post-uninstall: echo "Nothing to be done for lib-post-uninstall" # _____________________________________________________________________________ -# file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 8 August 2002 +# file: Makefile.tpl G. Moody 24 May 2000 +# Last revised: 7 November 2002 # Change the settings below as appropriate for your setup. # D2PARGS is a list of options for dvips. Uncomment one of these to set the @@ -270,12 +304,6 @@ # of each page. TMAN = -rC1 -rD1 -man -# TMS is the TROFF option needed to load the 'ms' macro package. Use the -# following definition to get the standard 'ms' macros. -# TMS = -ms -# Use the following definition to get the GNU groff version of the 'ms' macros. -TMS = -mgs - # WAGPSREQ is the target that must be made in order to make the PostScript # version of the manual (wag.ps), and MAKEWAGPS is the command that must be # run in order to do this. The process is a bit convoluted, because the @@ -332,16 +360,20 @@ wag.html: cp -p ../misc/icons/* fixag.sh fixag.sed ../wag ./manhtml.sh ../wag *.1 *.3 *.5 *.7 + cp -p install0.tex install.tex + cp -p eval0.tex eval.tex latex2html -dir ../wag -local_icons -prefix in \ -up_url="wag.htm" -up_title="WFDB Applications Guide" install latex2html -dir ../wag -local_icons -prefix ev \ -up_url="wag.htm" -up_title="WFDB Applications Guide" eval + rm -f install.tex eval.tex cd ../wag; rm -f index.html WARNINGS *.aux *.log *.tex sed "s/LONGDATE/$(LONGDATE)/" ../wag/intro.htm sed "s/LONGDATE/$(LONGDATE)/" ../wag/faq.htm cd ../wag; ./fixag.sh "$(LONGDATE)" *.html; rm -f fixag.sh images.* cd ../wag; rm -f .I* .ORIG_MAP *.html *.pl fixag.sed - sed "s/LONGDATE/$(LONGDATE)/" ../wag/wag.htm cd ../wag; ln -s wag.htm index.html @@ -373,27 +405,37 @@ wag.ps: $(WAGPSREQ) $(MAKEWAGPS) -wag0.ps: wag.tex appguide.int install.tex eval.tex +wag0.ps: wag.tex + $(MAKE) wag2.ps + $(MAKE) wag1.toc sed 's/VERSION/$(VERSION)/' wag1.tex - latex wag1 - dvips -o wag1.ps wag1 - sed "s/LONGDATE/$(LONGDATE)/" wag2.ps - tbl *.1 *.3 *.5 | $(TROFF) $(TMAN) >wag3.ps + sed 's/LONGDATE/$(LONGDATE)/' >wag1.tex + latex wag1 # front matter + dvips $(D2PARGS) -o wag1.ps wag1 + cat wag[1234].ps | grep -v '^%%' >wag0.ps # concatenate sections + +wag1.toc: wag2.ps + $(MAKE) getpagenos maketoclines + ./maketoc-tex.sh >wag1.toc # TOC and appendices + +wag2.ps: + tbl *.1 *.3 *.5 | $(TROFF) $(TMAN) >wag2.ps # man pages + +install.tex: wag1.toc +wag3.ps: install.tex sed "s/LONGDATE/$(LONGDATE)/" wag3.tex + latex wag3 + dvips $(D2PARGS) -o wag3.ps wag3.dvi + +eval.tex: wag1.toc +wag4.ps: eval.tex + sed "s/LONGDATE/$(LONGDATE)/" wag4.tex latex wag4 dvips $(D2PARGS) -o wag4.ps wag4.dvi - sed "s/LONGDATE/$(LONGDATE)/" wag5.tex - latex wag5 - dvips $(D2PARGS) -o wag5.ps wag5.dvi - cat wag[123].ps blankpage wag4.ps blankpage wag5.ps | grep -v '^%%' >wag0.ps # 'make clean': remove intermediate and backup files clean: rm -f *.aux *.dvi *.log *.ps *.toc intro.htm faq.htm wag.pdf wagcover \ - wag[145].tex *~ + eval.tex install.tex wag[1234].tex *~ diff -Naur wfdb-10.2.9/doc/wag-src/Makefile.tpl wfdb-10.3.0/doc/wag-src/Makefile.tpl --- wfdb-10.2.9/doc/wag-src/Makefile.tpl Thu Aug 8 10:35:39 2002 +++ wfdb-10.3.0/doc/wag-src/Makefile.tpl Thu Nov 7 21:30:11 2002 @@ -1,5 +1,5 @@ -# file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 8 August 2002 +# file: Makefile.tpl G. Moody 24 May 2000 +# Last revised: 7 November 2002 # Change the settings below as appropriate for your setup. # D2PARGS is a list of options for dvips. Uncomment one of these to set the @@ -61,12 +61,6 @@ # of each page. TMAN = -rC1 -rD1 -man -# TMS is the TROFF option needed to load the 'ms' macro package. Use the -# following definition to get the standard 'ms' macros. -# TMS = -ms -# Use the following definition to get the GNU groff version of the 'ms' macros. -TMS = -mgs - # WAGPSREQ is the target that must be made in order to make the PostScript # version of the manual (wag.ps), and MAKEWAGPS is the command that must be # run in order to do this. The process is a bit convoluted, because the @@ -123,16 +117,20 @@ wag.html: cp -p ../misc/icons/* fixag.sh fixag.sed ../wag ./manhtml.sh ../wag *.1 *.3 *.5 *.7 + cp -p install0.tex install.tex + cp -p eval0.tex eval.tex latex2html -dir ../wag -local_icons -prefix in \ -up_url="wag.htm" -up_title="WFDB Applications Guide" install latex2html -dir ../wag -local_icons -prefix ev \ -up_url="wag.htm" -up_title="WFDB Applications Guide" eval + rm -f install.tex eval.tex cd ../wag; rm -f index.html WARNINGS *.aux *.log *.tex sed "s/LONGDATE/$(LONGDATE)/" ../wag/intro.htm sed "s/LONGDATE/$(LONGDATE)/" ../wag/faq.htm cd ../wag; ./fixag.sh "$(LONGDATE)" *.html; rm -f fixag.sh images.* cd ../wag; rm -f .I* .ORIG_MAP *.html *.pl fixag.sed - sed "s/LONGDATE/$(LONGDATE)/" ../wag/wag.htm cd ../wag; ln -s wag.htm index.html @@ -164,27 +162,37 @@ wag.ps: $(WAGPSREQ) $(MAKEWAGPS) -wag0.ps: wag.tex appguide.int install.tex eval.tex +wag0.ps: wag.tex + $(MAKE) wag2.ps + $(MAKE) wag1.toc sed 's/VERSION/$(VERSION)/' wag1.tex - latex wag1 - dvips -o wag1.ps wag1 - sed "s/LONGDATE/$(LONGDATE)/" wag2.ps - tbl *.1 *.3 *.5 | $(TROFF) $(TMAN) >wag3.ps + sed 's/LONGDATE/$(LONGDATE)/' >wag1.tex + latex wag1 # front matter + dvips $(D2PARGS) -o wag1.ps wag1 + cat wag[1234].ps | grep -v '^%%' >wag0.ps # concatenate sections + +wag1.toc: wag2.ps + $(MAKE) getpagenos maketoclines + ./maketoc-tex.sh >wag1.toc # TOC and appendices + +wag2.ps: + tbl *.1 *.3 *.5 | $(TROFF) $(TMAN) >wag2.ps # man pages + +install.tex: wag1.toc +wag3.ps: install.tex sed "s/LONGDATE/$(LONGDATE)/" wag3.tex + latex wag3 + dvips $(D2PARGS) -o wag3.ps wag3.dvi + +eval.tex: wag1.toc +wag4.ps: eval.tex + sed "s/LONGDATE/$(LONGDATE)/" wag4.tex latex wag4 dvips $(D2PARGS) -o wag4.ps wag4.dvi - sed "s/LONGDATE/$(LONGDATE)/" wag5.tex - latex wag5 - dvips $(D2PARGS) -o wag5.ps wag5.dvi - cat wag[123].ps blankpage wag4.ps blankpage wag5.ps | grep -v '^%%' >wag0.ps # 'make clean': remove intermediate and backup files clean: rm -f *.aux *.dvi *.log *.ps *.toc intro.htm faq.htm wag.pdf wagcover \ - wag[145].tex *~ + eval.tex install.tex wag[1234].tex *~ diff -Naur wfdb-10.2.9/doc/wag-src/README wfdb-10.3.0/doc/wag-src/README --- wfdb-10.2.9/doc/wag-src/README Thu Dec 20 15:07:58 2001 +++ wfdb-10.3.0/doc/wag-src/README Thu Nov 7 21:30:15 2002 @@ -1,5 +1,5 @@ file: README G. Moody 7 September 1989 - Last revised: 20 December 2001 + Last revised: 29 October 2002 This directory contains UNIX man pages in troff source format for the WFDB software and other sources for the WFDB Applications Guide. Under Unix, Linux, @@ -26,31 +26,35 @@ The following files will be found in this directory: -.latex2html-init Customized startup file for converting the appendices of the - Applications Guide into HTML using latex2html -Makefile UNIX `make' description file for printing the WFDB software +.latex2html-init Customized startup file for converting the appendices into + HTML using latex2html +Makefile `make' description file for printing the WFDB software documentation and installing it on-line Makefile.top Used by ../../configure to construct Makefile (comments only) Makefile.tpl Used by ../../configure to construct Makefile (portable section) README this file -appguide.int troff contents and introduction for the WFDB Applications Guide -eval.tex LaTeX source for "Evaluating ECG Analyzers" (an appendix in - the WFDB Applications Guide) +eval0.tex LaTeX source for "Evaluating ECG Analyzers" (appendix 2) +faq.ht0 HTML-format FAQ fixag.sed sed commands for fixing HTML links (used by fixag.sh) -fixag.sh Script for postprocessing WFDB Applications Guide HTML files -install.tex LaTex source for "Installing the WFDB Software Package" (an - appendix in the WFDB Applications Guide) +fixag.sh Script for postprocessing HTML files +getpagenos.c utility for extracting page numbers (used by maketoc-tex.sh) +install0.tex LaTex source for "Installing the WFDB Software Package" + (appendix 1) intro.ht0 HTML-format introduction for the WFDB Applications Guide +maketoc-html.sh script for creating the HTML-form table of contents +maketoc-tex.sh script for creating the LaTeX-format table of contents +maketoclines.c utility for reformatting man page name lines to TOC entries + (used by maketoc-tex.sh) manhtml.sh Script for converting man pages to HTML using `rman' maninst.sh Script for installing man pages (to be invoked by `make' using `Makefile') tmac.dif notes on troff macros for printing the Applications Guide wag.cover troff source for the cover of the WFDB Applications Guide -wag.ht0 HTML-format table of contents for the WFDB Applications Guide -wag.tex LaTeX source for the title page of the WFDB Applications Guide - +wag.ht0 header for the HTML-format table of contents +wag.ht1 trailer for the HTML-format table of contents +wag.tex LaTeX source for the front matter (title, contents, intro, FAQ) *.1 troff sources for man pages for the programs in app, convert, psd, wave, and wview (*) *.3 troff sources for man pages for the WFDB library functions diff -Naur wfdb-10.2.9/doc/wag-src/ann2rr.1 wfdb-10.3.0/doc/wag-src/ann2rr.1 --- wfdb-10.2.9/doc/wag-src/ann2rr.1 Sun Jul 28 10:46:11 2002 +++ wfdb-10.3.0/doc/wag-src/ann2rr.1 Fri Nov 1 11:08:41 2002 @@ -1,4 +1,4 @@ -.TH ANN2RR 1 "28 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH ANN2RR 1 "1 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME ann2rr, rr2ann \- convert annotation files to interval lists and vice versa .SH SYNOPSIS @@ -51,6 +51,10 @@ a time; if none is chosen, only the RR intervals are printed, in units of sample intervals. When using \fB-vs\fR, \fB-vm\fR, \fB-vh\fR, \fB-Vs\fR, \fB-Vm\fR, or \fB-Vh\fR, intervals are printed in units of seconds. +.TP +\fB-w\fR +Print the type (\fBN\fR, \fBV\fR, etc., as for \fB-p\fR above) of the +annotation that ends each interval, at the end of each line of output. .PP The \fB-c\fR option, used without the \fB-p\fR option, causes \fBann2rr\fR to filter out intervals between beats that have intervening non-beat annotations, @@ -66,15 +70,15 @@ .PP Use \fBrr2ann\fR to create an annotation file from the standard input, which should usually be a list of intervals in the format produced by -\fBann2rr\fR. (For exceptions, see \fB-T\fR and \fB-x\fR below.) -Only the first token on each line is taken as an interval; anything -else on the same line is ignored, as are empty lines, spaces and tabs +\fBann2rr\fR. (For exceptions, see \fB-T\fR, \fB-w\fR, and \fB-x\fR below.) +The first token on each line is taken as an interval, and (if the \fB-w\fR +option is present) the second token is taken as an annotation mnemonic; +anything else on the same line is ignored, as are empty lines, spaces and tabs at the beginning of a line, non-numeric tokens and anything following them on the same line, negative intervals, and zero intervals. The -output consists of a binary annotation file -(\fIrecord\fR.\fIannotator\fR), and (if it does not exist already) a -text header file (\fIrecord\fR.hea). Options for \fBrr2ann\fR -include: +output consists of a binary annotation file (\fIrecord\fR.\fIannotator\fR), +and (if it does not exist already) a text header file (\fIrecord\fR.hea). +Options for \fBrr2ann\fR include: .TP \fB-F\fR \fIfrequency\fR Assume the specified sampling \fIfrequency\fR. This option has no effect unless @@ -87,13 +91,18 @@ \fB-T\fR Interpret the input as times of occurrence, rather than as intervals. .TP +\fB-w\fR +Set each annotation type from the mnemonic (\fBN\fR, \fBV\fR, etc.) in the +second column of the input (in the format produced by \fBann2rr\fR using +its \fB-w\fR option). +.TP \fB-x\fR \fIn\fR Multiply input by \fIn\fR to obtain intervals (or, if \fB-T\fR is also used, times of occurrence) in units of sample intervals). Default: \fIn\fR = 1. .PP -Note that \fBwrann\fR(1) also provides a way to generate an annotation file from -text. Unlike that of \fBrr2ann\fR, \fBwrann\fR's input format permits specifying -annotation types and other fields in addition to the times of occurrence. +Note that \fBwrann\fR(1) also provides a way to generate an annotation file +from text. Unlike that of \fBrr2ann\fR, \fBwrann\fR's input format permits +specifying annotation subtypes and other fields. .SH ENVIRONMENT .PP It may be necessary to set and export the shell variable \fBWFDB\fR (see diff -Naur wfdb-10.2.9/doc/wag-src/appguide.int wfdb-10.3.0/doc/wag-src/appguide.int --- wfdb-10.2.9/doc/wag-src/appguide.int Thu Aug 8 14:10:24 2002 +++ wfdb-10.3.0/doc/wag-src/appguide.int Wed Dec 31 19:00:00 1969 @@ -1,414 +0,0 @@ -\" file: appguide.int G. Moody July 1989 -\" Last revised: 8 August 2002 -\" Table of contents and introduction to the WFDB Applications Guide. -\" -\" To print this document using GNU groff, use: -\" tbl appguide.int | groff -mgs -\" To print this using standard UNIX troff and Adobe TranScript software, use: -\" tbl appguide.int | ptroff -ms -\" -\" Note that the table of contents must be updated manually if material is -\" added to or removed from the Guide. The page numbers were checked against -\" groff output of the remainder of the Guide; if you format your Guide using -\" another version of troff, your page numbers may differ. -\" -\" See the Makefile in this directory for details. -\" -.af PN i -.EH '''' -.EF '''' -.bp 2 -.OH 'Contents'WFDB Applications Guide'Contents' -.OF 'WFDB VERSION'LONGDATE'\\\\n(PN' -.bp 3 -.EH 'Contents'WFDB Applications Guide'Contents' -.EF '\\\\n(PN'LONGDATE'WFDB VERSION' -.ce 999 -.ps 16 -\fBTable of Contents\fP -.ce 0 -.ps 10 -.vs 12 -.TS -center; -l l r. - -\fBIntroduction\fR v -\fBFrequently Asked Questions\fR vii - -\fBSection 1: Applications\fR -a2m, ad2m, ahaconvert, converting between MIT and AHA DB formats 1 - m2a, md2a -ann2rr, rr2ann convert annotation files to interval lists and vice versa 4 -bxb ANSI/AAMI-standard beat-by-beat annotation comparator 6 -calsig calibrate signals of a DB record 8 -coherence estimate coherence and cross-spectrum of two time series 10 -dfa detrended fluctuation analysis 11 -ecgeval generate and run ECG analyzer evaluation script 13 -edf2mit converting from EDF to MIT format 14 -epic ANSI/AAMI-standard episode-by-episode annotation comparator 15 -fft fast Fourier transform 17 -fir general-purpose FIR filter for WFDB records 19 -hrfft, hrlomb, hrmem, calculate and plot heart rate power spectra 21 - hrplot -ihr calculate instantaneous heart rate 23 -log10 calculate common logarithms of two-column data 25 -lomb estimate power spectrum using the Lomb periodogram method 26 -memse estimate power spectrum using maximum entropy (all poles) 27 - method -mfilt general-purpose median filter for WFDB records 29 -mrgann merge annotation files 30 -mxm ANSI/AAMI-standard measurement-by-measurement comparator 32 -nst noise stress test for ECG analysis programs 34 -plot2d, plot3d make 2-D or 3-D plots from text files of data, using \fBgnuplot\fR 37 -plotstm produce scatter plot of ST measurement errors on a PostScript 39 - device -plt make 2-D plots 40 -pschart produce annotated `chart recordings' on a PostScript device 46 -psfd produce annotated `full-disclosure' plots on a PostScript device 50 -rdann read a WFDB annotation file 54 -rdsamp read WFDB signal files 56 -rxr ANSI/AAMI-standard run-by-run annotation comparator 57 -sampfreq show sampling frequency for a record 59 -sample digitize and replay analog signals (MS-DOS only) 60 -setwfdb, cshsetwfdb set WFDB environment variables 64 -sigamp measure signal amplitudes of a WFDB record 66 -skewedit edit skew fields of header file(s) 67 -snip copy an excerpt of a WFDB record 68 -sortann rearrange annotations in canonical order 69 -sqrs, sqrs125 single-channel QRS detector 71 -sumann summarize the contents of a WFDB annotation file 73 -sumstats derive aggregate statistics from bxb, rxr, etc., line-format output 74 -tach heart rate tachometer 75 -view, vsetup WFDB browser for MS-DOS 77 -wave, gtkwave waveform analyzer, viewer, and editor 80 -wfdbcat copy WFDB records to standard output 90 -wfdbcollate collate WFDB records into a multi-segment record 91 -wfdb-config print WFDB library version and configuration info 93 -wfdbdesc read signal specifications 94 -wfdbwhich find a WFDB file and print its pathname 95 -wrann write a WFDB annotation file 96 -wrsamp write WFDB signal files 97 -wview WFDB browser for MS Windows 99 -xform sampling frequency, amplitude, and format conversion 103 - for WFDB records - -\fBSection 3: WFDB libraries\fP -wfdb Waveform Database library 105 -wfdbf Waveform Database library wrappers for Fortran 108 - -\fBSection 5: WFDB file formats\fP -annot WFDB annotation file formats 111 -header WFDB header file format 113 -signal WFDB signal file formats 120 -wfdbcal WFDB calibration file format 122 - - -\fBAppendices\fP - \fIInstalling the WFDB Software Package\fP 125 - \fIEvaluating ECG Analyzers\fP 129 -.TE - -.LP -.OH 'Introduction'WFDB Applications Guide'Introduction' -.EH 'Introduction'WFDB Applications Guide'Introduction' - -.bp -.ce 1 -\fBINTRODUCTION\fP -.PP -Most of this guide consists of UNIX \fBman\fP pages that describe the -applications included in the WFDB (Waveform Database) Software -Package (and related software from PhysioToolkit). This introduction -contains important information about how to interpret the material in -the main sections of the guide, and about common conventions for using -all of the WFDB applications that are not described in the main sections. -The FAQ that follows this introduction contains additional information -that will be particularly helpful if you are using MS-Windows (but it -may be of interest even if you are not). - -.ce 1 -\fBUsing this Guide\fP - -.PP -The organization follows the traditional arrangement of the UNIX Reference -Manual: section 1 contains programs, section 3 contains libraries, and -section 5 contains file formats. In the UNIX Reference Manual, sections -2 and 4 are reserved for system calls and device interfaces respectively; -these sections do not exist in this guide. Following convention, a -citation such as \fBrdann\fR(1) refers to the page titled \fBrdann\fR in -section 1 of this guide. -.PP -A \fBman\fR "page" may span more than one physical page, although most -do not. Each \fBman\fR page in section 1 of this guide documents one or -more applications, as indicated in the \fBNAME\fR section at the top. -The \fBSYNOPSIS\fR appears next; it illustrates the form of the -command line needed to run the application. In the synopsis, \fBboldface\fR -indicates text to be typed as is, and \fIitalics\fR indicate replaceable -arguments; brackets ([], which are \fInot\fR to be typed) surround -arguments that may be omitted, and ellipses (...) follow arguments that -can be repeated. The \fBDESCRIPTION\fR sections are intentionally terse; -this is a reference manual and not a tutorial introduction to the software -described within. In those cases for which relevant tutorial material -exists elsewhere, references appear in the \fBSEE ALSO\fP sections of each -\fBman\fP page. A unique feature of this guide is the \fBSOURCE\fR section -at the end of each page, which provides a URL where you may find the current -version of the source(s) for each application. -.PP -On each page, the footer indicates the date when that page was last revised, -and (in most cases) the version of the WFDB Software Package that was current -at that time. An old date and version number do not mean that the page is -out-of-date; rather they mean that the material described on that page -remains current. -.PP -Under GNU/Linux or Unix, if the WFDB Software Package has been installed -on your system, you can also access the information contained in the -main sections of this guide using \fBman\fR and related programs. For -example, to see the manual page for \fBrdsamp\fR, run the command -.br - \fBman rdsamp\fR -.br -(This also works under MS-Windows if you have installed the -Cygwin package, which includes the \fBman\fR utility for formatting -and reading manual pages.) In some cases you may need to add -\fB/usr/local/man\fR to your \fBMANPATH\fR environment variable, in -order to make these pages accessible to \fBman\fR. -.PP -An HTML version of this guide is also available; point your Web browser to -\fBhttp://www.physionet.org/physiotools/wag/\fR to read it. - -.ce 1 -\fBUsing WFDB Applications\fP - -.PP -If you have not used any of these programs before, you may need to set up -your environment properly so that WFDB applications can find their -input files. See \fBsetwfdb\fR(1) in this guide for information about -doing this; a more detailed discussion may be found in the first chapter -of the \fIWFDB Programmer's Guide\fP, in the section about the database path. -.PP -Certain types of command-line arguments are used by many of the applications -described in this guide. These include: -.IP \fIrecord\fP -Where this appears, substitute the name of a WFDB record. \fBA record -name is \fInot\fB a file name!\fR The first part of the name of a .hea -file is the name of the record to which the .hea file belongs; so the -record name corresponding to `100.hea' is `100'. For example, MIT-BIH -Arrhythmia Database record names are 3-digit numbers, AHA Database -record names are 4-digit numbers, and European ST-T Database record -names begin with lowercase `e', followed by a 4-digit number. Record -names may contain letters, digits, and underscores. Case is significant in -record names that contain letters, even in environments such as -MS-Windows for which case translation is normally performed by the -operating system on file names; thus `e0104' is the name of a record -found in the European ST-T Database, whereas `E0104' is not. Once -again: a record name is \fBnot\fP a file name; record names never -include an extension (.hea, .dat, etc.). -.IP -Wherever a record name can be supplied to a WFDB application, you may include -path information if necessary. For example, if the WFDB path includes the -current directory, and if the current directory includes a subdirectory named -`my_records', and that directory contains a record named `record_23', you -can supply `my_records/record_23' as a \fIrecord\fR argument. See the \fIWFDB -Programmer's Guide\fP for further details on record names. -.IP -Each PhysioBank database directory includes a text file named \fBRECORDS\fR, -which lists the record names for all records in that directory. - -.IP \fIannotator\fP -Where this appears, substitute an annotator name. \fBAnnotator names -are \fInot\fB file names!\fR The suffix (extension) of the name of an -annotation file is the annotator name for that file; so, for example, -the annotator name for `e0104.atr' is `atr'. The special annotator -name `atr' is used to name the set of \fIreference annotations\fP -supplied by the database developers. Other annotation sets have -annotator names that may contain letters, digits, and underscores, as -for record names. -.IP -Each PhysioBank database directory includes a text file named \fBANNOTATORS\fR, -which lists the annotator names for all annotation files in that directory. - -.IP \fItime\fP -Where this appears, substitute a string in \fIstandard time format\fP. -\fITime\fP arguments generally specify elapsed times from the beginning -of the record (for exceptions to this rule, see the section on the -\fBstrtim\fR function in the \fIWFDB Programmer's Guide\fP). Examples -of standard time format: -.TS -center; -l l. -2:14.875 2 minutes + 14.875 seconds -143 143 seconds (2 minutes + 23 seconds) -4:02:01 4 hours + 2 minutes + 1 second -4:2:1 same as above -s12345 12345 sample intervals -e time of the end of the record -.TE - -.IP \fIsignal\fP -Where this appears, substitute a signal number. Signal numbers are integers; -the first signal in each record is signal 0. In printed documentation for -the databases, signals always appear with signal 0 at the top, signal 1 -beneath, etc. - -.IP \fIsignal-list\fP -Where this (or `\fIsignal ...\fP') appears, you may specify more than one -signal in any desired order; separate the signal numbers using spaces. -Unless otherwise noted, a signal may appear more than once, or not at all, -in a signal list. In most cases, the end of the signal list is unambiguous -(since signal numbers are never negative, an option argument beginning -with '-' is a reliable indicator). In unusual cases, you may need to arrange -options so that the signal list is at the end of the command, or so that it -is followed by an argument that cannot be interpreted as a signal number. - -.OH 'FAQ'WFDB Applications Guide'FAQ' -.EH 'FAQ'WFDB Applications Guide'FAQ' -.bp -.ce 2 -\fBFREQUENTLY ASKED QUESTIONS\fP -.br -\fB(and Frequently Exclaimed Exclamations)\fP - -.LP -\fBI double-clicked on the program icon, and nothing happens!\fR -.br -\fBI typed the program name in the 'Run...' dialog, and nothing happens!\fR -.PP -Don't do this! -.PP -With few exceptions, PhysioToolkit applications run in \fBtext mode\fR -(i.e., they do not include a graphical user interface). -These programs are intended to be run within a terminal emulator -using a command-line interface. In most cases, if you attempt to run them by -clicking on their icons or names, or by entering the program name in the -MS-Windows \fBRun...\fR dialog box, these programs will open a DOS box, print a -usage summary, and exit, usually much too fast for you to read anything. -.PP -By far the best way to use these programs under MS-Windows is to install a -Unix-compatible terminal emulator and shell in which to run them. The best of -these is also free; if you have not already done so, download and install the -Cygwin software package from \fBhttp://www.cygwin.com/\fP. This package -includes \fBbash\fR, the GNU Bourne Again Shell and a terminal emulator in -which to run it. After a standard installation of Cygwin, you can launch a -terminal emulator and \fBbash\fR by clicking on the Cygwin icon that will have -been installed on your desktop. -.PP -If you do not wish to use Cygwin, it is possible to run these applications -within a DOS box, but there are many limitations of \fBcommand.com\fR that may -prove frustrating. In particular, \fBcommand.com\fR supports a relatively -small space for environment variables that is not secure against buffer -overruns, and has idiosyncratic filename globbing behavior. - -.LP -\fBWhat does the message "init: can't open header for ..." mean?\fR - -.PP -This message can be produced by any application linked to the WFDB -library, including \fBrdsamp\fR(1) and \fBrdann\fR(1). In order to -read data files, these applications need to find a header (\fB.hea\fR) -file for the input record you specify. The message indicates that the header -file was not found in any of the expected places, or that it was -unreadable. There are three common reasons why this can happen: - -.IP 1. -The \fIrecord\fR name supplied to the application is not correct. Record -names are \fBnot\fR file names (if this doesn't sound familiar yet, go back -and read the introduction again). If you wish to read, for example, a signal -file named \fBslp60.dat\fR using \fBrdsamp\fR, you must specify the name of -the record to which this file belongs (\fBslp60\fR) after the \fB-r\fR option, -and not the name of the file itself. Whatever follows "init: can't open header -for ..." is what the application thinks is the name of the record you wish to -read. Also, be aware that case matters in record names, even under operating -systems that ignore case in file names. Thus "\fBSLP60\fR" is not a valid -record name; "\fBslp60\fR" is. - -.IP 2. -The header file is missing. If you download signal (\fB.dat\fR) or -annotation (\fB.atr\fR, \fB.qrs\fR, etc.) files, be sure to download -the corresponding \fB.hea\fR files from the same locations. - -.IP 3. -The list of locations to be searched does not include the location of -the header file. WFDB applications find their input files by searching -a list of locations specified by the WFDB path (the environment variable -\fBWFDB\fR, or a default list of locations if WFDB has not been set). The -WFDB path normally includes the current directory, but this may not be -true if the WFDB path has been modified; the current directory must -appear explicitly (either as a "." or as an empty component in the path) -in order to be included in the list of locations to be searched. For -further information, see "The Database Path and Other Environment Variables" -in the \fIWFDB Programmer's Guide\fR. - -.bp -.LP -\fBHow can I save the output of ... in a file?\fR -.br -\fBHow can one program read another's output?\fR - -.PP -If you are running programs from a command prompt (by typing commands into a -terminal emulator window or an MS-DOS box), these things can be done easily. - -.PP -If you have ever used GNU/Linux, Unix, or MS-DOS, you may have captured the -output of a program by \fIredirecting\fR it to a file, like this: -.br - \fBfoo >bar\fR -.br -The > operator redirects \fBfoo\fR's standard output (which would normally -appear on-screen) into a file named \fBbar\fR. If \fBbar\fR exists already, its -contents are replaced. If you wish to append \fBfoo\fR's output to whatever is -already contained in \fBbar\fR, use a command such as this instead: -.br - \fBfoo >>bar\fR -.br -There is an analogous operator that arranges for a program's standard input -(which would normally be read from whatever you type on the keyboard) to be -read from a file instead: -.br - \fBbaz , >>, <, and |) are supported by all shells (command -interpreters) under Unix, GNU/Linux, and MS-DOS (including those that run -within MS-DOS boxes or other types of terminal emulators under MS-Windows). For -further information, please refer to the documentation for your shell or -command interpreter. - -.PP -\fBWhere else can I find answers to my questions about this software?\fR - -.PP -If you haven't read the introduction to this guide yet, do so now. It answers -many frequently asked questions by describing the common behavior of many of -the WFDB applications. It also describes the typographic and organizational -conventions used in the remainder of this guide. - -.PP -Many more questions are asked and answered in the PhysioNet FAQ -(http://www.physionet.org/faq.shtml). diff -Naur wfdb-10.2.9/doc/wag-src/bxb.1 wfdb-10.3.0/doc/wag-src/bxb.1 --- wfdb-10.2.9/doc/wag-src/bxb.1 Wed Jul 31 22:11:36 2002 +++ wfdb-10.3.0/doc/wag-src/bxb.1 Sun Nov 24 15:24:37 2002 @@ -1,4 +1,4 @@ -.TH BXB 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH BXB 1 "24 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME bxb \- ANSI/AAMI-standard beat-by-beat annotation comparator .SH SYNOPSIS @@ -147,7 +147,8 @@ These options are provided for the use of developers, who may find them useful for obtaining a more detailed understanding of algorithm errors. .SH SEE ALSO -\fBecgeval\fR(1), \fBepic\fR(1), \fBmxm\fR(1), \fBrxr\fR(1), \fBsetwfdb\fR(1), \fBsumstats\fR(1) +\fBecgeval\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), \fBrxr\fR(1), +\fBsetwfdb\fR(1), \fBsumstats\fR(1) .br \fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) .br diff -Naur wfdb-10.2.9/doc/wag-src/dfa.1 wfdb-10.3.0/doc/wag-src/dfa.1 --- wfdb-10.2.9/doc/wag-src/dfa.1 Wed Jul 31 22:15:53 2002 +++ wfdb-10.3.0/doc/wag-src/dfa.1 Mon Oct 28 17:28:19 2002 @@ -1,6 +1,6 @@ .TH DFA 1 "31 July 2002" "DFA 4.2" "WFDB Applications Guide" .SH NAME -dfa \- Detrended fluctuation analysis +dfa \- detrended fluctuation analysis .SH SYNOPSIS \fBdfa\fR [ \fIoption\fR ... ] .SH DESCRIPTION diff -Naur wfdb-10.2.9/doc/wag-src/ecgeval.1 wfdb-10.3.0/doc/wag-src/ecgeval.1 --- wfdb-10.2.9/doc/wag-src/ecgeval.1 Sun Jul 28 10:47:12 2002 +++ wfdb-10.3.0/doc/wag-src/ecgeval.1 Fri Nov 22 14:54:19 2002 @@ -1,5 +1,5 @@ '\" t -.TH ECGEVAL 1 "28 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH ECGEVAL 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME ecgeval \- generate and run ECG analyzer evaluation script .SH SYNOPSIS @@ -10,7 +10,7 @@ a batch file under MS-DOS, to compare a set of test annotation files with a set of reference annotation files and a set of reference heart rate measurement files using the programs \fBbxb\fR(1), \fBrxr\fR(1), \fBmxm\fR(1), -and \fBepic\fR(1), and then to produce summary reports by passing the outputs +and \fBepicmp\fR(1), and then to produce summary reports by passing the outputs of these programs to \fBsumstats\fR(1) and \fBplotstm\fR(1). .PP \fBecgeval\fR asks interactively for the annotator names, the name of @@ -45,7 +45,7 @@ CU DB culist Creighton University Sustained Ventricular Arrhythmia Database .TE .SH SEE ALSO -\fBbxb\fR(1), \fBepic\fR(1), \fBmxm\fR(1), \fBplotstm\fR(1), \fBrxr\fR(1), +\fBbxb\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), \fBplotstm\fR(1), \fBrxr\fR(1), \fBsetwfdb\fR(1), \fBsumstats\fR(1) .br \fIEvaluating ECG Analyzers\fR diff -Naur wfdb-10.2.9/doc/wag-src/ecgpuwave.1 wfdb-10.3.0/doc/wag-src/ecgpuwave.1 --- wfdb-10.2.9/doc/wag-src/ecgpuwave.1 Thu Oct 31 11:35:06 2002 +++ wfdb-10.3.0/doc/wag-src/ecgpuwave.1 Fri Nov 22 15:08:36 2002 @@ -1,4 +1,4 @@ -.TH ECGPUWAVE 1 "31 October 2002" "ecgpuwave 1.0" "WFDB Applications Guide" +.TH ECGPUWAVE 1 "22 November 2002" "ecgpuwave 1.0" "WFDB Applications Guide" .SH NAME ecgpuwave \- QRS detector and waveform limit locator .SH SYNOPSIS @@ -58,7 +58,7 @@ It may be necessary to set and export the shell variable \fBWFDB\fR (see \fBsetwfdb\fR(1)). .SH SEE ALSO -\fBrdann\fR(1), \fBsqrs\fR(1), \fBwave\fR(1) +\fBrdann\fR(1), \fBsqrs\fR(1), \fBwave\fR(1), \fBwqrs\fR(1) .SH REFERENCES .br 1. Pan J and Tompkins WJ. A Real-Time QRS Detection Algorithm. \fIIEEE diff -Naur wfdb-10.2.9/doc/wag-src/edf2mit.1 wfdb-10.3.0/doc/wag-src/edf2mit.1 --- wfdb-10.2.9/doc/wag-src/edf2mit.1 Wed Jul 31 22:02:56 2002 +++ wfdb-10.3.0/doc/wag-src/edf2mit.1 Sat Nov 2 11:13:25 2002 @@ -1,15 +1,19 @@ -.TH EDF2MIT 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH EDF2MIT 1 "2 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME -edf2mit \- converting from EDF to MIT format +edf2mit, mit2edf \- convert between EDF and MIT formats .SH SYNOPSIS \fBedf2mit -i\fR \fIedffile\fR [ \fIoptions\fR ... ] +.br +\fBmit2edf -r\fR \fIrecord\fR [ \fIoptions\fR ... ] .SH DESCRIPTION .PP -This program reads the specified \fIedffile\fR, an EDF (European Data Format) -file, and creates MIT-format signal and header files containing the same data. -European Data Format was originally designed for storage of polysomnograms. +These programs convert EDF (European Data Format) files into +MIT-format files (as used in PhysioBank) and vice versa. European +Data Format was originally designed for storage of polysomnograms. .PP -Options include: +\fBedf2mit\fR reads the specified \fIedffile\fR and creates MIT-format +signal and header files containing the same data. Options for +\fBedf2mit\fR include: .TP \fB-b\fR Input is in big-endian byte order (default: little-endian). @@ -29,14 +33,37 @@ .TP \fB-v\fR Verbose mode (print debugging output). +.PP +\fBmit2edf\fR reads the specified MIT-format \fIrecord\fR (header and signal +files) and creates an EDF file containing the same data. Output from +\fBmit2edf\fR is always in the standard little-endian format. Options for +\fBmit2edf\fR include: +.TP +\fB-h\fR +Print a brief usage summary. +.TP +\fB-o\fR \fIfile\fR +Write output to the specified \fIfile\fR (default: \fIrecord\fR\fB.edf\fR). +.TP +\fB-v\fR +Verbose mode (print debugging output). + +.PP +Note that EDF format does not include a way to specify the baseline value +of a signal, and that MIT format does not include a standard way to specify the +transducer type or the prefiltering specification; these parameters are +not preserved by these conversion programs. Also note that use of the standard +signal and unit names specified for EDF is permitted but not enforced by +\fBmit2edf\fR. + .SH ENVIRONMENT .PP It may be necessary to set and export the shell variable \fBWFDB\fR (see \fBsetwfdb\fR(1)). .SH AVAILABILITY -This program is provided in the \fIconvert\fR directory of the WFDB Software -Package. Run \fBmake\fR in that directory to compile and install it if it -has not been installed already. +These programs are provided in the \fIconvert\fR directory of the WFDB Software +Package. Run \fBmake\fR in that directory to compile and install them if they +have not been installed already. .SH SEE ALSO \fBa2m\fR(1), \fBsnip\fR(1), \fBxform\fR(1), \fBwfdb\fR(3), \fBheader\fR(5) .HP @@ -44,7 +71,7 @@ A simple format for exchange of digitized polygraphic recordings. \fIElectroencephalography and Clinical Neurophysiology\fB 82\fR:391-393 (1992). .HP -Bob Kemp's EDF web site (http://www.hsr.nl/bobkemp/edf/edf.htm). +Bob Kemp's EDF web site (http://www.hsr.nl/edf/). The definitive reference on the format; it includes the full specification of EDF from the 1992 paper, sample EDF files, software for reading and viewing them, FAQs, and much more. @@ -52,3 +79,5 @@ George B. Moody (george@mit.edu) .SH SOURCES http://www.physionet.org/physiotools/wfdb/convert/edf2mit.c +.br +http://www.physionet.org/physiotools/wfdb/convert/mit2edf.c diff -Naur wfdb-10.2.9/doc/wag-src/epic.1 wfdb-10.3.0/doc/wag-src/epic.1 --- wfdb-10.2.9/doc/wag-src/epic.1 Sun Jul 28 10:48:15 2002 +++ wfdb-10.3.0/doc/wag-src/epic.1 Wed Dec 31 19:00:00 1969 @@ -1,165 +0,0 @@ -.TH EPIC 1 "28 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" -.SH NAME -epic \- ANSI/AAMI-standard episode-by-episode annotation comparator -.SH SYNOPSIS -\fBepic -r\fR \fIrecord\fR \fB-a\fR \fIreference-annotator test-annotator\fR [ \fIoptions ... \fR ] -.SH DESCRIPTION -.PP -This program implements the VF, AF, and ST episode-by-episode -comparison algorithms specified by the current American National -Standard for ambulatory ECG analyzers (ANSI/AAMI EC38:1998). \fBepic\fR -is the reference implementation of these algorithms, and must be used -to obtain the episode-by-episode performance statistics cited in EC38 -in order to be in compliance with the standard (see EC38, section 5.2.14). -.PP -Input to this program consists of two annotation files associated with the same -\fIrecord\fR. One of these is designated the \fIreference\fR annotation file, -the other the \fItest\fR annotation file. -.PP -\fIOptions\fR include: -.TP -\fB-A\fR \fIfile\fR -Append atrial fibrillation detection reports to the specified \fIfile\fR. -.TP -\fB-f\fR \fItime\fR -Begin the comparison at the specified \fItime\fR (default: 5 minutes after the -beginning of the record). -.TP -\fB-h\fR -Print a usage summary. -.TP -\fB-i\fR \fItime\fR -Ignore episodes shorter than \fItime\fR (default: 0 seconds). -.TP -\fB-l\fR -Write reports in line format (default: matrix format). -.TP -\fB-L\fR -Same as \fB-l\fR. -.TP -\fB-S\fR \fIfile1 file2\fR -Append ischemic ST episode detection reports to \fIfile1\fR, and ST deviation -measurements to \fIfile2\fR. -.TP -\fB-S0\fR \fIfile1 file2\fR -As for \fB-S\fR, but report on signal 0 only. -.TP -\fB-S1\fR \fIfile1 file2\fR -As for \fB-S\fR, but report on signal 1 only. -.TP -\fB-t\fR \fItime\fR -Stop the comparison at the specified \fItime\fR (default: the end of the record -if it is defined, the end of the reference annotation file otherwise; if -\fItime\fR is 0, the comparison ends when the end of either annotation file is -reached). -.TP -\fB-V\fR -Append ventricular flutter and fibrillation detection reports to the specified -\fIfile\fR. -.PP -The episode and duration statistics gathered by \fBepic\fR are based on tallies -of overlapping episodes in the reference and test annotation files. -Duration statistics give weight to each episode or detection in -proportion to its duration. -Episode statistics give equal weight to each episode or detection, -irrespective of length; each test-annotated episode that meets the criteria -for overlap (see below) with a reference-annotated episode is counted as -a true positive. Episodes are defined as follows (see -\fI\fR for definitions of annotation types): -.TP -\fIAtrial fibrillation episodes\fR -begin with a \fBRHYTHM\fR annotation, with the \fIaux\fR field containing -the text `\fB(AFIB\fR', and end with any other \fBRHYTHM\fR annotation -(or at the end of the record). Reference-marked episodes of atrial flutter -(begun by \fBRHYTHM\fR annotations with the text `\fB(AFL\fR') are excluded -from AF comparisons (i.e., the test annotator is neither penalized nor rewarded -for its treatment of atrial flutter in this context). Any amount of overlap -is sufficient to qualify a test episode as a true positive. -.TP -\fIVentricular fibrillation or flutter episodes\fR -begin with a \fBVFON\fR annotation, and end with a \fBVFOFF\fR annotation -(or at the end of the record). \fBRHYTHM\fR annotations are ignored in this -context by \fBepic\fR. Any amount of overlap is sufficient to qualify a test -episode as a true positive. -.TP -\fIIschemic ST episodes\fR -begin with a \fBSTCH\fR annotation, with the \fIaux\fR field containing the -text `\fB(ST\fIns\fR', and end with another \fBSTCH\fR annotation, with the -text `\fBST\fIns\fB)\fR' (or at the end of the record). Between these -annotations, the extremum (the time at which the absolute value of the ST -deviation is greatest) is marked with another \fBSTCH\fR annotation, with -the text `\fBAST\fInsm\fR'; this annotation may be omitted in the test -annotation file. In these annotations, \fIn\fR is `\fB0\fR' or -`\fB1\fR', and denotes the affected signal; \fIs\fR is `\fB+\fR' for episodes -of ST elevation, or `\fB-\fR' for episodes of ST depression; and \fIm\fR is -the ST deviation in microvolts, relative to a reference level established from -the first 30 seconds of the record. The values of \fIs\fR and \fIm\fR are not -significant for the episode comparison made by \fIepic\fR. When using the -\fB-S0\fR or \fB-S1\fR options, \fIn\fR must be 0 or 1 respectively; other -\fBSTCH\fR annotations are ignored. When using the \fB-S\fR option, the value -of \fIn\fR is ignored: each `\fB(ST\fIns\fR' annotation increments a counter, -and each `\fBST\fIns\fB)\fR' annotation decrements the counter; in this -context, ST episodes begin when the counter becomes positive and end when the -counter reaches zero (or at the end of the record). To qualify a test episode -as a true positive for purposes of determining ST episode sensitivity, it must -overlap at least 50% of the reference episode, or the overlap must include the -reference-marked extremum. To qualify a test episode as a true positive for -purposes of determining ST episode positive predictivity, the reference episode -must overlap at least 50% of the test episode, or the overlap must include the -test-marked extremum, if present. -.PP -The second file generated when using the `\fB-S\fR', `\fB-S0\fR', or -`\fB-S1\fR' options contains comparisons of ST deviation measurements wherever -such measurements are available in the reference annotation files. In the -existing databases, these appear only at extrema within each annotated -ischemic (or non-ischemic) ST episode, as described above. -For purposes of comparison of ST deviation measurements, test ST measurements -for each signal are read from the \fIaux\fR field of beat annotations, which -should contain text of the format `\fIm n\fR' (where \fIm\fR and \fIn\fR -are the measured ST deviations for signals 0 and 1 respectively). If these -measurements are missing from any test beat annotation, \fBepic\fR assumes that -they have not changed since they last appeared. \fBepic\fR ignores -`\fBAST\fR...' annotations in the test annotation file when making this -comparison. In the output file, any test measurements that deviate from the -reference measurements by more than 100 microvolts are tagged with an asterisk -(`\fB*\fR'). \fBplotstm\fR(1) can produce a scatter plot of these data using -this file as input. -.PP -At least one of the options `\fB-A\fR', `\fB-S\fR', `\fB-S0\fR', `\fB-S1\fR', -and `\fB-V\fR' must be used. If `\fB-\fR' is given as a \fIfile\fR argument, -reports are written on the standard output. The output generated by selecting -\fB-l\fR or \fB-L\fR includes column headings only if a \fIfile\fR other than -`\fB-\fR' is specified, and only if the specified \fIfile\fR does not already -exist. In this way, \fBepic\fR can be used repeatedly to build up line-format -tables for multiple records, for further processing by \fBsumstats\fR(1). -.SH ENVIRONMENT -.PP -It may be necessary to set and export the shell variable \fBWFDB\fR (see -\fBsetwfdb\fR(1)). -.SH DIAGNOSTICS -.TP -\fInon-standard comparison selected\fR -The \fB-f\fR, \fB-i\fR, and \fB-t\fR options modify the comparison algorithms -used by \fBepic\fR in ways not permitted by EC38. These options are provided -for the use of developers, who may find them useful for obtaining a more -detailed understanding of algorithm errors. -.SH BUGS -.PP -Since \fBepic\fR performs multiple passes over its input files, it cannot be -used at the end of a pipe. -.PP -It's not really an epic, it's just long. By analogy to \fBbxb\fR and -\fBrxr\fR, this program should have been called \fBexe\fR, which would have -created interesting possibilities for confusion. -.SH SEE ALSO -bxb(1), ecgeval(1), mxm(1), plotstm(1), rxr(1), setwfdb(1), sumstats(1) -.br -\fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) -.br -\fIAmerican National Standard ANSI/AAMI EC38:1998, Ambulatory -Electrocardiographs\fR; available from AAMI, 1110 N Glebe Road, -Suite 220, Arlington, VA 22201 USA (http://www.aami.org/). -.SH AUTHOR -George B. Moody (george@mit.edu) -.SH SOURCE -http://www.physionet.org/physiotools/wfdb/app/epic.c diff -Naur wfdb-10.2.9/doc/wag-src/epicmp.1 wfdb-10.3.0/doc/wag-src/epicmp.1 --- wfdb-10.2.9/doc/wag-src/epicmp.1 Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/epicmp.1 Fri Nov 22 14:48:18 2002 @@ -0,0 +1,167 @@ +.TH EPICMP 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" +.SH NAME +epicmp \- ANSI/AAMI-standard episode-by-episode annotation comparator +.SH SYNOPSIS +\fBepicmp -r\fR \fIrecord\fR \fB-a\fR \fIreference-annotator test-annotator\fR [ \fIoptions ... \fR ] +.SH DESCRIPTION +.PP +This program implements the VF, AF, and ST episode-by-episode +comparison algorithms specified by the current American National +Standard for ambulatory ECG analyzers (ANSI/AAMI EC38:1998). \fBepicmp\fR +is the reference implementation of these algorithms, and must be used +to obtain the episode-by-episode performance statistics cited in EC38 +in order to be in compliance with the standard (see EC38, section 5.2.14). +.PP +Input to this program consists of two annotation files associated with the same +\fIrecord\fR. One of these is designated the \fIreference\fR annotation file, +the other the \fItest\fR annotation file. +.PP +\fIOptions\fR include: +.TP +\fB-A\fR \fIfile\fR +Append atrial fibrillation detection reports to the specified \fIfile\fR. +.TP +\fB-f\fR \fItime\fR +Begin the comparison at the specified \fItime\fR (default: 5 minutes after the +beginning of the record). +.TP +\fB-h\fR +Print a usage summary. +.TP +\fB-i\fR \fItime\fR +Ignore episodes shorter than \fItime\fR (default: 0 seconds). +.TP +\fB-l\fR +Write reports in line format (default: matrix format). +.TP +\fB-L\fR +Same as \fB-l\fR. +.TP +\fB-S\fR \fIfile1 file2\fR +Append ischemic ST episode detection reports to \fIfile1\fR, and ST deviation +measurements to \fIfile2\fR. +.TP +\fB-S0\fR \fIfile1 file2\fR +As for \fB-S\fR, but report on signal 0 only. +.TP +\fB-S1\fR \fIfile1 file2\fR +As for \fB-S\fR, but report on signal 1 only. +.TP +\fB-t\fR \fItime\fR +Stop the comparison at the specified \fItime\fR (default: the end of the record +if it is defined, the end of the reference annotation file otherwise; if +\fItime\fR is 0, the comparison ends when the end of either annotation file is +reached). +.TP +\fB-V\fR +Append ventricular flutter and fibrillation detection reports to the specified +\fIfile\fR. +.PP +The episode and duration statistics gathered by \fBepicmp\fR are based on tallies +of overlapping episodes in the reference and test annotation files. +Duration statistics give weight to each episode or detection in +proportion to its duration. +Episode statistics give equal weight to each episode or detection, +irrespective of length; each test-annotated episode that meets the criteria +for overlap (see below) with a reference-annotated episode is counted as +a true positive. Episodes are defined as follows (see +\fI\fR for definitions of annotation types): +.TP +\fIAtrial fibrillation episodes\fR +begin with a \fBRHYTHM\fR annotation, with the \fIaux\fR field containing +the text `\fB(AFIB\fR', and end with any other \fBRHYTHM\fR annotation +(or at the end of the record). Reference-marked episodes of atrial flutter +(begun by \fBRHYTHM\fR annotations with the text `\fB(AFL\fR') are excluded +from AF comparisons (i.e., the test annotator is neither penalized nor rewarded +for its treatment of atrial flutter in this context). Any amount of overlap +is sufficient to qualify a test episode as a true positive. +.TP +\fIVentricular fibrillation or flutter episodes\fR +begin with a \fBVFON\fR annotation, and end with a \fBVFOFF\fR annotation +(or at the end of the record). \fBRHYTHM\fR annotations are ignored in this +context by \fBepicmp\fR. Any amount of overlap is sufficient to qualify a test +episode as a true positive. +.TP +\fIIschemic ST episodes\fR +begin with a \fBSTCH\fR annotation, with the \fIaux\fR field containing the +text `\fB(ST\fIns\fR', and end with another \fBSTCH\fR annotation, with the +text `\fBST\fIns\fB)\fR' (or at the end of the record). Between these +annotations, the extremum (the time at which the absolute value of the ST +deviation is greatest) is marked with another \fBSTCH\fR annotation, with +the text `\fBAST\fInsm\fR'; this annotation may be omitted in the test +annotation file. In these annotations, \fIn\fR is `\fB0\fR' or +`\fB1\fR', and denotes the affected signal; \fIs\fR is `\fB+\fR' for episodes +of ST elevation, or `\fB-\fR' for episodes of ST depression; and \fIm\fR is +the ST deviation in microvolts, relative to a reference level established from +the first 30 seconds of the record. The values of \fIs\fR and \fIm\fR are not +significant for the episode comparison made by \fIepicmp\fR. When using the +\fB-S0\fR or \fB-S1\fR options, \fIn\fR must be 0 or 1 respectively; other +\fBSTCH\fR annotations are ignored. When using the \fB-S\fR option, the value +of \fIn\fR is ignored: each `\fB(ST\fIns\fR' annotation increments a counter, +and each `\fBST\fIns\fB)\fR' annotation decrements the counter; in this +context, ST episodes begin when the counter becomes positive and end when the +counter reaches zero (or at the end of the record). To qualify a test episode +as a true positive for purposes of determining ST episode sensitivity, it must +overlap at least 50% of the reference episode, or the overlap must include the +reference-marked extremum. To qualify a test episode as a true positive for +purposes of determining ST episode positive predictivity, the reference episode +must overlap at least 50% of the test episode, or the overlap must include the +test-marked extremum, if present. +.PP +The second file generated when using the `\fB-S\fR', `\fB-S0\fR', or +`\fB-S1\fR' options contains comparisons of ST deviation measurements wherever +such measurements are available in the reference annotation files. In the +existing databases, these appear only at extrema within each annotated +ischemic (or non-ischemic) ST episode, as described above. +For purposes of comparison of ST deviation measurements, test ST measurements +for each signal are read from the \fIaux\fR field of beat annotations, which +should contain text of the format `\fIm n\fR' (where \fIm\fR and \fIn\fR +are the measured ST deviations for signals 0 and 1 respectively). If these +measurements are missing from any test beat annotation, \fBepicmp\fR assumes that +they have not changed since they last appeared. \fBepicmp\fR ignores +`\fBAST\fR...' annotations in the test annotation file when making this +comparison. In the output file, any test measurements that deviate from the +reference measurements by more than 100 microvolts are tagged with an asterisk +(`\fB*\fR'). \fBplotstm\fR(1) can produce a scatter plot of these data using +this file as input. +.PP +At least one of the options `\fB-A\fR', `\fB-S\fR', `\fB-S0\fR', `\fB-S1\fR', +and `\fB-V\fR' must be used. If `\fB-\fR' is given as a \fIfile\fR argument, +reports are written on the standard output. The output generated by selecting +\fB-l\fR or \fB-L\fR includes column headings only if a \fIfile\fR other than +`\fB-\fR' is specified, and only if the specified \fIfile\fR does not already +exist. In this way, \fBepicmp\fR can be used repeatedly to build up line-format +tables for multiple records, for further processing by \fBsumstats\fR(1). +.SH ENVIRONMENT +.PP +It may be necessary to set and export the shell variable \fBWFDB\fR (see +\fBsetwfdb\fR(1)). +.SH DIAGNOSTICS +.TP +\fInon-standard comparison selected\fR +The \fB-f\fR, \fB-i\fR, and \fB-t\fR options modify the comparison algorithms +used by \fBepicmp\fR in ways not permitted by EC38. These options are provided +for the use of developers, who may find them useful for obtaining a more +detailed understanding of algorithm errors. +.SH BUGS +.PP +Since \fBepicmp\fR performs multiple passes over its input files, it cannot be +used at the end of a pipe. +.PP +Between 1992 and 2002, this program was known as \fBepic\fR; the name +was changed to avoid conflict with a new but widely distributed IRC +chat client also named \fBepic\fR. By analogy to \fBbxb\fR and +\fBrxr\fR, this program should have been called \fBexe\fR, which would +have created interesting possibilities for confusion. +.SH SEE ALSO +bxb(1), ecgeval(1), mxm(1), plotstm(1), rxr(1), setwfdb(1), sumstats(1) +.br +\fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) +.br +\fIAmerican National Standard ANSI/AAMI EC38:1998, Ambulatory +Electrocardiographs\fR; available from AAMI, 1110 N Glebe Road, +Suite 220, Arlington, VA 22201 USA (http://www.aami.org/). +.SH AUTHOR +George B. Moody (george@mit.edu) +.SH SOURCE +http://www.physionet.org/physiotools/wfdb/app/epicmp.c diff -Naur wfdb-10.2.9/doc/wag-src/eval.tex wfdb-10.3.0/doc/wag-src/eval.tex --- wfdb-10.2.9/doc/wag-src/eval.tex Sat Aug 3 22:22:48 2002 +++ wfdb-10.3.0/doc/wag-src/eval.tex Wed Dec 31 19:00:00 1969 @@ -1,760 +0,0 @@ -\documentclass[twoside]{article} -\usepackage{rawfonts} -\IfFileExists{times.sty}{\usepackage{times}}{\@missingfileerror{times}{sty}} - -\usepackage{fancyheadings} -\oddsidemargin 0.1in -\evensidemargin -0.1in -\topmargin -0.5in -\textheight 650pt -\footskip 48pt -\def\textwidth{6.375 in} -\pagestyle{fancy} -\def\headrulewidth{0pt} -\lhead{\rm{}Evaluating ECG Analyzers} -\chead{\rm{}WFDB Applications Guide} -\rhead{\rm{}Evaluating ECG Analyzers} -\lfoot[\rm\thepage]{\rm{}WFDB VERSION} -\cfoot{\rm{}LONGDATE} -\rfoot[\rm{}WFDB VERSION]{\rm\thepage} - -\title{Evaluating ECG Analyzers} -\author{George B. Moody\\ -Harvard-MIT Division of Health Sciences and Technology, Cambridge, MA, USA} -\date{} - -\begin{document} -\setcounter{page}{129} - -\maketitle - -\section*{Summary} -This paper describes how to evaluate an automated ECG analyzer using -available annotated ECG databases and software, in compliance with -standard evaluation protocols. These protocols have been adopted as -parts of the {\em American National Standard for Ambulatory -Electrocardiographs} (ANSI/AAMI EC38:1998, and its predecessor, -ANSI/AAMI EC38:1994), and the {\em American National Standard for -Testing and Reporting Performance Results of Cardiac Rhythm and ST -Segment Measurement Algorithms} (ANSI/AAMI EC57:1998). They include -earlier evaluation protocols developed for an AAMI Recommended -Practice, {\em Testing and Reporting Performance Results of -Ventricular Arrhythmia Detection Algorithms} (AAMI ECAR, 1987). It -will be most useful to readers who plan to use the suite of evaluation -software included in the WFDB Software Package ({\tt -http://www.\-physio\-net.\-org/\-physio\-tools/\-wfdb.\-shtml}); this -suite of software includes the reference implementations of the -evaluation protocols specified in EC38 and EC57. - -\section{Introduction} -Continuous monitoring of the electrocardiogram in both inpatients and -ambulatory subjects has become a very common procedure during the past -thirty years, with diverse applications ranging from screening for cardiac -arrhythmias or transient ischemia, to evaluation of the efficacy of -antiarrhythmic drug therapy, to surgical and critical care monitoring. -Since the first intensive care units were established in the 1960s, -the need for automated data reduction and analysis of the ECG has been -apparent, motivated by the very large amount of data that must be -analyzed (on the order of $10^{5}$ cardiac cycles per patient per -day). As clinical experience has led to the identification of more -and more prognostic indicators in the ECG, clinicians have demanded -and received increasingly sophisticated automated ECG analyzers. The -early heart rate monitors rapidly evolved into devices that were -designed first to detect ventricular fibrillation, then other -``premonitory'' ventricular arrhythmias. Many newer devices attempt -to detect supraventricular arrhythmias and transient ischemic ST -changes. - -Visual analysis of the ECG is far from simple. Accurate diagnosis of -ECG abnormalities requires attention to subtle features of the -signals, features that may appear only rarely, and which are often -obscured by or mimicked by noise. Diagnostic criteria are complicated -by inter- and intra-patient variability of both normal and abnormal -ECG features. Given these considerations, it is not surprising that -developers are faced with a difficult task in the design of algorithms -for automated ECG analysis, and that the results of their efforts are -imperfect. Certain parts of the problem --- QRS detection in the -absence of noise, for example --- are well-solved by most current -algorithms; others --- detection of supraventricular arrhythmias, for -example --- remain exceedingly difficult. Just as we may find it easiest -to analyze ``textbook'' examples, automated ECG analyzers may perform -better while analyzing the recordings used during their development -than when applied to ``real-world'' signals. - -Since automated ECG analyzers vary in performance, and since their -performance is dependent on the characteristics of their input, -quantitative evaluations of these devices are essential in order to -assess the usefulness of their outputs. At one extreme, a device's -outputs in the context of a particular type of signal may be so -unreliable as to be worthless; unfortunately, the other extreme --- -an output so reliable it can be accepted uncritically --- is not a -characteristic of any existing monitor, nor can it be expected in -the future. - -\subsection{ECG Databases} -Several databases of ECG recordings are generally available -for evaluating ECG analyzers. They serve several important needs: -\begin{itemize} - \item They contain {\em representative} signals. Wide variations in -ECG characteristics among subjects severely limit the value of -synthesized waveforms for testing purposes. Realistic tests of ECG -analyzers require large sets of ``real-world'' signals. - - \item They contain {\em rarely observed but clinically significant} -signals. Although it is not particularly difficult to obtain -recordings of common ECG abnormalities, often those that are most -significant are rarely recorded. Both developers and evaluators of -ECG analyzers need examples of such recordings. - - \item They contain {\em standard} signals. System comparisons -are meaningless unless performance is measured using the same test -data in each case, since performance is so strongly data-dependent. - - \item They contain {\em annotated} signals. Typically, each QRS -complex has been manually annotated by two or more cardiologists -working independently. The {\em reference} annotations produced -as a result serve as a ``gold standard'' against which a device's -analysis can be compared quantitatively. - - \item They contain {\em digitized, computer-readable} signals. It is -therefore possible to perform a fully automated, strictly reproducible -test in the digital domain if desired, allowing one to establish with -certainty the effects of algorithm modifications on performance. -\end{itemize} - -Standards EC38 and EC57 require the use of the following ECG -databases:\footnote{Sources: ECRI, 5200 Butler Pike, Plymouth Meeting, -PA 19462 USA (AHA DB); MIT-BIH Database Distribution, MIT Room -E25-505A, 77 Massachusetts Avenue, Cambridge, MA 02139 USA (MIT, NST, -and CU databases); CNR Institute of Clinical Physiology, Computer -Laboratory, via Trieste, 41, 56100 Pisa, Italy (ESC DB). Except for -the AHA DB, all are available in whole or in part from PhysioNet -({\tt http://www.\-physio\-net.\-org/}).} -\begin{itemize} - \item {\bf AHA DB}: The American Heart Association Database for -Evaluation of Ventricular Arrhythmia Detectors (80 records, 35 minutes -each) - - \item {\bf MIT DB}: The Massachusetts Institute of Technology--Beth -Israel Hospital Arrhythmia Database (48 records, 30 minutes each) - - \item {\bf ESC DB}: The European Society of Cardiology ST-T -Database (90 records, two hours each) - - \item {\bf NST DB}: The Noise Stress Test Database (12 records, 30 -minutes each) - - \item {\bf CU DB}: The Creighton University Sustained Ventricular -Arrhythmia Database (35 records, 8 minutes each) - -\end{itemize} -Each of these databases represents a very substantial effort by many -workers; in particular, the AHA, MIT, and ESC databases each required -more than five years of sustained effort by large teams of researchers -and clinicians from many institutions. Nevertheless, it should be -recognized that even these databases do not fully represent the -variety of ``real-world'' ECGs observed in clinical practice. -Although these databases permit standardized, quantitative, automated, -and fully reproducible evaluations of analyzer performance, it is -risky to extrapolate from the results of such evaluations to -expectations of real-world performance. Such extrapolations can be -particularly error-prone if the evaluation data were also used for -development of the analysis algorithm, since the algorithm may have -been (perhaps unintentionally) ``tuned'' to its training set. It -should also be noted that the first four of the databases listed above were -obtained from Holter ECG recordings; although the frequency response -of the Holter recording technique is not usually a limiting factor in -the performance of an ECG analyzer, it may tend to favor devices that -are designed to analyze Holter recordings over devices that have been -designed to analyze higher-fidelity input signals. - -\subsection{Evaluation Protocols} -Between 1984 and 1987, the Association for the Advancement of Medical -Instrumentation (AAMI) sponsored the development of a protocol for the -use of the first two of these databases, which was published as an -AAMI Recommended Practice.\footnote{{\it Testing and Reporting -Performance Results of Ventricular Arrhythmia Detection -Algorithms}. Publication AAMI ECAR (1987); succeeded by ANSI/AAMI -EC57:1998, available from AAMI, 1110 N Glebe Road, Suite 220, -Arlington, VA 22201 USA.} Between 1990 and 1998, the ambulatory ECG -subcommittee of the AAMI ECG committee developed and revised a -standard for ambulatory ECG monitors, significant portions of which -address the issue of the accuracy of automated analysis performed by -some of these devices.\footnote{{\it American National Standard for -Ambulatory Electrocardiographs}. Publication ANSI/AAMI EC38:1998; -available from AAMI (address above).} The ambulatory ECG standard -EC38:1998, and the ``testing and reporting performance results'' -standard EC57:1998, build on the evaluation protocol adopted for the -earlier Recommended Practice (ECAR), incorporating provisions for the -use of all five of the databases listed above, with extensions for -assessing detection of supraventricular arrhythmias and transient -ischemic ST changes. The standard breaks new ground in establishing -specific reporting requirements for the performance of automated ECG -analyzers on standard tests using the databases listed above. - -A significant constraint imposed on evaluators by the EC38 standard -is that they must obtain annotation files containing the analysis -results of the device under test. Although the device itself need not -produce these files, EC38 specifically requires that they be produced -by an automated procedure, which must be fully disclosed. The intent -of this requirement is to permit reproducible independent evaluations -in which neither the proprietary data of the developers (the analysis -algorithms) nor that of the evaluators (the test signals and reference -annotations) need necessarily to be disclosed. By defining the -interface between the developer and the evaluator to be the annotation -file, the responsibilities of each party are clearly defined: the -developer must make certain that the device's outputs are recorded in -the annotation file in the manner intended by the developer, but in -the language of the standard; the evaluator must make certain -that the algorithms used to compare the device's annotation files with -the reference annotation files conform to the specification of the -standard. The format and content of these annotation files is -specified in detail below. For many existing devices, it may be -difficult or impossible to obtain such annotation files without the -cooperation of the developers. Newly-designed devices should -incorporate the necessary ``hooks'' for producing annotation files. - -\subsection{Software to Support Evaluations} -This paper describes a suite of programs that support evaluations of -automated ECG analyzers in accordance with the methods described in -the EC38 and EC57 standards (as well as those in the earlier ECAR -Recommended Practice). These methods are sufficiently complex that -the development of such a suite of programs is not an afternoon's -work. By making generally available reference implementations of the -evaluation algorithms, much needless duplication of effort may be -avoided. By circulating them in source form to other users, we may -hope to find and correct any bugs, with the eventual result that -evaluators of devices should not have to bear the burden of evaluating -the evaluation technique itself. By using them for evaluations, any -ambiguities in the English specification of the evaluation algorithms -are resolved in a consistent manner for each device tested. These -programs are written in C and run under MS-DOS or UNIX. They have -been made available as part of the WFDB Software Package. In this -paper, the names of these programs are printed {\tt like this}. - -\section{Evaluating an ECG Analyzer} -The major task facing an evaluator is that of presenting the reference signals -to the device under test, and collecting annotation files from the device. The -details of this task will vary for each device, but a few general hints are -given below. A second task, that of obtaining reference heart rate -measurements, should be a much simpler job. Once all of this information has -been gathered, the remaining work required --- that of comparing the device's -analysis against the ``gold standard'' --- can be performed automatically. - -\subsection{Presenting Signals to the Analyzer} -Two distinctly different types of tests are possible. If the device can accept -digital inputs, the reference signals can be supplied in that form (perhaps -after resampling with {\tt xform} to convert the digitized samples to the -expected sampling frequency and numerical range, and possibly with additional -digital signal processing to simulate the signal conditioning normally -performed by the device's front-end data acquisition hardware). The primary -advantage of testing in the digital domain is that the test is (or should be) -strictly reproducible, since no noise or additional quantization error can be -introduced in this way. This method usually avoids the issue of -synchronization of the test annotations with the reference signals discussed -below. - -Testing in the analog domain requires that analog signals be recreated from -the digital signals. (It should be noted that even the analog versions of the -MIT and AHA databases that have been available in the past were recreated -from the digitized signals by the database developers.) The advantage of this -approach is that it exercises the entire system, including the front-end data -acquisition hardware. It is often difficult, however, to establish -synchronization between the signal source and the analyzer, needed in order to -permit comparisons of annotations. One way of dealing with this problem is to -arrange for the analyzer's sampling clock to trigger the digital-to-analog -converter used to recreate the analog signals, or to arrange for an external -clock to trigger both D/A conversion in the playback system and A/D conversion -in the analyzer. Another method is to begin and end the signal generation -process by delivering signals from the analyzer to the playback device, and -recording the analyzer's clock time at the times of the signals; assuming that -both the analyzer and the playback device have stable clocks, event times in -the analyzer's frame of reference can be converted to database sample numbers -by linear interpolation. The WFDB software package includes a program ({\tt -sample}) that uses a Microstar DAP 2400-series analog interface -board\footnote{ -Source: Microstar Laboratories, {\tt http://www.mstarlabs.com/}. External -analog anti-aliasing filters (to reduce ``staircasing'') and attenuators (to -obtain patient-level signals) may also be required, depending on the system to -be evaluated. DAP boards can also be used with {\tt sample} to create new -database records.} -and an MS-DOS PC to recreate analog signals from digital database records on -CD-ROMs or magnetic disk files. - -\subsection{Obtaining Test Annotation Files} -For any ambulatory ECG monitor that incorporates automated analysis functions, -the EC-38 standard requires the manufacturer to implement and disclose a -method for producing test annotation files. Independent evaluators should seek -assistance from the manufacturer in any case, since the manufacturer's -interpretation of the device's outputs in the language of EC-38 is definitive -(in effect, the annotation file generation technique becomes part of -the system under test). Note that generation of annotation files need not be -synchronous with data acquisition; a device might conceivably store all of the -necessary data until the end of the test, and only then write the file. -Neither does the standard require that an annotation be determined within any -fixed amount of time, as would be expected of devices designed to trigger -pacing, for example. Furthermore, EC-38 specifically allows for the -possibility that the device under test might not produce the annotation file -directly. If any external hardware or software is required to do so, however, -it must be made generally available or specified in sufficient detail by the -manufacturer to permit an independent evaluator to obtain test annotation -files. - -Annotation files contain a label (an annotation) for each beat and for certain -other features of the signals, such as rhythm and ST changes. Annotations are -stored in time order in annotation files. The ``time'' of an annotation is -that of the sample in the signal file with which the annotation is -associated.\footnote{Times in annotation and signal files are usually expressed -as {\em sample numbers} (the number of samples in the signal file that precede -the sample in question).} The WFDB library (included in the WFDB software package) -includes C-callable functions ({\tt getann} and {\tt putann}) for reading and -writing annotations. In a C program, annotations appear as data structures -containing a 32-bit {\tt time} field together with a pair of 8-bit fields that -encode the annotation type and sub-type ({\tt anntyp} and {\tt subtyp} [sic], -respectively), and a variable-length {\tt aux} field usually used to store -text. In annotation files, these annotation structures are usually stored in -a variable-length bit-packed format averaging slightly more than 16 bits per -annotation.\footnote{Test annotations that include heart rate or ST -measurements require substantially more storage. {\tt getann} and -{\tt putann} can also use the original AHA DB format (containing fixed-length -annotations, 16 bytes each), but this format should not be used for -evaluations of devices that incorporate ST analysis functions, since the -space available for the {\tt aux} data is too small to store ST measurements.} - -Test annotation files may include the following: -\begin{itemize} - \item {\em Beat annotations}. These need not coincide precisely with the -reference beat annotations, since the evaluation protocol allows a time -difference of up to 150 ms between each pair of matching beat annotations. -All beat annotations are mapped during the evaluation process into the set -\{ N, V, F, S, Q \} (corresponding to normal, ventricular ectopic, ventricular -fusion, supraventricular ectopic, and unclassifiable or paced beats -respectively); devices need not be capable of producing all of these -annotations, but any beat annotations that they do produce will be translated -into one of these types. The standard specifies the mapping used for the -{\tt anntyp} values defined in {\tt }. (This file is -included in the WFDB Software Package.) Any beat annotations that -appear in the first five minutes of a record (the ``learning period'') are -ignored in the evaluation process. The remainder of the record (the ``test -period'') must be fully annotated. Note in particular that the last beat of -some records may be very close to the last sample; since the analyzer may -reach the end of the input signals before producing an annotation for the last -beat, it may be necessary to ``pad'' the input data for a few seconds at the -end of the record to permit the analyzer to emit its final beat annotation. - - \item {\em Shutdown annotations}. If the device suspends its analysis -because of poor signal quality or for any other reason, it should mark the -periods during which analysis is suspended. The evaluation software tallies -beats missed during such periods separately from beats missed at other times. -The beginning of each period of shutdown may be marked using a {\tt NOISE} -annotation with ${\tt subtyp} = -1$, and the end of each period of shutdown -may be marked using a {\tt NOISE} annotation with ${\tt subtyp} = 0$ (see -the source for {\tt bxb} for notes on other acceptable methods of marking -shutdown). - - \item {\em Ventricular fibrillation annotations}. The beginning and end -of each detected episode of ventricular fibrillation should be marked using -{\tt VFON} and {\tt VFOFF} annotations. - - \item {\em Other rhythm annotations}. These should include -{\tt RHYTHM} annotations marking the beginning and end of each detected episode -of atrial fibrillation. The beginning of each episode should be marked with an -``{\tt (AFIB}'' rhythm annotation, i.e., an annotation with {\tt anntyp} = {\tt -RHYTHM} and {\tt aux} = \verb|"\05(AFIB"|, where ``\verb|\05|'' is C notation -for a byte with the value 5 (ASCII control-E). Non-empty {\tt aux} fields -always begin with a byte that specifies the number of data bytes that follow; -in this case, the five characters ({\tt ( A F I B}) of the string. The end of -each episode should be marked with any other rhythm annotation (for example, -\verb|"\02(N"|). - - \item {\em Heart rate measurements}. Each type of heart rate measurement -(including any heart rate or RR interval variability measurements) made by the -device under test should be assigned a measurement number, $m$, between 0 and -127. A {\tt MEASURE} annotation should be recorded for each heart rate -measurement, with ${\tt subtyp} = m$ and with the measurement in the {\tt aux} -field, as an ASCII-coded decimal number. - - \item {\em ST deviation measurements}. If available, these should -be provided in the {\tt aux} fields of beat annotations, as -ASCII-coded decimal numbers indicating the deviations in microvolts -from reference levels established for each signal from the first 30 -seconds of each record. For example, ``{\tt 25 -104}'' indicates a 25 -$\mu$V elevation in signal 0 and a 104 $\mu$V depression in signal 1. -If ST measurements are omitted from any beat annotation, the -evaluation software assumes they are unchanged from their previous -values. - - \item {\em Ischemic ST change annotations}. These {\tt STCH} annotations -should mark the beginning and end of each detected episode of ischemic ST -change. ST change annotations have additional information in the {\tt aux} -field as for rhythm annotations: the beginning of each episode is marked by an -``{\tt (ST}{\it ns}'' annotation, and the end of each episode by a -``{\tt ST{\it ns})}'' annotation, where {\it n} indicates the signal affected - (``{\tt 0}'' or ``{\tt 1}''), and {\it s} indicates ST elevation (``{\tt +}'') -or depression (``{\tt -}''). {\it n} may be omitted if the episode detection -criteria depend on features of both signals. The extremum of each episode may -optionally be marked with an ``{\tt AST}{\it nsm}'' annotation, where {\it n} -and {\it s} are defined as above, and {\it m} is the ST deviation in -microvolts, relative to a reference level established as above. - - \item {\em Comment annotations}. Annotations with {\tt anntyp = NOTE} -and any desired string data in {\tt aux} may be included anywhere in -an annotation file. {\tt NOTE} annotations are ignored by the -standard evaluation software; they may be used, for example, to -record the values of internal algorithm variables for debugging purposes. -\end{itemize} -Note that only beat annotations are absolutely required in test annotation -files. ST deviation measurements within beat annotations, and the other -types of annotations listed above, only need to be recorded for devices -that are claimed by their manufacturers to provide optional features for -detection of ventricular or atrial fibrillation, measurement of ST deviations, -or detection of ischemic ST changes. - -If the time units in the test annotation files are not the same as those in -the reference annotation files (for example, because {\tt xform} was used to -change the sampling frequency of the signal files in a digital-domain test), -the time units must be rescaled before proceeding with the comparison. This -may be done by using {\tt xform} to rewrite the test annotation files with -the original sampling frequency.\footnote{ -The obvious alternative, using {\tt xform} to rewrite the reference annotation -files at the time the signal files are resampled, should not be used in a -formal evaluation. Because of the possibility that resampling the reference -annotation files might result in moving reference annotations into or out of -the test period, or changing the lengths of episodes, doing so might produce -results that could not be directly compared with those obtained in a standard -evaluation.} - -Details of the ST deviation measurement and episode detection criteria used in -producing the reference annotation files for the ESC database may be found in -several sources.\footnote{ See, for example, the {\it European ST-T Database -Directory}, pp. vi-vii, supplied with the ESC DB; or Taddei, A., et al., ``The -European ST-T database: development, distribution, and use'', {\it Computers -in Cardiology} {\bf 17}:177-180 (1990).} Note, however, that many techniques -for measuring ST deviation and for detecting transient ischemic ST changes are -possible, and that to date the best evaluation results have been obtained for -analyzers using criteria that do not attempt to mimic those used by the human -experts who annotated the database. - -\subsection{Obtaining Reference Heart Rate Data} -The final step of preparation for the evaluation is to process the -reference annotation files to obtain reference heart rate annotation -files. These files must contain heart rate measurement annotations -with the same measurement numbers assigned as for the test heart rate -annotations; they need not necessarily contain beat or other -annotations from the reference annotation files. Quoting from EC38, -\begin{quote} -To evaluate the accuracy of heart rate measurement, the evaluator -shall implement and disclose a method for obtaining heart rate -measurements using the reference annotation files (the `reference -heart rate'). This method need not be identical to the method used by -the device under test, but in general it will be advantageous if it -matches that method as closely as possible. -\end{quote} -It will generally be in the manufacturer's interest to provide a -program for generating reference heart rate annotation files, to avoid -the need for an independent evaluator to do so, with a likely result -of less than optimal agreement with the test heart rate measurements. -The WFDB software package includes a sample implementation of such a -program ({\tt examples/refhr.c}); note that it will need to be -customized for each device to be tested. - -Note that measurement errors are normalized by the mean value of the reference -measurements in each record. Be certain that this mean value cannot be -zero!\footnote{ -For certain types of HRV or RRV measurements (though not for heart rate -measurements), this is a potential problem. One solution is to add a small -positive offset to any measurement with an expected zero mean. It is within -the letter, though not the spirit, of the standard protocol, to add a -very large number in such a case, so as to make the error percentage -arbitrarily small. The mean value of the reference measurements must be -reported; this should serve as a disincentive to this sort of creative abuse -of the standard. An honest approach might be to add an offset on the order of -the expected standard deviation of the individual measurements.} - -\section{Comparing Annotation Files} - -Once the test annotation files and the reference heart rate annotation files -have been obtained, the remainder of the evaluation procedure is -straightforward. All of the information needed to characterize the analysis -performed by the device under test is encoded in the test annotation files; -similarly, all of the information needed to characterize the actual contents -of the test signals is encoded in the reference annotation and reference -heart rate annotation files. The evaluation procedure thus entails comparison -of the test and reference annotation files for each record. - -Four programs are provided in the WFDB Software Package for this purpose: -\begin{itemize} - \item {\tt bxb} compares annotation files beat by beat; its output -includes QRS, VEB, and (optionally) SVEB sensitivity and positive -predictivity, as well as RR interval error and shutdown statistics. - - \item {\tt rxr} compares annotation files run by run; its output -includes ventricular (and, optionally, supraventricular) ectopic couplet, short -run (3--5 beats), and long run (6 or more beats) sensitivity and positive -predictivity. - - \item {\tt epic} compares annotation files episode by episode; its -output includes ventricular fibrillation, atrial fibrillation, and ischemic ST -detection statistics as well as comparisons of ST deviation measurements. - - \item {\tt mxm} compares measurements from a test annotation -file and a reference heart rate annotation file; its output indicates -measurement error.\footnote{ -{\tt mxm} is not restricted to comparison of heart rate measurements; if -other types of measurements are available, they may be compared in the same -manner as heart rates by {\tt mxm}.} -\end{itemize} - -The WFDB Software Package also includes three related programs: -\begin{itemize} - \item {\tt sumstats} reads certain output files generated by {\tt bxb}, -{\tt rxr}, {\tt epic}, and {\tt mxm}, and calculates aggregate statistics for -a set of records. - \item {\tt plotstm} generates scatter plots of ST deviation measurements -collected by {\tt epic}. - \item {\tt ecgeval} automates the entire comparison procedure by running -{\tt bxb}, {\tt rxr}, {\tt epic}, and {\tt mxm} for each record, collecting -their output, then running {\tt sumstats} (and optionally {\tt plotstm}), and -finally printing the results. -\end{itemize} - -To obtain a concise summary of how to use any of these programs, including -a list of any command-line options, simply run the program without any -command-line arguments. Refer to the {\it WFDB Applications Guide}, -which accompanies the WFDB Software Package, for details. - -In most cases, it will be easiest to collect all of the annotation files -before beginning the comparison, and then to perform the comparison by typing: -\begin{verbatim} -ecgeval -\end{verbatim} -The program asks for the test annotator name, the names of the databases -used for testing, and what optional detector outputs should be evaluated. - -Only the statistics required by EC38 and EC57 are reported by {\tt -ecgeval}. If more detailed evaluation data are needed, it will be -necessary to run {\tt bxb}, {\tt rxr}, etc., separately. If file -space is extremely limited, it may be necessary to delete each test -annotation file after it has been compared against the reference file, -before the next test annotation file can be created; in such cases, it -may also be necessary to prompt the user to change media containing -signal or reference annotation files, or to reset the device under -test before beginning each record. Optionally, {\tt ecgeval} can -generate a script (batch) file of commands, which can be edited to -accommodate special requirements such as these. - -For example, suppose we have obtained a set of test annotation files with the -annotator name ``{\tt yow}'', which we wish to compare against the reference -annotation files (annotator name ``{\tt atr}'')\footnote{ -Annotation files for any given record are distinguished by annotator names, -which correspond to the ``extension'' of the file name. The -reference annotation files supplied with the databases have the annotator -name ``{\tt atr}'' (originally ``{\tt atruth}'' because ``{\tt a}'' -was intended to indicate the file type, and ``{\tt truth}'' because \ldots -well, because the annotations are supposed to be The Truth).} -and reference heart rate annotation files (annotator name ``{\tt htr}''). -The portion of the evaluation script generated by {\tt ecgeval} for MIT DB -record 100 is: -\begin{verbatim} -bxb -r 100 -a atr yow -L bxb.out sd.out -rxr -r 100 -a atr yow -L vruns.out sruns.out -mxm -r 100 -a htr yow -L hr0.out -m 0 -epic -r 100 -a atr yow -L -A af.out - -V vf.out -S st.out stm.out -\end{verbatim} -(The last two lines shown above form a single command. The {\tt mxm} command -gathers statistics on measurement number 0; if other heart rate measurements -are defined, {\tt mxm} should be run once for each such measurement, -substituting the appropriate measurement numbers for {\tt 0} in the output -file name, {\tt hr0.out}, and the final argument.) Statistics for the -remainder of the MIT DB are obtained by repeating these commands, substituting -in each the appropriate record names for {\tt 100}. Once these commands have -been run for all of the records, the record-by-record statistics will be found -in nine files ({\tt bxb.out}, {\tt sd.out}, {\tt vruns.out}, {\tt sruns.out}, -{\tt hr0.out}, {\tt af.out}, {\tt vf.out}, {\tt st.out}, and {\tt stm.out}). -The first eight of these files contain one line for each record.\footnote{ -{\tt stm.out} contains one line for each ST deviation measurement that was -compared; in this example, {\tt stm.out} would be empty since the reference -annotation files of the MIT DB do not contain ST deviation measurements.} {\tt -sumstats} can read any of these files, and calculates aggregate performance -statistics; to use it, type ``{\tt sumstats} {\it file}'', where {\it file} is -the name of one of these files. The output of {\tt sumstats} contains a copy -of its input, with aggregate statistics appended to the end. Typically this -output might be saved in a file to be printed later, e.g., -\begin{verbatim} -sumstats bxb.out >>report.out -\end{verbatim} - -A scatter plot of the ST measurement comparisons performed by {\tt epic} can be -produced using {\tt plotstm}, the output of which can be printed directly on -any PostScript printer. For example, to make a plot file for {\tt stm.out}, -type: -\begin{verbatim} -plotstm stm.out >stm.ps -\end{verbatim} - -\section{Studying Discrepancies} - -Having conducted an evaluation as described above, a common question -is ``what were the errors?'' {\tt bxb} and {\tt rxr} can help -answer such questions. - -{\tt bxb} can generate an output annotation file (with annotator name -``{\tt bxb}'') in which all matching beat annotations are copied from -the test annotation file, and each mismatch is indicated by a {\tt -NOTE} annotation, with the {\tt aux} field indicating the element of -the confusion matrix in which the mismatch is tallied (e.g., ``{\tt Vn}'' -represents a beat called a VEB by the reference annotator and a normal -beat by the test annotator). Programs such as {\tt view}, -{\tt wave}, and {\tt wview}\footnote{ -{\tt view} (for MS-DOS), {\tt wave} (for Linux, Solaris, and SunOS) and -{\tt wview} (for MS Windows) are included in the WFDB Software Package.} -can be used to search for and display the waveforms associated with the -mismatches. To generate an output annotation file, add the {\tt -o} option to -the {\tt bxb} command line, as in: -\begin{verbatim} -bxb -r 100 -a atr yow -L bxb.out sd.out -o -\end{verbatim} -A particularly useful way to document an evaluation is to print a -full disclosure report with {\tt bxb} output annotations, using the -program {\tt psfd} (also included in the WFDB Software Package). This may -be accomplished by preparing a file containing a list of the names of -the records to be printed (call it {\tt list}), and then using the -command: -\begin{verbatim} -psfd -a bxb list >output.ps -\end{verbatim} -The file {\tt output.ps} can be printed on any PostScript printer. -Run {\tt psfd} without any arguments for a summary of its (numerous) -options; try a short test before making a large set of printouts, -which can take a long time. - -Both {\tt bxb} and {\tt rxr} accept a {\tt -v} option to run in -``verbose'' mode, in which each discrepancy is reported in the -standard error output. When running {\tt rxr}, this feature is useful -for finding missed and falsely detected ectopic couplets and runs. - -\section{Acknowledgements} - -Having been involved in the production of most of the databases as -well as the design of the evaluation protocols, it has been my -privilege to receive the benefits of the sustained contributions of -many colleagues who have supported these projects with their dedicated -efforts. I would like especially to thank -Paul Albrecht, -Jim Bailey, -Ted Baker, -Rich Bowser, -Don Brodnick, -Jerry Cox, -Phil Devlin, -Charlie Feldman, -Scott Greenwald, -Russ Hermes, -David Israel, -Franc Jager, -Carlo Marchesi, -Roger Mark, -Joe Mietus, -Warren Muldrow, -Diane Perry, -Scott Peterson, -Ken Ripley, -Paul Schluter, -Alessandro Taddei, -Roy Wallen, -and Cees Zeelenberg. - -\appendix -\section{Using the AHA Database} - -Since the AHA DB is not available in the standard PhysioBank format -used by all of the other databases, the WFDB Software Package includes -a pair of programs that convert files read from AHA DB distribution -tapes or floppy disks into files in PhysioBank format. {\tt a2m} -converts AHA annotation files, and {\tt ad2m} converts AHA signal -files and also generates header ({\tt *.hea}) files. (Run these -programs without command-line arguments to obtain instructions on -their use.) Using {\tt a2m} and {\tt ad2m}, all 80 AHA DB records can -be stored in roughly 130 Mb of disk space (assuming use of the -standard 35-minute records). These programs can also reformat old -(pre-1989) MIT DB tapes written in the AHA DB distribution format. - -It is also possible to read and write AHA tape-format files directly using -the WFDB library; refer to the {\it WFDB Programmer's Guide} -for details. - -\section{Noise stress testing} - -With respect to many tasks performed by an ECG analyzer, dealing with -noise is the major problem faced by system designers. Although -measurements such as ST deviation may be obtained reliably in clean -signals, the presence of noise may render them inaccurate. In some -instances, it is sufficient to recognize the presence of noise and either -to mark measurements as unreliable or to avoid making measurements -altogether. In other cases, excluding noisy data is inappropriate -(for example, given the multiple correlations among physical -activity, noise, and transient ischemia, excluding noisy signals is -likely to introduce sampling bias in an ischemia detector). - -It is difficult to measure the effects of noise on an ECG analyzer -using ordinary recordings. Even if existing databases include an -adequate variety of both ECG signals and noise, the sample size is -certainly too small to include all combinations of noise and ECG -signals that may be encountered in clinical use. In ordinary -recordings, it is difficult or impossible to separate the effects of -noise from the intrinsic problems of analyzing clean signals of the -same type. - -The noise stress test circumvents these problems. By adding noise -in calibrated amounts to clean signals, any combination of noise and -signal types is possible. Since both the noise-corrupted signal and -the clean signal can be analyzed (in separate experiments) by the -same analyzer, the effects of noise on the analysis are readily -separable from any other problems that may arise while analyzing the -clean signals. Finally, since the test can be repeated using -different amounts of noise, it is possible to characterize analyzer -performance as a function of signal-to-noise ratio. - -The major criticisms of the noise stress test are that not all noise -is additive, and that the characteristics of the added noise may not -perfectly match those of noise observed in clinical practice. These -points, though formally irrefutable, do not negate the value of the -test. In practice, most of the troublesome noise is additive; thus -(given appropriate inputs) the noise stress test can simulate most of -the noisy signals of interest. The NST DB includes noise recordings -made using standard ambulatory ECG electrodes and recorders, but with -electrodes placed on the limbs of active volunteers in configurations -in which the subject's ECG is not apparent in the recorded signals. -Given the recording technique used, it is not surprising that the -characteristics of the recorded noise closely match those of noise in -standard ambulatory ECG recordings. Although it may be argued that the -particular muscles responsible for the recorded noise might produce -different signals than those that generate the EMG present in noisy -ECGs, no such differences are apparent from comparisons of either the -signals or their power spectra. - -The NST DB includes a small set of ECG records with calibrated amounts -of added noise. EC38 specifies that performance on these records must -be reported, although no specific performance levels are required. -Program {\tt nst} can be used to generate additional records for noise -stress testing. To do so, choose an ECG record and a noise record -(the latter may be {\tt bw}, {\tt em}, or {\tt ma} from the NST DB, or -any other available noise recording). Run {\tt nst} and answer its -questions to generate a noisy ECG record that may then be used in the -same way as any other WFDB record. By default, {\tt nst} adds no noise -during the first five minutes of the record, then adds noise for the -next two minutes, none for the following two minutes, and repeats this -pattern of two minutes of noise followed by two minutes of clean -signals for the remainder of the record. The scale factors for the -noise, if determined by {\tt nst}, are adjusted such that the -signal-to-noise ratios are equal for each signal. The durations of -the noisy periods, and the scale factors for each signal, are recorded -in a {\em protocol annotation file}, which is generated by {\tt nst} -unless an existing protocol annotation file is supplied as input. To -change these parameters, simply edit the protocol annotation file -(using, for example, {\tt rdann} to convert it to text form, any text -editor to make the modifications, and {\tt wrann} to convert it back -to annotation file format), then rerun {\tt nst} using the protocol -file to generate a new record. -\end{document} diff -Naur wfdb-10.2.9/doc/wag-src/eval0.tex wfdb-10.3.0/doc/wag-src/eval0.tex --- wfdb-10.2.9/doc/wag-src/eval0.tex Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/eval0.tex Fri Nov 22 14:56:46 2002 @@ -0,0 +1,760 @@ +\documentclass[twoside]{article} +\usepackage{rawfonts} +\IfFileExists{times.sty}{\usepackage{times}}{\@missingfileerror{times}{sty}} + +\usepackage{fancyheadings} +\oddsidemargin 0.1in +\evensidemargin -0.1in +\topmargin -0.5in +\textheight 650pt +\footskip 48pt +\def\textwidth{6.375 in} +\pagestyle{fancy} +\def\headrulewidth{0pt} +\lhead{\rm{}Evaluating ECG Analyzers} +\chead{\rm{}WFDB Applications Guide} +\rhead{\rm{}Evaluating ECG Analyzers} +\lfoot[\rm\thepage]{\rm{}WFDB VERSION} +\cfoot{\rm{}LONGDATE} +\rfoot[\rm{}WFDB VERSION]{\rm\thepage} + +\title{Evaluating ECG Analyzers} +\author{George B. Moody\\ +Harvard-MIT Division of Health Sciences and Technology, Cambridge, MA, USA} +\date{} + +\begin{document} +\setcounter{page}{FIRSTPAGE} + +\maketitle + +\section*{Summary} +This paper describes how to evaluate an automated ECG analyzer using +available annotated ECG databases and software, in compliance with +standard evaluation protocols. These protocols have been adopted as +parts of the {\em American National Standard for Ambulatory +Electrocardiographs} (ANSI/AAMI EC38:1998, and its predecessor, +ANSI/AAMI EC38:1994), and the {\em American National Standard for +Testing and Reporting Performance Results of Cardiac Rhythm and ST +Segment Measurement Algorithms} (ANSI/AAMI EC57:1998). They include +earlier evaluation protocols developed for an AAMI Recommended +Practice, {\em Testing and Reporting Performance Results of +Ventricular Arrhythmia Detection Algorithms} (AAMI ECAR, 1987). It +will be most useful to readers who plan to use the suite of evaluation +software included in the WFDB Software Package ({\tt +http://www.\-physio\-net.\-org/\-physio\-tools/\-wfdb.\-shtml}); this +suite of software includes the reference implementations of the +evaluation protocols specified in EC38 and EC57. + +\section{Introduction} +Continuous monitoring of the electrocardiogram in both inpatients and +ambulatory subjects has become a very common procedure during the past +thirty years, with diverse applications ranging from screening for cardiac +arrhythmias or transient ischemia, to evaluation of the efficacy of +antiarrhythmic drug therapy, to surgical and critical care monitoring. +Since the first intensive care units were established in the 1960s, +the need for automated data reduction and analysis of the ECG has been +apparent, motivated by the very large amount of data that must be +analyzed (on the order of $10^{5}$ cardiac cycles per patient per +day). As clinical experience has led to the identification of more +and more prognostic indicators in the ECG, clinicians have demanded +and received increasingly sophisticated automated ECG analyzers. The +early heart rate monitors rapidly evolved into devices that were +designed first to detect ventricular fibrillation, then other +``premonitory'' ventricular arrhythmias. Many newer devices attempt +to detect supraventricular arrhythmias and transient ischemic ST +changes. + +Visual analysis of the ECG is far from simple. Accurate diagnosis of +ECG abnormalities requires attention to subtle features of the +signals, features that may appear only rarely, and which are often +obscured by or mimicked by noise. Diagnostic criteria are complicated +by inter- and intra-patient variability of both normal and abnormal +ECG features. Given these considerations, it is not surprising that +developers are faced with a difficult task in the design of algorithms +for automated ECG analysis, and that the results of their efforts are +imperfect. Certain parts of the problem --- QRS detection in the +absence of noise, for example --- are well-solved by most current +algorithms; others --- detection of supraventricular arrhythmias, for +example --- remain exceedingly difficult. Just as we may find it easiest +to analyze ``textbook'' examples, automated ECG analyzers may perform +better while analyzing the recordings used during their development +than when applied to ``real-world'' signals. + +Since automated ECG analyzers vary in performance, and since their +performance is dependent on the characteristics of their input, +quantitative evaluations of these devices are essential in order to +assess the usefulness of their outputs. At one extreme, a device's +outputs in the context of a particular type of signal may be so +unreliable as to be worthless; unfortunately, the other extreme --- +an output so reliable it can be accepted uncritically --- is not a +characteristic of any existing monitor, nor can it be expected in +the future. + +\subsection{ECG Databases} +Several databases of ECG recordings are generally available +for evaluating ECG analyzers. They serve several important needs: +\begin{itemize} + \item They contain {\em representative} signals. Wide variations in +ECG characteristics among subjects severely limit the value of +synthesized waveforms for testing purposes. Realistic tests of ECG +analyzers require large sets of ``real-world'' signals. + + \item They contain {\em rarely observed but clinically significant} +signals. Although it is not particularly difficult to obtain +recordings of common ECG abnormalities, often those that are most +significant are rarely recorded. Both developers and evaluators of +ECG analyzers need examples of such recordings. + + \item They contain {\em standard} signals. System comparisons +are meaningless unless performance is measured using the same test +data in each case, since performance is so strongly data-dependent. + + \item They contain {\em annotated} signals. Typically, each QRS +complex has been manually annotated by two or more cardiologists +working independently. The {\em reference} annotations produced +as a result serve as a ``gold standard'' against which a device's +analysis can be compared quantitatively. + + \item They contain {\em digitized, computer-readable} signals. It is +therefore possible to perform a fully automated, strictly reproducible +test in the digital domain if desired, allowing one to establish with +certainty the effects of algorithm modifications on performance. +\end{itemize} + +Standards EC38 and EC57 require the use of the following ECG +databases:\footnote{Sources: ECRI, 5200 Butler Pike, Plymouth Meeting, +PA 19462 USA (AHA DB); MIT-BIH Database Distribution, MIT Room +E25-505A, 77 Massachusetts Avenue, Cambridge, MA 02139 USA (MIT, NST, +and CU databases); CNR Institute of Clinical Physiology, Computer +Laboratory, via Trieste, 41, 56100 Pisa, Italy (ESC DB). Except for +the AHA DB, all are available in whole or in part from PhysioNet +({\tt http://www.\-physio\-net.\-org/}).} +\begin{itemize} + \item {\bf AHA DB}: The American Heart Association Database for +Evaluation of Ventricular Arrhythmia Detectors (80 records, 35 minutes +each) + + \item {\bf MIT DB}: The Massachusetts Institute of Technology--Beth +Israel Hospital Arrhythmia Database (48 records, 30 minutes each) + + \item {\bf ESC DB}: The European Society of Cardiology ST-T +Database (90 records, two hours each) + + \item {\bf NST DB}: The Noise Stress Test Database (12 records, 30 +minutes each) + + \item {\bf CU DB}: The Creighton University Sustained Ventricular +Arrhythmia Database (35 records, 8 minutes each) + +\end{itemize} +Each of these databases represents a very substantial effort by many +workers; in particular, the AHA, MIT, and ESC databases each required +more than five years of sustained effort by large teams of researchers +and clinicians from many institutions. Nevertheless, it should be +recognized that even these databases do not fully represent the +variety of ``real-world'' ECGs observed in clinical practice. +Although these databases permit standardized, quantitative, automated, +and fully reproducible evaluations of analyzer performance, it is +risky to extrapolate from the results of such evaluations to +expectations of real-world performance. Such extrapolations can be +particularly error-prone if the evaluation data were also used for +development of the analysis algorithm, since the algorithm may have +been (perhaps unintentionally) ``tuned'' to its training set. It +should also be noted that the first four of the databases listed above were +obtained from Holter ECG recordings; although the frequency response +of the Holter recording technique is not usually a limiting factor in +the performance of an ECG analyzer, it may tend to favor devices that +are designed to analyze Holter recordings over devices that have been +designed to analyze higher-fidelity input signals. + +\subsection{Evaluation Protocols} +Between 1984 and 1987, the Association for the Advancement of Medical +Instrumentation (AAMI) sponsored the development of a protocol for the +use of the first two of these databases, which was published as an +AAMI Recommended Practice.\footnote{{\it Testing and Reporting +Performance Results of Ventricular Arrhythmia Detection +Algorithms}. Publication AAMI ECAR (1987); succeeded by ANSI/AAMI +EC57:1998, available from AAMI, 1110 N Glebe Road, Suite 220, +Arlington, VA 22201 USA.} Between 1990 and 1998, the ambulatory ECG +subcommittee of the AAMI ECG committee developed and revised a +standard for ambulatory ECG monitors, significant portions of which +address the issue of the accuracy of automated analysis performed by +some of these devices.\footnote{{\it American National Standard for +Ambulatory Electrocardiographs}. Publication ANSI/AAMI EC38:1998; +available from AAMI (address above).} The ambulatory ECG standard +EC38:1998, and the ``testing and reporting performance results'' +standard EC57:1998, build on the evaluation protocol adopted for the +earlier Recommended Practice (ECAR), incorporating provisions for the +use of all five of the databases listed above, with extensions for +assessing detection of supraventricular arrhythmias and transient +ischemic ST changes. The standard breaks new ground in establishing +specific reporting requirements for the performance of automated ECG +analyzers on standard tests using the databases listed above. + +A significant constraint imposed on evaluators by the EC38 standard +is that they must obtain annotation files containing the analysis +results of the device under test. Although the device itself need not +produce these files, EC38 specifically requires that they be produced +by an automated procedure, which must be fully disclosed. The intent +of this requirement is to permit reproducible independent evaluations +in which neither the proprietary data of the developers (the analysis +algorithms) nor that of the evaluators (the test signals and reference +annotations) need necessarily to be disclosed. By defining the +interface between the developer and the evaluator to be the annotation +file, the responsibilities of each party are clearly defined: the +developer must make certain that the device's outputs are recorded in +the annotation file in the manner intended by the developer, but in +the language of the standard; the evaluator must make certain +that the algorithms used to compare the device's annotation files with +the reference annotation files conform to the specification of the +standard. The format and content of these annotation files is +specified in detail below. For many existing devices, it may be +difficult or impossible to obtain such annotation files without the +cooperation of the developers. Newly-designed devices should +incorporate the necessary ``hooks'' for producing annotation files. + +\subsection{Software to Support Evaluations} +This paper describes a suite of programs that support evaluations of +automated ECG analyzers in accordance with the methods described in +the EC38 and EC57 standards (as well as those in the earlier ECAR +Recommended Practice). These methods are sufficiently complex that +the development of such a suite of programs is not an afternoon's +work. By making generally available reference implementations of the +evaluation algorithms, much needless duplication of effort may be +avoided. By circulating them in source form to other users, we may +hope to find and correct any bugs, with the eventual result that +evaluators of devices should not have to bear the burden of evaluating +the evaluation technique itself. By using them for evaluations, any +ambiguities in the English specification of the evaluation algorithms +are resolved in a consistent manner for each device tested. These +programs are written in C and run under MS-DOS or UNIX. They have +been made available as part of the WFDB Software Package. In this +paper, the names of these programs are printed {\tt like this}. + +\section{Evaluating an ECG Analyzer} +The major task facing an evaluator is that of presenting the reference signals +to the device under test, and collecting annotation files from the device. The +details of this task will vary for each device, but a few general hints are +given below. A second task, that of obtaining reference heart rate +measurements, should be a much simpler job. Once all of this information has +been gathered, the remaining work required --- that of comparing the device's +analysis against the ``gold standard'' --- can be performed automatically. + +\subsection{Presenting Signals to the Analyzer} +Two distinctly different types of tests are possible. If the device can accept +digital inputs, the reference signals can be supplied in that form (perhaps +after resampling with {\tt xform} to convert the digitized samples to the +expected sampling frequency and numerical range, and possibly with additional +digital signal processing to simulate the signal conditioning normally +performed by the device's front-end data acquisition hardware). The primary +advantage of testing in the digital domain is that the test is (or should be) +strictly reproducible, since no noise or additional quantization error can be +introduced in this way. This method usually avoids the issue of +synchronization of the test annotations with the reference signals discussed +below. + +Testing in the analog domain requires that analog signals be recreated from +the digital signals. (It should be noted that even the analog versions of the +MIT and AHA databases that have been available in the past were recreated +from the digitized signals by the database developers.) The advantage of this +approach is that it exercises the entire system, including the front-end data +acquisition hardware. It is often difficult, however, to establish +synchronization between the signal source and the analyzer, needed in order to +permit comparisons of annotations. One way of dealing with this problem is to +arrange for the analyzer's sampling clock to trigger the digital-to-analog +converter used to recreate the analog signals, or to arrange for an external +clock to trigger both D/A conversion in the playback system and A/D conversion +in the analyzer. Another method is to begin and end the signal generation +process by delivering signals from the analyzer to the playback device, and +recording the analyzer's clock time at the times of the signals; assuming that +both the analyzer and the playback device have stable clocks, event times in +the analyzer's frame of reference can be converted to database sample numbers +by linear interpolation. The WFDB software package includes a program ({\tt +sample}) that uses a Microstar DAP 2400-series analog interface +board\footnote{ +Source: Microstar Laboratories, {\tt http://www.mstarlabs.com/}. External +analog anti-aliasing filters (to reduce ``staircasing'') and attenuators (to +obtain patient-level signals) may also be required, depending on the system to +be evaluated. DAP boards can also be used with {\tt sample} to create new +database records.} +and an MS-DOS PC to recreate analog signals from digital database records on +CD-ROMs or magnetic disk files. + +\subsection{Obtaining Test Annotation Files} +For any ambulatory ECG monitor that incorporates automated analysis functions, +the EC-38 standard requires the manufacturer to implement and disclose a +method for producing test annotation files. Independent evaluators should seek +assistance from the manufacturer in any case, since the manufacturer's +interpretation of the device's outputs in the language of EC-38 is definitive +(in effect, the annotation file generation technique becomes part of +the system under test). Note that generation of annotation files need not be +synchronous with data acquisition; a device might conceivably store all of the +necessary data until the end of the test, and only then write the file. +Neither does the standard require that an annotation be determined within any +fixed amount of time, as would be expected of devices designed to trigger +pacing, for example. Furthermore, EC-38 specifically allows for the +possibility that the device under test might not produce the annotation file +directly. If any external hardware or software is required to do so, however, +it must be made generally available or specified in sufficient detail by the +manufacturer to permit an independent evaluator to obtain test annotation +files. + +Annotation files contain a label (an annotation) for each beat and for certain +other features of the signals, such as rhythm and ST changes. Annotations are +stored in time order in annotation files. The ``time'' of an annotation is +that of the sample in the signal file with which the annotation is +associated.\footnote{Times in annotation and signal files are usually expressed +as {\em sample numbers} (the number of samples in the signal file that precede +the sample in question).} The WFDB library (included in the WFDB software package) +includes C-callable functions ({\tt getann} and {\tt putann}) for reading and +writing annotations. In a C program, annotations appear as data structures +containing a 32-bit {\tt time} field together with a pair of 8-bit fields that +encode the annotation type and sub-type ({\tt anntyp} and {\tt subtyp} [sic], +respectively), and a variable-length {\tt aux} field usually used to store +text. In annotation files, these annotation structures are usually stored in +a variable-length bit-packed format averaging slightly more than 16 bits per +annotation.\footnote{Test annotations that include heart rate or ST +measurements require substantially more storage. {\tt getann} and +{\tt putann} can also use the original AHA DB format (containing fixed-length +annotations, 16 bytes each), but this format should not be used for +evaluations of devices that incorporate ST analysis functions, since the +space available for the {\tt aux} data is too small to store ST measurements.} + +Test annotation files may include the following: +\begin{itemize} + \item {\em Beat annotations}. These need not coincide precisely with the +reference beat annotations, since the evaluation protocol allows a time +difference of up to 150 ms between each pair of matching beat annotations. +All beat annotations are mapped during the evaluation process into the set +\{ N, V, F, S, Q \} (corresponding to normal, ventricular ectopic, ventricular +fusion, supraventricular ectopic, and unclassifiable or paced beats +respectively); devices need not be capable of producing all of these +annotations, but any beat annotations that they do produce will be translated +into one of these types. The standard specifies the mapping used for the +{\tt anntyp} values defined in {\tt }. (This file is +included in the WFDB Software Package.) Any beat annotations that +appear in the first five minutes of a record (the ``learning period'') are +ignored in the evaluation process. The remainder of the record (the ``test +period'') must be fully annotated. Note in particular that the last beat of +some records may be very close to the last sample; since the analyzer may +reach the end of the input signals before producing an annotation for the last +beat, it may be necessary to ``pad'' the input data for a few seconds at the +end of the record to permit the analyzer to emit its final beat annotation. + + \item {\em Shutdown annotations}. If the device suspends its analysis +because of poor signal quality or for any other reason, it should mark the +periods during which analysis is suspended. The evaluation software tallies +beats missed during such periods separately from beats missed at other times. +The beginning of each period of shutdown may be marked using a {\tt NOISE} +annotation with ${\tt subtyp} = -1$, and the end of each period of shutdown +may be marked using a {\tt NOISE} annotation with ${\tt subtyp} = 0$ (see +the source for {\tt bxb} for notes on other acceptable methods of marking +shutdown). + + \item {\em Ventricular fibrillation annotations}. The beginning and end +of each detected episode of ventricular fibrillation should be marked using +{\tt VFON} and {\tt VFOFF} annotations. + + \item {\em Other rhythm annotations}. These should include +{\tt RHYTHM} annotations marking the beginning and end of each detected episode +of atrial fibrillation. The beginning of each episode should be marked with an +``{\tt (AFIB}'' rhythm annotation, i.e., an annotation with {\tt anntyp} = {\tt +RHYTHM} and {\tt aux} = \verb|"\05(AFIB"|, where ``\verb|\05|'' is C notation +for a byte with the value 5 (ASCII control-E). Non-empty {\tt aux} fields +always begin with a byte that specifies the number of data bytes that follow; +in this case, the five characters ({\tt ( A F I B}) of the string. The end of +each episode should be marked with any other rhythm annotation (for example, +\verb|"\02(N"|). + + \item {\em Heart rate measurements}. Each type of heart rate measurement +(including any heart rate or RR interval variability measurements) made by the +device under test should be assigned a measurement number, $m$, between 0 and +127. A {\tt MEASURE} annotation should be recorded for each heart rate +measurement, with ${\tt subtyp} = m$ and with the measurement in the {\tt aux} +field, as an ASCII-coded decimal number. + + \item {\em ST deviation measurements}. If available, these should +be provided in the {\tt aux} fields of beat annotations, as +ASCII-coded decimal numbers indicating the deviations in microvolts +from reference levels established for each signal from the first 30 +seconds of each record. For example, ``{\tt 25 -104}'' indicates a 25 +$\mu$V elevation in signal 0 and a 104 $\mu$V depression in signal 1. +If ST measurements are omitted from any beat annotation, the +evaluation software assumes they are unchanged from their previous +values. + + \item {\em Ischemic ST change annotations}. These {\tt STCH} annotations +should mark the beginning and end of each detected episode of ischemic ST +change. ST change annotations have additional information in the {\tt aux} +field as for rhythm annotations: the beginning of each episode is marked by an +``{\tt (ST}{\it ns}'' annotation, and the end of each episode by a +``{\tt ST{\it ns})}'' annotation, where {\it n} indicates the signal affected + (``{\tt 0}'' or ``{\tt 1}''), and {\it s} indicates ST elevation (``{\tt +}'') +or depression (``{\tt -}''). {\it n} may be omitted if the episode detection +criteria depend on features of both signals. The extremum of each episode may +optionally be marked with an ``{\tt AST}{\it nsm}'' annotation, where {\it n} +and {\it s} are defined as above, and {\it m} is the ST deviation in +microvolts, relative to a reference level established as above. + + \item {\em Comment annotations}. Annotations with {\tt anntyp = NOTE} +and any desired string data in {\tt aux} may be included anywhere in +an annotation file. {\tt NOTE} annotations are ignored by the +standard evaluation software; they may be used, for example, to +record the values of internal algorithm variables for debugging purposes. +\end{itemize} +Note that only beat annotations are absolutely required in test annotation +files. ST deviation measurements within beat annotations, and the other +types of annotations listed above, only need to be recorded for devices +that are claimed by their manufacturers to provide optional features for +detection of ventricular or atrial fibrillation, measurement of ST deviations, +or detection of ischemic ST changes. + +If the time units in the test annotation files are not the same as those in +the reference annotation files (for example, because {\tt xform} was used to +change the sampling frequency of the signal files in a digital-domain test), +the time units must be rescaled before proceeding with the comparison. This +may be done by using {\tt xform} to rewrite the test annotation files with +the original sampling frequency.\footnote{ +The obvious alternative, using {\tt xform} to rewrite the reference annotation +files at the time the signal files are resampled, should not be used in a +formal evaluation. Because of the possibility that resampling the reference +annotation files might result in moving reference annotations into or out of +the test period, or changing the lengths of episodes, doing so might produce +results that could not be directly compared with those obtained in a standard +evaluation.} + +Details of the ST deviation measurement and episode detection criteria used in +producing the reference annotation files for the ESC database may be found in +several sources.\footnote{ See, for example, the {\it European ST-T Database +Directory}, pp. vi-vii, supplied with the ESC DB; or Taddei, A., et al., ``The +European ST-T database: development, distribution, and use'', {\it Computers +in Cardiology} {\bf 17}:177-180 (1990).} Note, however, that many techniques +for measuring ST deviation and for detecting transient ischemic ST changes are +possible, and that to date the best evaluation results have been obtained for +analyzers using criteria that do not attempt to mimic those used by the human +experts who annotated the database. + +\subsection{Obtaining Reference Heart Rate Data} +The final step of preparation for the evaluation is to process the +reference annotation files to obtain reference heart rate annotation +files. These files must contain heart rate measurement annotations +with the same measurement numbers assigned as for the test heart rate +annotations; they need not necessarily contain beat or other +annotations from the reference annotation files. Quoting from EC38, +\begin{quote} +To evaluate the accuracy of heart rate measurement, the evaluator +shall implement and disclose a method for obtaining heart rate +measurements using the reference annotation files (the `reference +heart rate'). This method need not be identical to the method used by +the device under test, but in general it will be advantageous if it +matches that method as closely as possible. +\end{quote} +It will generally be in the manufacturer's interest to provide a +program for generating reference heart rate annotation files, to avoid +the need for an independent evaluator to do so, with a likely result +of less than optimal agreement with the test heart rate measurements. +The WFDB software package includes a sample implementation of such a +program ({\tt examples/refhr.c}); note that it will need to be +customized for each device to be tested. + +Note that measurement errors are normalized by the mean value of the reference +measurements in each record. Be certain that this mean value cannot be +zero!\footnote{ +For certain types of HRV or RRV measurements (though not for heart rate +measurements), this is a potential problem. One solution is to add a small +positive offset to any measurement with an expected zero mean. It is within +the letter, though not the spirit, of the standard protocol, to add a +very large number in such a case, so as to make the error percentage +arbitrarily small. The mean value of the reference measurements must be +reported; this should serve as a disincentive to this sort of creative abuse +of the standard. An honest approach might be to add an offset on the order of +the expected standard deviation of the individual measurements.} + +\section{Comparing Annotation Files} + +Once the test annotation files and the reference heart rate annotation files +have been obtained, the remainder of the evaluation procedure is +straightforward. All of the information needed to characterize the analysis +performed by the device under test is encoded in the test annotation files; +similarly, all of the information needed to characterize the actual contents +of the test signals is encoded in the reference annotation and reference +heart rate annotation files. The evaluation procedure thus entails comparison +of the test and reference annotation files for each record. + +Four programs are provided in the WFDB Software Package for this purpose: +\begin{itemize} + \item {\tt bxb} compares annotation files beat by beat; its output +includes QRS, VEB, and (optionally) SVEB sensitivity and positive +predictivity, as well as RR interval error and shutdown statistics. + + \item {\tt rxr} compares annotation files run by run; its output +includes ventricular (and, optionally, supraventricular) ectopic couplet, short +run (3--5 beats), and long run (6 or more beats) sensitivity and positive +predictivity. + + \item {\tt epicmp} compares annotation files episode by episode; its +output includes ventricular fibrillation, atrial fibrillation, and ischemic ST +detection statistics as well as comparisons of ST deviation measurements. + + \item {\tt mxm} compares measurements from a test annotation +file and a reference heart rate annotation file; its output indicates +measurement error.\footnote{ +{\tt mxm} is not restricted to comparison of heart rate measurements; if +other types of measurements are available, they may be compared in the same +manner as heart rates by {\tt mxm}.} +\end{itemize} + +The WFDB Software Package also includes three related programs: +\begin{itemize} + \item {\tt sumstats} reads certain output files generated by {\tt bxb}, +{\tt rxr}, {\tt epicmp}, and {\tt mxm}, and calculates aggregate statistics for +a set of records. + \item {\tt plotstm} generates scatter plots of ST deviation measurements +collected by {\tt epicmp}. + \item {\tt ecgeval} automates the entire comparison procedure by running +{\tt bxb}, {\tt rxr}, {\tt epicmp}, and {\tt mxm} for each record, collecting +their output, then running {\tt sumstats} (and optionally {\tt plotstm}), and +finally printing the results. +\end{itemize} + +To obtain a concise summary of how to use any of these programs, including +a list of any command-line options, simply run the program without any +command-line arguments. Refer to the {\it WFDB Applications Guide}, +which accompanies the WFDB Software Package, for details. + +In most cases, it will be easiest to collect all of the annotation files +before beginning the comparison, and then to perform the comparison by typing: +\begin{verbatim} +ecgeval +\end{verbatim} +The program asks for the test annotator name, the names of the databases +used for testing, and what optional detector outputs should be evaluated. + +Only the statistics required by EC38 and EC57 are reported by {\tt +ecgeval}. If more detailed evaluation data are needed, it will be +necessary to run {\tt bxb}, {\tt rxr}, etc., separately. If file +space is extremely limited, it may be necessary to delete each test +annotation file after it has been compared against the reference file, +before the next test annotation file can be created; in such cases, it +may also be necessary to prompt the user to change media containing +signal or reference annotation files, or to reset the device under +test before beginning each record. Optionally, {\tt ecgeval} can +generate a script (batch) file of commands, which can be edited to +accommodate special requirements such as these. + +For example, suppose we have obtained a set of test annotation files with the +annotator name ``{\tt yow}'', which we wish to compare against the reference +annotation files (annotator name ``{\tt atr}'')\footnote{ +Annotation files for any given record are distinguished by annotator names, +which correspond to the ``extension'' of the file name. The +reference annotation files supplied with the databases have the annotator +name ``{\tt atr}'' (originally ``{\tt atruth}'' because ``{\tt a}'' +was intended to indicate the file type, and ``{\tt truth}'' because \ldots +well, because the annotations are supposed to be The Truth).} +and reference heart rate annotation files (annotator name ``{\tt htr}''). +The portion of the evaluation script generated by {\tt ecgeval} for MIT DB +record 100 is: +\begin{verbatim} +bxb -r 100 -a atr yow -L bxb.out sd.out +rxr -r 100 -a atr yow -L vruns.out sruns.out +mxm -r 100 -a htr yow -L hr0.out -m 0 +epicmp -r 100 -a atr yow -L -A af.out + -V vf.out -S st.out stm.out +\end{verbatim} +(The last two lines shown above form a single command. The {\tt mxm} command +gathers statistics on measurement number 0; if other heart rate measurements +are defined, {\tt mxm} should be run once for each such measurement, +substituting the appropriate measurement numbers for {\tt 0} in the output +file name, {\tt hr0.out}, and the final argument.) Statistics for the +remainder of the MIT DB are obtained by repeating these commands, substituting +in each the appropriate record names for {\tt 100}. Once these commands have +been run for all of the records, the record-by-record statistics will be found +in nine files ({\tt bxb.out}, {\tt sd.out}, {\tt vruns.out}, {\tt sruns.out}, +{\tt hr0.out}, {\tt af.out}, {\tt vf.out}, {\tt st.out}, and {\tt stm.out}). +The first eight of these files contain one line for each record.\footnote{ +{\tt stm.out} contains one line for each ST deviation measurement that was +compared; in this example, {\tt stm.out} would be empty since the reference +annotation files of the MIT DB do not contain ST deviation measurements.} {\tt +sumstats} can read any of these files, and calculates aggregate performance +statistics; to use it, type ``{\tt sumstats} {\it file}'', where {\it file} is +the name of one of these files. The output of {\tt sumstats} contains a copy +of its input, with aggregate statistics appended to the end. Typically this +output might be saved in a file to be printed later, e.g., +\begin{verbatim} +sumstats bxb.out >>report.out +\end{verbatim} + +A scatter plot of the ST measurement comparisons performed by {\tt epicmp} can +be produced using {\tt plotstm}, the output of which can be printed directly on +any PostScript printer. For example, to make a plot file for {\tt stm.out}, +type: +\begin{verbatim} +plotstm stm.out >stm.ps +\end{verbatim} + +\section{Studying Discrepancies} + +Having conducted an evaluation as described above, a common question +is ``what were the errors?'' {\tt bxb} and {\tt rxr} can help +answer such questions. + +{\tt bxb} can generate an output annotation file (with annotator name +``{\tt bxb}'') in which all matching beat annotations are copied from +the test annotation file, and each mismatch is indicated by a {\tt +NOTE} annotation, with the {\tt aux} field indicating the element of +the confusion matrix in which the mismatch is tallied (e.g., ``{\tt Vn}'' +represents a beat called a VEB by the reference annotator and a normal +beat by the test annotator). Programs such as {\tt view}, +{\tt wave}, and {\tt wview}\footnote{ +{\tt view} (for MS-DOS), {\tt wave} (for Linux, Solaris, and SunOS) and +{\tt wview} (for MS Windows) are included in the WFDB Software Package.} +can be used to search for and display the waveforms associated with the +mismatches. To generate an output annotation file, add the {\tt -o} option to +the {\tt bxb} command line, as in: +\begin{verbatim} +bxb -r 100 -a atr yow -L bxb.out sd.out -o +\end{verbatim} +A particularly useful way to document an evaluation is to print a +full disclosure report with {\tt bxb} output annotations, using the +program {\tt psfd} (also included in the WFDB Software Package). This may +be accomplished by preparing a file containing a list of the names of +the records to be printed (call it {\tt list}), and then using the +command: +\begin{verbatim} +psfd -a bxb list >output.ps +\end{verbatim} +The file {\tt output.ps} can be printed on any PostScript printer. +Run {\tt psfd} without any arguments for a summary of its (numerous) +options; try a short test before making a large set of printouts, +which can take a long time. + +Both {\tt bxb} and {\tt rxr} accept a {\tt -v} option to run in +``verbose'' mode, in which each discrepancy is reported in the +standard error output. When running {\tt rxr}, this feature is useful +for finding missed and falsely detected ectopic couplets and runs. + +\section{Acknowledgements} + +Having been involved in the production of most of the databases as +well as the design of the evaluation protocols, it has been my +privilege to receive the benefits of the sustained contributions of +many colleagues who have supported these projects with their dedicated +efforts. I would like especially to thank +Paul Albrecht, +Jim Bailey, +Ted Baker, +Rich Bowser, +Don Brodnick, +Jerry Cox, +Phil Devlin, +Charlie Feldman, +Scott Greenwald, +Russ Hermes, +David Israel, +Franc Jager, +Carlo Marchesi, +Roger Mark, +Joe Mietus, +Warren Muldrow, +Diane Perry, +Scott Peterson, +Ken Ripley, +Paul Schluter, +Alessandro Taddei, +Roy Wallen, +and Cees Zeelenberg. + +\appendix +\section{Using the AHA Database} + +Since the AHA DB is not available in the standard PhysioBank format +used by all of the other databases, the WFDB Software Package includes +a pair of programs that convert files read from AHA DB distribution +tapes or floppy disks into files in PhysioBank format. {\tt a2m} +converts AHA annotation files, and {\tt ad2m} converts AHA signal +files and also generates header ({\tt *.hea}) files. (Run these +programs without command-line arguments to obtain instructions on +their use.) Using {\tt a2m} and {\tt ad2m}, all 80 AHA DB records can +be stored in roughly 130 Mb of disk space (assuming use of the +standard 35-minute records). These programs can also reformat old +(pre-1989) MIT DB tapes written in the AHA DB distribution format. + +It is also possible to read and write AHA tape-format files directly using +the WFDB library; refer to the {\it WFDB Programmer's Guide} +for details. + +\section{Noise stress testing} + +With respect to many tasks performed by an ECG analyzer, dealing with +noise is the major problem faced by system designers. Although +measurements such as ST deviation may be obtained reliably in clean +signals, the presence of noise may render them inaccurate. In some +instances, it is sufficient to recognize the presence of noise and either +to mark measurements as unreliable or to avoid making measurements +altogether. In other cases, excluding noisy data is inappropriate +(for example, given the multiple correlations among physical +activity, noise, and transient ischemia, excluding noisy signals is +likely to introduce sampling bias in an ischemia detector). + +It is difficult to measure the effects of noise on an ECG analyzer +using ordinary recordings. Even if existing databases include an +adequate variety of both ECG signals and noise, the sample size is +certainly too small to include all combinations of noise and ECG +signals that may be encountered in clinical use. In ordinary +recordings, it is difficult or impossible to separate the effects of +noise from the intrinsic problems of analyzing clean signals of the +same type. + +The noise stress test circumvents these problems. By adding noise +in calibrated amounts to clean signals, any combination of noise and +signal types is possible. Since both the noise-corrupted signal and +the clean signal can be analyzed (in separate experiments) by the +same analyzer, the effects of noise on the analysis are readily +separable from any other problems that may arise while analyzing the +clean signals. Finally, since the test can be repeated using +different amounts of noise, it is possible to characterize analyzer +performance as a function of signal-to-noise ratio. + +The major criticisms of the noise stress test are that not all noise +is additive, and that the characteristics of the added noise may not +perfectly match those of noise observed in clinical practice. These +points, though formally irrefutable, do not negate the value of the +test. In practice, most of the troublesome noise is additive; thus +(given appropriate inputs) the noise stress test can simulate most of +the noisy signals of interest. The NST DB includes noise recordings +made using standard ambulatory ECG electrodes and recorders, but with +electrodes placed on the limbs of active volunteers in configurations +in which the subject's ECG is not apparent in the recorded signals. +Given the recording technique used, it is not surprising that the +characteristics of the recorded noise closely match those of noise in +standard ambulatory ECG recordings. Although it may be argued that the +particular muscles responsible for the recorded noise might produce +different signals than those that generate the EMG present in noisy +ECGs, no such differences are apparent from comparisons of either the +signals or their power spectra. + +The NST DB includes a small set of ECG records with calibrated amounts +of added noise. EC38 specifies that performance on these records must +be reported, although no specific performance levels are required. +Program {\tt nst} can be used to generate additional records for noise +stress testing. To do so, choose an ECG record and a noise record +(the latter may be {\tt bw}, {\tt em}, or {\tt ma} from the NST DB, or +any other available noise recording). Run {\tt nst} and answer its +questions to generate a noisy ECG record that may then be used in the +same way as any other WFDB record. By default, {\tt nst} adds no noise +during the first five minutes of the record, then adds noise for the +next two minutes, none for the following two minutes, and repeats this +pattern of two minutes of noise followed by two minutes of clean +signals for the remainder of the record. The scale factors for the +noise, if determined by {\tt nst}, are adjusted such that the +signal-to-noise ratios are equal for each signal. The durations of +the noisy periods, and the scale factors for each signal, are recorded +in a {\em protocol annotation file}, which is generated by {\tt nst} +unless an existing protocol annotation file is supplied as input. To +change these parameters, simply edit the protocol annotation file +(using, for example, {\tt rdann} to convert it to text form, any text +editor to make the modifications, and {\tt wrann} to convert it back +to annotation file format), then rerun {\tt nst} using the protocol +file to generate a new record. +\end{document} diff -Naur wfdb-10.2.9/doc/wag-src/fixag.sed wfdb-10.3.0/doc/wag-src/fixag.sed --- wfdb-10.2.9/doc/wag-src/fixag.sed Mon Sep 9 10:43:13 2002 +++ wfdb-10.3.0/doc/wag-src/fixag.sed Sat Nov 2 01:05:03 2002 @@ -44,7 +44,7 @@ s+(http://www.aami.org/)+(http://www.aami.org/)+ s+"http://www.gnuplot.info/"+"http://www.gnuplot.info/" target="other"+ s+http://www.mstarlabs.com/+http://www.mstarlabs.com/+ -s+(http://www.hsr.nl/bobkemp/edf/edf.htm)+(http://www.hsr.nl/bobkemp/edf/edf.htm)+ +s+(http://www.hsr.nl/edf/)+(http://www.hsr.nl/edf/)+ s+Evaluating ECG Analyzers+Evaluating ECG Analyzers+ s+WFDB Programmer's Guide+WFDB Programmer's Guide+ s+WFDB Applications Guide+WFDB Applications Guide+ diff -Naur wfdb-10.2.9/doc/wag-src/getpagenos.c wfdb-10.3.0/doc/wag-src/getpagenos.c --- wfdb-10.2.9/doc/wag-src/getpagenos.c Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/getpagenos.c Tue Oct 29 11:38:44 2002 @@ -0,0 +1,58 @@ +/* file: getpagenos.c G. Moody 29 October 2002 + +Extract page numbers for the table of contents for the WFDB Applications Guide +*/ + +#include + +main() +{ + static char buf[200], pagename[200], *p, *q; + int lineno = 0; + int pageno = 0; + int n; + + while (fgets(buf, sizeof(buf), stdin)) { + lineno++; + if (strncmp(buf, "%%Page: ", 8) == 0) { /* found a page number */ + if (sscanf(buf+8, "%d", &n) < 1) + fprintf(stderr, "%d: missing page number\n", lineno); + else { + if (n != pageno+1) + fprintf(stderr, "%d: page %d expected, page %d found\n", + lineno, pageno+1, n); + pageno = n; + /* Look for page name */ + fgets(buf, sizeof(buf), stdin); lineno++; + if (strcmp(buf, "%%BeginPageSetup\n")) { + fprintf(stderr, "%d: BeginPageSetup missing\n", lineno); + continue; + } + fgets(buf, sizeof(buf), stdin); lineno++; + if (strcmp(buf, "BP\n")) { + fprintf(stderr, "%d: BP\n", lineno); + continue; + } + fgets(buf, sizeof(buf), stdin); lineno++; + if (strcmp(buf, "%%EndPageSetup\n")) { + fprintf(stderr, "%d: EndPageSetup missing\n", lineno); + continue; + } + fgets(buf, sizeof(buf), stdin); lineno++; + for (p = buf; p-bufatr' is used to name the set of reference annotations supplied by the database developers. Other annotation sets have annotator names that may contain letters, digits, and underscores, as for record names. -.IP -Each PhysioBank database directory includes a text file named \fBANNOTATORS\fR, -which lists the annotator names for all annotation files in that directory. + +

+Each PhysioBank database directory includes a text file named +ANNOTATORS, which lists the annotator names for all annotation files in +that directory.

time diff -Naur wfdb-10.2.9/doc/wag-src/maketoc-html.sh wfdb-10.3.0/doc/wag-src/maketoc-html.sh --- wfdb-10.2.9/doc/wag-src/maketoc-html.sh Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/maketoc-html.sh Fri Nov 1 10:29:13 2002 @@ -0,0 +1,84 @@ +#! /bin/sh +# file: maketoc-html.sh G. Moody 29 October 2002 +# +# Generate the HTML table of contents for the WFDB Applications Guide + +necho() +{ + if [ -s echo.$$ ] + then echo $* "\\c" + else echo -n $* + fi +} + +tocentry() +{ + case $1 in + *.1) b=`basename $1 .1`; s=1 ;; + *.3) b=`basename $1 .3`; s=3 ;; + *.5) b=`basename $1 .5`; s=5 ;; + *.7) b=`basename $1 .7`; s=7 ;; + *) b=$1; s=x ;; + esac + case $b in + ???????*) b=`echo $b | cut -c 1-6` ;; + esac + necho '
  • ' + grep "\\\\-" $1 | head -1 | sed "s+ \\\\- +: +" | \ + sed "s+\\\\fB++" | sed "s+\\\\fR++" +} + +echo -n >echo.$$ + +cat wag.ht0 +cat <Applications +
      +EOF + +for F in *.1 +do + tocentry $F +done + +cat < +

      WFDB libraries

      +
        +EOF + +for F in *.3 +do + tocentry $F +done + +cat < +

        WFDB file formats

        +
          +EOF + +for F in *.5 +do + tocentry $F +done + +cat < +

          Miscellaneous

          +
            +EOF + +for F in *.7 +do + tocentry $F +done + +cat < +EOF + +cat wag.ht1 +rm echo.$$ diff -Naur wfdb-10.2.9/doc/wag-src/maketoc-tex.sh wfdb-10.3.0/doc/wag-src/maketoc-tex.sh --- wfdb-10.2.9/doc/wag-src/maketoc-tex.sh Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/maketoc-tex.sh Tue Oct 29 15:29:41 2002 @@ -0,0 +1,78 @@ +#! /bin/sh +# file: maketoc-tex.sh G. Moody 29 October 2002 +# +# Generate the table of contents and appendices for the WFDB Applications Guide + +prep() +{ + ( for F in *.1 *.3 *.5; do grep "\\\\-" $F | head -1; done ) >namelines.out + ./getpagenos pagenos.out + pr -m -s -T namelines.out pagenos.out | \ + sed "s+\\\\fB+\\\\textbf{ +" | \ + sed "s+\\\\fR+}+" >toc.out + rm -f namelines.out pagenos.out +} + +appendices() +{ + P=`grep '%%Pages: ' >wag2.ps; P=`expr $P + 2`;; + *) P=`expr $P + 1`;; + esac + sed s/FIRSTPAGE/$P/ install.tex + make wag3.ps + N=`grep '%%Pages: ' >wag3.ps; Q=`expr $Q + 1`;; + esac + sed s/FIRSTPAGE/$Q/ eval.tex + make wag4.ps +} + +prep >toc-log.$$ 2>&1 + +cat <>toc-log.$$ 2>&1 + +cat < +#include + +main() +{ + static char buf[200], *p, *q; + + while (fgets(buf, sizeof(buf), stdin)) { + if ((p = strstr(buf, " \\- ")) == NULL) + continue; + *p = '\0'; + p += 4; + if ((q = strstr(p, "\t")) == NULL) + continue; + *q = '\0'; + q++; + q[strlen(q) - 1] = '\0'; + printf("\\contentsline {section}{\\textbf{%s}: %s}{%s}\n", buf, p, q); + } +} + + diff -Naur wfdb-10.2.9/doc/wag-src/mxm.1 wfdb-10.3.0/doc/wag-src/mxm.1 --- wfdb-10.2.9/doc/wag-src/mxm.1 Tue Jul 30 21:36:27 2002 +++ wfdb-10.3.0/doc/wag-src/mxm.1 Fri Nov 22 14:47:37 2002 @@ -1,4 +1,4 @@ -.TH MXM 1 "30 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH MXM 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME mxm \- ANSI/AAMI-standard measurement-by-measurement annotation comparator .SH SYNOPSIS @@ -90,7 +90,7 @@ It may be necessary to set and export the shell variable \fBWFDB\fR (see \fBsetwfdb\fR(1)). .SH SEE ALSO -\fBbxb\fR(1), \fBecgeval\fR(1), \fBepic\fR(1), \fBrxr\fR(1), +\fBbxb\fR(1), \fBecgeval\fR(1), \fBepicmp\fR(1), \fBrxr\fR(1), \fBsetwfdb\fR(1), \fBsumstats\fR(1) .br \fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) diff -Naur wfdb-10.2.9/doc/wag-src/nst.1 wfdb-10.3.0/doc/wag-src/nst.1 --- wfdb-10.2.9/doc/wag-src/nst.1 Wed Jul 31 22:32:10 2002 +++ wfdb-10.3.0/doc/wag-src/nst.1 Fri Nov 22 14:49:11 2002 @@ -1,5 +1,5 @@ '\" t -.TH NST 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH NST 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME nst \- noise stress test for ECG analysis programs .SH SYNOPSIS @@ -208,7 +208,7 @@ .SS Using \fBnst\fP output The output records generated by \fBnst\fR may be analyzed in the same way as the clean records from which they were obtained. For ECG analyzers, -programs such as \fBbxb\fR(1), \fBepic\fR(1), \fBmxm\fR(1), and \fBrxr\fR(1) +programs such as \fBbxb\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), and \fBrxr\fR(1) may be useful for assessing the accuracy of analysis results. A series of \fBnst\fR output records with a range of signal-to-noise ratios may be used to determine how analyzer performance varies as a function of SNR. The @@ -228,7 +228,7 @@ It may be necessary to set and export the shell variable \fBWFDB\fR (see \fBsetwfdb\fR(1)). .SH SEE ALSO -\fBbxb\fR(1), \fBepic\fR(1), \fBmxm\fR(1), \fBrdann\fR(1), +\fBbxb\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), \fBrdann\fR(1), \fBrxr\fR(1), \fBsetwfdb\fR(1), \fBsigamp\fR(1), \fBxform\fR(1), \fBwrann\fR(1), \fBsignal\fR(5) .HP diff -Naur wfdb-10.2.9/doc/wag-src/plot2d.1 wfdb-10.3.0/doc/wag-src/plot2d.1 --- wfdb-10.2.9/doc/wag-src/plot2d.1 Wed Aug 7 12:07:12 2002 +++ wfdb-10.3.0/doc/wag-src/plot2d.1 Mon Oct 28 17:34:46 2002 @@ -1,6 +1,6 @@ .TH PLOTxD 1 "30 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" .SH NAME -plot2d, plot3d \- make 2-D or 3-D plots from text files of data, using \fIgnuplot\fR +plot2d, plot3d \- make 2-D or 3-D plots from text files of data, using \fBgnuplot\fR .SH SYNOPSIS \fBplot2d\fR [ \fIinput-file\fR ] [ [ \fIxcol\fR ] \fIycol\fR ] [ \fIoptions ...\fR ] .br diff -Naur wfdb-10.2.9/doc/wag-src/plotstm.1 wfdb-10.3.0/doc/wag-src/plotstm.1 --- wfdb-10.2.9/doc/wag-src/plotstm.1 Thu Aug 1 10:00:03 2002 +++ wfdb-10.3.0/doc/wag-src/plotstm.1 Fri Nov 22 14:50:12 2002 @@ -1,17 +1,17 @@ -.TH PLOTSTM 1 "1 August 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH PLOTSTM 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME plotstm \- produce scatter plot of ST measurement errors on a PostScript device .SH SYNOPSIS \fBplotstm\fR \fIfile\fR .SH DESCRIPTION .PP -\fBplotstm\fR reads a file of ST measurement errors produced by \fBepic\fR(1) +\fBplotstm\fR reads a file of ST measurement errors produced by \fBepicmp\fR(1) using its \fB-S\fR, \fB-S0\fR, or \fB-S1\fR option, and generates a PostScript page description for a scatter plot of these data, as specified by ANSI/AAMI EC38 and ANSI/AAMI EC57. The standard output of \fBplotstm\fR may be printed directly on any PostScript device. .SH SEE ALSO -\fBecgeval\fR(1), \fBepic\fR(1) +\fBecgeval\fR(1), \fBepicmp\fR(1) .br \fIEvaluating ECG Analyzers\fR .br diff -Naur wfdb-10.2.9/doc/wag-src/plt.1 wfdb-10.3.0/doc/wag-src/plt.1 --- wfdb-10.2.9/doc/wag-src/plt.1 Wed Jul 31 22:35:24 2002 +++ wfdb-10.3.0/doc/wag-src/plt.1 Sun Nov 17 00:59:09 2002 @@ -1,4 +1,4 @@ -.TH PLT 1 "31 July 2002" "plt 1.99" "WFDB Applications Guide" +.TH PLT 1 "17 November 2002" "plt 2.2" "WFDB Applications Guide" .SH NAME plt \- make 2-D plots .SH SYNOPSIS @@ -27,8 +27,8 @@ .PP Usually, data must be in text form in order for \fBplt\fR to read them. Each non-empty, non-comment line (row) in the input should contain a -value for each column that will be plotted; if there are additional -values or other extra text at the end of a row, it will be ignored. +value for each column that will be plotted; any additional +values or other extra text at the end of a row will be ignored. Columns can be separated by any number of spaces or tabs. Commas and single or double quotation marks can also be used as column separators with current versions of \fBplt\fR, though not with older versions. @@ -352,12 +352,12 @@ .PP By default, \fBplt\fR makes an X11 screen plot. To make a printed plot, use the option \fB-T lw\fR, and pipe the output of \fBplt\fR to -\fBlwcat\fR. Under Unix or Linux, \fBlwcat\fR uses the standard +\fBlwcat\fR. Under Unix, GNU/Linux, or MacOS/X, \fBlwcat\fR uses the standard \fBlpr\fR print spooler to send \fBplt\fR's output in PostScript -format to the default printer. Under MS-Windows, or using -\fBlwcat\fR's \fB-gv\fR option under Unix or Linux, the PostScript -output is displayed on-screen using GhostScript (\fBGSView\fR under -MS-Windows, or \fBgv\fR otherwise; these programs can save the output +format to the default printer. When running with a Cygwin/bash window under +MS-Windows, or when using \fBlwcat\fR's \fB-gv\fR option under Unix or Linux, +the PostScript output is displayed on-screen using GhostScript (\fBGSView\fR +under MS-Windows, or \fBgv\fR otherwise; these programs can save the output in a file or send it to a printer). .SH EXAMPLES .PP diff -Naur wfdb-10.2.9/doc/wag-src/rdsamp.1 wfdb-10.3.0/doc/wag-src/rdsamp.1 --- wfdb-10.2.9/doc/wag-src/rdsamp.1 Wed Jul 31 13:56:28 2002 +++ wfdb-10.3.0/doc/wag-src/rdsamp.1 Thu Nov 7 22:39:54 2002 @@ -1,4 +1,4 @@ -.TH RDSAMP 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH RDSAMP 1 "7 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME rdsamp \- read WFDB signal files .SH SYNOPSIS @@ -34,6 +34,8 @@ \fB-p\fR Print times in seconds and milliseconds, and values in physical units. By default, \fBrdsamp\fR prints times in sample intervals and values in A/D units. +Use \fB-p -p\fR to obtain higher precision in the sample values +(8 decimal places rather than 3). .TP \fB-s\fR \fIsignal-list\fR Print only the signals named in the \fIsignal-list\fR (one or more input signal diff -Naur wfdb-10.2.9/doc/wag-src/rxr.1 wfdb-10.3.0/doc/wag-src/rxr.1 --- wfdb-10.2.9/doc/wag-src/rxr.1 Wed Jul 31 14:31:56 2002 +++ wfdb-10.3.0/doc/wag-src/rxr.1 Fri Nov 22 14:55:27 2002 @@ -1,4 +1,4 @@ -.TH RXR 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH RXR 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME rxr \- ANSI/AAMI-standard run-by-run annotation comparator .SH SYNOPSIS @@ -87,8 +87,8 @@ Since \fBrxr\fR performs multiple passes over its input files, it cannot be used at the end of a pipe. .SH SEE ALSO -\fBbxb\fR(1), \fBecgeval\fR(1), \fBepic\fR(1), \fBmxm\fR(1), \fBsetwfdb\fR(1), -\fBsumstats\fR(1) +\fBbxb\fR(1), \fBecgeval\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), +\fBsetwfdb\fR(1), \fBsumstats\fR(1) .PP \fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) diff -Naur wfdb-10.2.9/doc/wag-src/sigamp.1 wfdb-10.3.0/doc/wag-src/sigamp.1 --- wfdb-10.2.9/doc/wag-src/sigamp.1 Wed Jul 31 15:45:35 2002 +++ wfdb-10.3.0/doc/wag-src/sigamp.1 Mon Nov 25 23:51:37 2002 @@ -1,11 +1,11 @@ -.TH SIGAMP 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH SIGAMP 1 "25 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME sigamp \- measure signal amplitudes of a WFDB record .SH SYNOPSIS \fBsigamp -r\fR \fIrecord\fR [ \fIoptions\fR ... ] .SH DESCRIPTION .PP -\fRsigamp\fR measures either baseline-corrected RMS amplitudes or (for +\fBsigamp\fR measures either baseline-corrected RMS amplitudes or (for suitably annotated ECG signals) normal QRS peak-to-peak amplitudes for all signals of the specified \fIrecord\fR. It makes up to 300 measurements (but see \fB-n\fR below) for each signal and calculates @@ -51,7 +51,7 @@ It may be necessary to set and export the shell variable \fBWFDB\fR (see \fBsetwfdb\fR(1)). .SH SEE ALSO -\fBcalsig\fR(1), \fBsetwfdb\fR(1) +\fBcalsig\fR(1), \fBsetwfdb\fR(1), \fBsigavg\fR(1) .SH AUTHOR George B. Moody (george@mit.edu) .SH SOURCE diff -Naur wfdb-10.2.9/doc/wag-src/sigavg.1 wfdb-10.3.0/doc/wag-src/sigavg.1 --- wfdb-10.2.9/doc/wag-src/sigavg.1 Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/sigavg.1 Tue Nov 26 21:35:50 2002 @@ -0,0 +1,68 @@ +.TH SIGAVG 1 "25 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" +.SH NAME +sigavg \- calculate averages of annotated waveforms +.SH SYNOPSIS +\fBsigavg -r\fR \fIrecord\fR \fB-a\fR \fIannotator\fR [ \fIoptions\fR ... ] +.SH DESCRIPTION +.PP +A common problem in signal processing is to determine the shape of a +recurring waveform in the presence of noise. If the waveform recurs +periodically (for example, once per second) the signal can be divided +into segments of an appropriate length (one second in this example), and +the segments can be averaged to reduce the amplitude of any noise that +is uncorrelated with the signal. Typically, noise is reduced by a factor +of the square root of the number of segments included in the average. For +physiologic signals, the waveforms of interest are usually not strictly +periodic, however. \fBsigavg\fR averages such waveforms by defining segments +(averaging windows) relative to the locations of waveform annotations. +.PP +\fBsigavg\fR requires a WFDB \fIrecord\fR containing any number of signals to +be averaged, and an annotation file containing markers (fiducial points) that +define a fixed point in the averaging window for each waveform. By default, +all QRS (beat) annotations for the specified \fIannotator\fR are included in +an average that begins 50 ms before the annotation and ends 50 ms after the +annotation. The output is in text form, with times (in seconds, relative to +the annotations) of each sample in the first column, and averages for each +signal in the remaining columns. +.PP +\fIOptions\fR include: +.TP +\fB-d\fR \fIdt1 dt2\fR +Set the measurement window relative to QRS annotations. Negative values +correspond to offsets that precede the annotations. Defaults: \fIdt1\fR = +-0.05 seconds; \fIdt2\fR = 0.05 seconds. +.TP +\fB-f\fR \fItime\fR +Begin at the specified \fItime\fR in \fIrecord\fR (default: the beginning of +\fIrecord\fR). +.TP +\fB-h\fR +Print a usage summary. +.TP +\fB-H\fR +Read multifrequency records in high resolution mode (default: use low +resolution mode). +.TP +\fB-p\fR \fItype\fR [ \fItype\fR ... ] +Include annotations of the specified \fItype\fRs only (default: include all QRS +annotations). +.TP +\fB-t\fR \fItime\fR +Process until the specified \fItime\fR in \fIrecord\fR (default: the end of +the record). +.TP +\fB-v\fR +Verbose mode: print column headings above measurements. +.TP +\fB-z\fR +Set the baseline to zero before averaging. +.SH ENVIRONMENT +.PP +It may be necessary to set and export the shell variable \fBWFDB\fR (see +\fBsetwfdb\fR(1)). +.SH SEE ALSO +\fBcalsig\fR(1), \fBsetwfdb\fR(1), \fBsigamp\fR(1) +.SH AUTHOR +George B. Moody (george@mit.edu) +.SH SOURCE +http://www.physionet.org/physiotools/wfdb/app/sigavg.c diff -Naur wfdb-10.2.9/doc/wag-src/signal.5 wfdb-10.3.0/doc/wag-src/signal.5 --- wfdb-10.2.9/doc/wag-src/signal.5 Thu Aug 1 02:30:03 2002 +++ wfdb-10.3.0/doc/wag-src/signal.5 Mon Oct 28 17:37:20 2002 @@ -1,6 +1,6 @@ .TH SIGNAL 5 "1 August 2002" "WFDB software 10.2.7" "WFDB Applications Guide" .SH NAME -signal \- Waveform Database signal file formats +signal \- WFDB signal file formats .SH DESCRIPTION WFDB signal files exist in several formats. Any of these formats can be used for multiplexed signal files, in which samples from two or more diff -Naur wfdb-10.2.9/doc/wag-src/sqrs.1 wfdb-10.3.0/doc/wag-src/sqrs.1 --- wfdb-10.2.9/doc/wag-src/sqrs.1 Wed Jul 31 23:15:25 2002 +++ wfdb-10.3.0/doc/wag-src/sqrs.1 Fri Nov 22 15:11:19 2002 @@ -1,6 +1,6 @@ -.TH SQRS 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH SQRS 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME -sqrs \- single-channel QRS detector +sqrs, sqrs125 \- single-channel QRS detector .SH SYNOPSIS \fBsqrs -r\fR \fIrecord\fR [ \fIoptions\fR ... ] .br @@ -83,7 +83,7 @@ .br \fBbxb -r 100 -a atr qrs\fR .SH SEE ALSO -\fBbxb\fR(1), \fBrdann\fR(1), \fBsetwfdb\fR(1), \fBxform\fR(1) +\fBbxb\fR(1), \fBrdann\fR(1), \fBsetwfdb\fR(1), \fBwqrs\fR(1), \fBxform\fR(1) .SH AUTHORS George B. Moody (george@mit.edu). This program is a fairly literal translation with minor corrections of the Pascal original by WAH Engelse and diff -Naur wfdb-10.2.9/doc/wag-src/sumstats.1 wfdb-10.3.0/doc/wag-src/sumstats.1 --- wfdb-10.2.9/doc/wag-src/sumstats.1 Wed Jul 31 23:22:17 2002 +++ wfdb-10.3.0/doc/wag-src/sumstats.1 Fri Nov 22 14:52:46 2002 @@ -1,4 +1,4 @@ -.TH SUMSTATS 1 "31 July 2002" "WFDB 10.2.7" "WFDB Applications Guide" +.TH SUMSTATS 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" .SH NAME sumstats \- derive aggregate statistics from bxb, rxr, etc., line-format output .SH SYNOPSIS @@ -13,14 +13,14 @@ electrocardiographs\fR (ANSI/AAMI EC38:1998). .PP To use this program, first generate a line-format report \fIfile\fR using the -\fB-l\fR or \fB-L\fR options of \fBbxb\fR(1), \fBepic\fR(1), \fBmxm\fR(1), or +\fB-l\fR or \fB-L\fR options of \fBbxb\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), or \fBrxr\fR(1). This file must include column headings so that \fBsumstats\fR can recognize the file type. Output is written to the standard output; it includes a copy of the input file, with aggregate statistics appended at the end. .SH SEE ALSO -\fBbxb\fR(1), \fBecgeval\fR(1), \fBepic\fR(1), \fBmxm\fR(1), \fBplotstm\fR(1), -\fBrxr\fR(1) +\fBbxb\fR(1), \fBecgeval\fR(1), \fBepicmp\fR(1), \fBmxm\fR(1), +\fBplotstm\fR(1), \fBrxr\fR(1) .HP \fIEvaluating ECG Analyzers\fR (in the \fIWFDB Applications Guide\fR) .HP diff -Naur wfdb-10.2.9/doc/wag-src/wag.ht0 wfdb-10.3.0/doc/wag-src/wag.ht0 --- wfdb-10.2.9/doc/wag-src/wag.ht0 Thu Aug 1 14:35:14 2002 +++ wfdb-10.3.0/doc/wag-src/wag.ht0 Tue Oct 29 10:00:30 2002 @@ -52,155 +52,3 @@

            Contents

            Introduction

            FAQ

            -

            Applications

            -
              -
            • a2m, ad2m, ahaconvert, m2a, md2a: converting - between MIT and AHA DB formats -
            • ann2rr, rr2ann: convert annotation files to - interval lists and vice versa -
            • bxb: ANSI/AAMI-standard beat-by-beat annotation - comparator -
            • calsig: calibrate signals of a WFDB record -
            • coherence: estimate coherence and - cross-spectrum of two time series -
            • dfa: detrended fluctuation analysis -
            • ecgeval: generate and run ECG analyzer - evaluation script -
            • edf2mit: converting from EDF to MIT format -
            • epic: ANSI/AAMI-standard episode-by-episode - annotation comparator -
            • fft: fast Fourier transform -
            • fir: general-purpose FIR filter for WFDB records -
            • hrfft, hrlomb, hrmem, hrplot: calculate and - plot heart rate power spectra -
            • ihr: calculate instantaneous heart rate -
            • log10: calculate common logarithms of - two-column data -
            • lomb: estimate power spectrum using the Lomb - periodogram method -
            • memse: estimate power spectrum using the - maximum entropy (all poles) method -
            • mfilt: general-purpose median filter for WFDB - records -
            • mrgann: merge annotation files -
            • mxm: ANSI/AAMI-standard - measurement-by-measurement comparator -
            • nst: noise stress test for ECG analysis programs -
            • plot2d, plot3d: make 2-D or 3-D plots from - text files of data, using gnuplot -
            • plotstm: produce scatter plot of ST measurement - errors on a PostScript device -
            • plt: make 2-D plots -
            • pschart: produce annotated `chart recordings' - on a PostScript device -
            • psfd: produce annotated `full disclosure' plots - on a PostScript device -
            • rdann: read a WFDB annotation file -
            • rdsamp: read WFDB signal files -
            • rxr: ANSI/AAMI-standard run-by-run annotation - comparator -
            • sampfreq: show sampling frequency for a record -
            • sample: digitize and replay analog signals - (MS-DOS only) -
            • setwfdb, cshsetwfdb: set WFDB environment - variables -
            • sigamp: measure signal amplitudes of a WFDB - record -
            • skewedit: edit skew fields of header file(s) -
            • snip: copy an excerpt of a WFDB record -
            • sortann: rearrange annotations in canonical - order -
            • sqrs, sqrs125: single-channel QRS detector -
            • sumann: summarize the contents of a WFDB - annotation file -
            • sumstats: derive aggregate statistics from - bxb, rxr, etc., line-format output -
            • tach: heart rate tachometer -
            • view, vsetup: WFDB browser for MS-DOS -
            • wave, gtkwave: waveform analyzer, viewer, and - editor -
            • wfdbcat: copy WFDB files to standard output -
            • wfdbcollate: collate WFDB records into a - multi-segment record -
            • wfdb-config: print WFDB library info -
            • wfdbdesc: read signal specifications -
            • wfdbwhich: find a WFDB file and print its - pathname -
            • wrann: write a WFDB annotation file -
            • wrsamp: write WFDB signal files -
            • wview: WFDB browser for MS Windows -
            • xform: sampling frequency, amplitude, and - format conversion for WFDB records -
            -

            Functions

            -
              -
            • wfdb: Waveform Database library -
            • wfdbf: Waveform Database library bindings for - Fortran -
            -

            File formats

            -
              -
            • annot: WFDB annotation file format -
            • header: WFDB header file format -
            • signal: WFDB signal file format -
            • wfdbcal: WFDB calibration file format -
            -

            Miscellaneous

            -
              -
            • xview: XView toolkit information -
            -

            Appendices

            - -

            -

            Other links of interest

            -
              -
            • PhysioNet
              -PhysioNet offers free access via the web to large collections of -recorded physiologic signals and related open-source software. -PhysioNet is a public service of the Research Resource for -Complex Physiologic Signals, funded by the National Center for -Research Resources of the National Institutes of Health. -The most recent version of this guide, and of the software it -describes, may be obtained from PhysioNet. -
            • The MIT-BIH Database Distribution -Home Page
              -Information about obtaining CD-ROMs containing many of the databases -available from PhysioNet can be found here. -
            • WFDB Programmer's Guide -
              -Includes tutorial and reference material relating to the WFDB library, -a portable set of functions (subroutines) for reading and writing files in the -formats supported by the applications described here. The WFDB library may be -used with C, C++, or Fortran programs; the guide primarily describes the C -interface. -
            • WAVE User's Guide
              -A comprehensive tutorial, with extensive reference material, for -WAVE, an interactive waveform browser with facilities for -annotation editing and control of external analysis programs. -WAVE runs on PCs under the free Linux operating system, and -on SPARC-based systems under SunOS or Solaris. -
            -
            - -
            - -

            -Please e-mail your comments and suggestions to -webmaster@physionet.org, -or post them to: -

            -

            -PhysioNet
            -MIT Room E25-505A
            -77 Massachusetts Avenue
            -Cambridge, MA 02139 USA
            -

            -Updated - -LONGDATE - - - diff -Naur wfdb-10.2.9/doc/wag-src/wag.ht1 wfdb-10.3.0/doc/wag-src/wag.ht1 --- wfdb-10.2.9/doc/wag-src/wag.ht1 Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/wag.ht1 Tue Oct 29 09:05:44 2002 @@ -0,0 +1,55 @@ +

            Appendices

            + +

            +

            Other links of interest

            +
              +
            • PhysioNet
              +PhysioNet offers free access via the web to large collections of +recorded physiologic signals and related open-source software. +PhysioNet is a public service of the Research Resource for +Complex Physiologic Signals, funded by the National Center for +Research Resources of the National Institutes of Health. +The most recent version of this guide, and of the software it +describes, may be obtained from PhysioNet. +
            • The MIT-BIH Database Distribution +Home Page
              +Information about obtaining CD-ROMs containing many of the databases +available from PhysioNet can be found here. +
            • WFDB Programmer's Guide +
              +Includes tutorial and reference material relating to the WFDB library, +a portable set of functions (subroutines) for reading and writing files in the +formats supported by the applications described here. The WFDB library may be +used with C, C++, or Fortran programs; the guide primarily describes the C +interface. +
            • WAVE User's Guide
              +A comprehensive tutorial, with extensive reference material, for +WAVE, an interactive waveform browser with facilities for +annotation editing and control of external analysis programs. +WAVE runs on PCs under the free Linux operating system, and +on SPARC-based systems under SunOS or Solaris. +
            +
            + +
            + +

            +Please e-mail your comments and suggestions to +webmaster@physionet.org, +or post them to: +

            +

            +PhysioNet
            +MIT Room E25-505A
            +77 Massachusetts Avenue
            +Cambridge, MA 02139 USA
            +

            +Updated + +LONGDATE + + + diff -Naur wfdb-10.2.9/doc/wag-src/wag.tex wfdb-10.3.0/doc/wag-src/wag.tex --- wfdb-10.2.9/doc/wag-src/wag.tex Tue Aug 6 10:32:00 2002 +++ wfdb-10.3.0/doc/wag-src/wag.tex Tue Oct 29 15:36:11 2002 @@ -1,7 +1,23 @@ \documentclass[twoside]{book} +\nofiles \usepackage{rawfonts} \IfFileExists{times.sty}{\usepackage{times}}{\@missingfileerror{times}{sty}} + +\usepackage{fancyheadings} +\oddsidemargin 0.1in +\evensidemargin -0.1in +\topmargin -0.5in +\textheight 650pt +\footskip 48pt +\def\textwidth{6.375 in} \pagenumbering{roman} +\def\headrulewidth{0pt} +\lhead{\rm{}Contents} +\chead{\rm{}WFDB Applications Guide} +\rhead{\rm{}Contents} +\lfoot[\rm\thepage]{\rm{}WFDB VERSION} +\cfoot{\rm{}LONGDATE} +\rfoot[\rm{}WFDB VERSION]{\rm\thepage} \title{WFDB Applications Guide} \author{Tenth Edition\\ @@ -25,7 +41,8 @@ \vspace{1 in} \noindent The most recent versions of the software described in this guide may be -freely downloaded from PhysioNet ({\tt http://www.physionet.org/}). +freely downloaded from PhysioNet\\ +({\tt http://www.physionet.org/}). For further information, write to: \begin{quote} @@ -57,4 +74,321 @@ \noindent Permission is granted to copy and distribute translations of this guide into another language, under the above conditions for modified versions. + +\newpage +\pagestyle{fancyplain} + +\tableofcontents + +\newpage +\lhead{\rm{}Introduction} +\chead{\rm{}WFDB Applications Guide} +\rhead{\rm{}Introduction} + + +\chapter*{Introduction} + +Most of this guide consists of UNIX \textbf{man} pages that describe the +applications included in the WFDB (Waveform Database) Software +Package (and related software from PhysioToolkit). This introduction +contains important information about how to interpret the material in +the main sections of the guide, and about common conventions for using +all of the WFDB applications that are not described in the main sections. +The FAQ that follows this introduction contains additional information +that will be particularly helpful if you are using MS-Windows (but it +may be of interest even if you are not). + +\section*{Using this Guide} + +The organization follows the traditional arrangement of the UNIX Reference +Manual: section 1 contains programs, section 3 contains libraries, and +section 5 contains file formats. In the UNIX Reference Manual, sections +2 and 4 are reserved for system calls and device interfaces respectively; +these sections do not exist in this guide. Following convention, a +citation such as \textbf{rdann}(1) refers to the page titled \textbf{rdann} +in section 1 of this guide. + +A \textbf{man} "page" may span more than one physical page, although most do +not. Each \textbf{man} page in section 1 of this guide documents one or more +applications, as indicated in the \textbf{NAME} section at the top. The +\textbf{SYNOPSIS} appears next; it illustrates the form of the command line +needed to run the application. In the synopsis, \textbf{boldface} indicates +text to be typed as is, and \textit{italics} indicate replaceable arguments; +brackets ([], which are \textit{not} to be typed) surround arguments that may +be omitted, and ellipses (...) follow arguments that can be repeated. The +\textbf{DESCRIPTION} sections are intentionally terse; this is a reference +manual and not a tutorial introduction to the software described within. In +those cases for which relevant tutorial material exists elsewhere, references +appear in the \textbf{SEE ALSO} sections of each \textbf{man} page. A unique +feature of this guide is the \textbf{SOURCE} section at the end of each page, +which provides a URL where you may find the current version of the source(s) +for each application. + +On each page, the footer indicates the date when that page was last revised, +and (in most cases) the version of the WFDB Software Package that was current +at that time. An old date and version number do not mean that the page is +out-of-date; rather they mean that the material described on that page +remains current. + +Under GNU/Linux or Unix, if the WFDB Software Package has been installed +on your system, you can also access the information contained in the +main sections of this guide using \textbf{man} and related programs. For +example, to see the manual page for \textbf{rdsamp}, run the command +\begin{quote} + \textbf{man rdsamp} +\end{quote} +(This also works under MS-Windows if you have installed the +Cygwin package, which includes the \textbf{man} utility for formatting +and reading manual pages.) In some cases you may need to add +\textbf{/usr/local/man} to your \textbf{MANPATH} environment variable, in +order to make these pages accessible to \textbf{man}. + +An HTML version of this guide is also available (at +\textbf{http://www.physionet.org/physiotools/wag/} ). + +\section*{Using WFDB Applications} + +If you have not used any of these programs before, you may need to set up +your environment properly so that WFDB applications can find their +input files. See \textbf{setwfdb}(1) in this guide for information about +doing this; a more detailed discussion may be found in the first chapter +of the \textit{WFDB Programmer's Guide}, in the section about the database +path. + +Certain types of command-line arguments are used by many of the applications +described in this guide. These include: + +\begin{description} +\item{\textit{record}} + +Where this appears, substitute the name of a WFDB record. \textbf{A record +name is \textit{not} a file name!} The first part of the name of a .hea +file is the name of the record to which the .hea file belongs; so the +record name corresponding to `100.hea' is `100'. For example, MIT-BIH +Arrhythmia Database record names are 3-digit numbers, AHA Database +record names are 4-digit numbers, and European ST-T Database record +names begin with lowercase `e', followed by a 4-digit number. Record +names may contain letters, digits, and underscores. Case is significant in +record names that contain letters, even in environments such as +MS-Windows for which case translation is normally performed by the +operating system on file names; thus `e0104' is the name of a record +found in the European ST-T Database, whereas `E0104' is not. Once +again: a record name is \textbf{not} a file name; record names never +include an extension (.hea, .dat, etc.). + +Wherever a record name can be supplied to a WFDB application, you may include +path information if necessary. For example, if the WFDB path includes the +current directory, and if the current directory includes a subdirectory named +`my\_records', and that directory contains a record named `record\_23', you can +supply `my\_records/record\_23' as a \textit{record} argument. See the +\textit{WFDB Programmer's Guide} for further details on record names. + +Each PhysioBank database directory includes a text file named \textbf{RECORDS}, +which lists the record names for all records in that directory. + +\item{\textit{annotator}} + +Where this appears, substitute an annotator name. \textbf{Annotator names are +\textit{not} file names!} The suffix (extension) of the name of an +annotation file is the annotator name for that file; so, for example, the +annotator name for `e0104.atr' is `atr'. The special annotator name `atr' is +used to name the set of \textit{reference annotations} supplied by the database +developers. Other annotation sets have annotator names that may contain +letters, digits, and underscores, as for record names. + +Each PhysioBank database directory includes a text file named +\textbf{ANNOTATORS}, which lists the annotator names for all annotation files +in that directory. + +\item{\textit{time}} + +Where this appears, substitute a string in \textit{standard time format}. +\textit{Time} arguments generally specify elapsed times from the beginning +of the record (for exceptions to this rule, see the section on the +\textbf{strtim} function in the \textit{WFDB Programmer's Guide}). Examples +of standard time format: + +\begin{center} +\begin{tabular}{lr} +2:14.875 & 2 minutes + 14.875 seconds \\ +143 & 143 seconds (2 minutes + 23 seconds) \\ +4:02:01 & 4 hours + 2 minutes + 1 second \\ +4:2:1 & same as above \\ +s12345 & 12345 sample intervals \\ +e & time of the end of the record \\ +\end{tabular} +\end{center} + +\item{\textit{signal}} + +Where this appears, substitute a signal number. Signal numbers are integers; +the first signal in each record is signal 0. In printed documentation for +the databases, signals always appear with signal 0 at the top, signal 1 +beneath, etc. + +\item{\textit{signal-list}} + +Where this (or `\textit{signal ...}') appears, you may specify more than one +signal in any desired order; separate the signal numbers using spaces. +Unless otherwise noted, a signal may appear more than once, or not at all, +in a signal list. In most cases, the end of the signal list is unambiguous +(since signal numbers are never negative, an option argument beginning +with '-' is a reliable indicator). In unusual cases, you may need to arrange +options so that the signal list is at the end of the command, or so that it +is followed by an argument that cannot be interpreted as a signal number. +\end{description} + +\chapter*{Frequently Asked Questions\\(and Frequently Exclaimed Exclamations)} +\lhead{\rm{}FAQ} +\rhead{\rm{}FAQ} + +\noindent +{\large +\textbf{I double-clicked on the program icon, and nothing happens!}\\ +\textbf{I typed the program name in the 'Run...' dialog, and nothing happens!}} + +\noindent +Don't do this! + +With few exceptions, PhysioToolkit applications run in \textbf{text mode} +(i.e., they do not include a graphical user interface). These programs are +intended to be run within a terminal emulator using a command-line interface. +In most cases, if you attempt to run them by clicking on their icons or names, +or by entering the program name in the MS-Windows \textbf{Run...} dialog box, +these programs will open a DOS box, print a usage summary, and exit, usually +much too fast for you to read anything. + +By far the best way to use these programs under MS-Windows is to install a +Unix-compatible terminal emulator and shell in which to run them. The best of +these is also free; if you have not already done so, download and install the +Cygwin software package from \textbf{http://www.cygwin.com/}. This package +includes \textbf{bash}, the GNU Bourne Again Shell and a terminal emulator in +which to run it. After a standard installation of Cygwin, you can launch a +terminal emulator and \textbf{bash} by clicking on the Cygwin icon that will +have been installed on your desktop. + +If you do not wish to use Cygwin, it is possible to run these applications +within a DOS box, but there are many limitations of \textbf{command.com} that +may prove frustrating. In particular, \textbf{command.com} supports a +relatively small space for environment variables that is not secure against +buffer overruns, and has idiosyncratic filename globbing behavior. + +\vspace{5mm} +\noindent +{\large \textbf{What does the message "init: can't open header for ..." mean?}} + +\noindent +This message can be produced by any application linked to the WFDB +library, including \textbf{rdsamp}(1) and \textbf{rdann}(1). In order to +read data files, these applications need to find a header (\textbf{.hea}) +file for the input record you specify. The message indicates that the header +file was not found in any of the expected places, or that it was +unreadable. There are three common reasons why this can happen: + +\begin{itemize} +\item +The \textit{record} name supplied to the application is not correct. Record +names are \textbf{not} file names (if this doesn't sound familiar yet, go back +and read the introduction again). If you wish to read, for example, a signal +file named \textbf{slp60.dat} using \textbf{rdsamp}, you must specify the name +of the record to which this file belongs (\textbf{slp60}) after the \textbf{-r} +option, and not the name of the file itself. Whatever follows "init: can't +open header for ..." is what the application thinks is the name of the record +you wish to read. Also, be aware that case matters in record names, even under +operating systems that ignore case in file names. Thus "\textbf{SLP60}" is not +a valid record name; "\textbf{slp60}" is. + +\item +The header file is missing. If you download signal (\textbf{.dat}) or +annotation (\textbf{.atr}, \textbf{.qrs}, etc.) files, be sure to download +the corresponding \textbf{.hea} files from the same locations. + +\item +The list of locations to be searched does not include the location of +the header file. WFDB applications find their input files by searching +a list of locations specified by the WFDB path (the environment variable +\textbf{WFDB}, or a default list of locations if WFDB has not been set). The +WFDB path normally includes the current directory, but this may not be +true if the WFDB path has been modified; the current directory must +appear explicitly (either as a "." or as an empty component in the path) +in order to be included in the list of locations to be searched. For +further information, see "The Database Path and Other Environment Variables" +in the \textit{WFDB Programmer's Guide}. +\end{itemize} + +\vspace{5mm} +\noindent +{\large \textbf{How can I save the output of ... in a file?} \\ +\textbf{How can one program read another's output?}} + +\noindent +If you are running programs from a command prompt (by typing commands into a +terminal emulator window or an MS-DOS box), these things can be done easily. + +If you have ever used GNU/Linux, Unix, or MS-DOS, you may have captured the +output of a program by \textit{redirecting} it to a file, like this: +\begin{quote} +\textbf{foo $>$bar} +\end{quote} + +The $>$ operator redirects \textbf{foo}'s standard output (which would normally +appear on-screen) into a file named \textbf{bar}. If \textbf{bar} exists +already, its contents are replaced. If you wish to append \textbf{foo}'s output +to whatever is already contained in \textbf{bar}, use a command such as this +instead: +\begin{quote} +\textbf{foo $>>$bar} +\end{quote} + +There is an analogous operator that arranges for a program's standard input +(which would normally be read from whatever you type on the keyboard) to be +read from a file instead: +\begin{quote} +\textbf{baz $<$bar} +\end{quote} + +Here, the $<$ operator arranges for \textbf{baz} to read its input from a file +named \textbf{bar}. If \textbf{bar} was created by \textbf{foo}, then this +command allows \textbf{baz} to read \textbf{foo}'s output. + +You can combine input and output redirection in a single command using the pipe +($|$) operator: +\begin{quote} +\textbf{foo $|$ baz} +\end{quote} + +This command runs \textbf{foo} and sends its standard output directly to +\textbf{baz}, without requiring an intermediate file. True multitasking +operating systems such as Unix and GNU/Linux allow both programs to run +(apparently) simultaneously; under MS-DOS or MS-Windows, the first program runs +to completion before the second one begins execution. + +You can use these techniques whenever you run programs from a command prompt, +whether those programs are among those available here or obtained from some +other source. You can use the same techniques with programs you write yourself; +the only requirement is that your programs must read from the standard input +and write to the standard output (i.e., they must not attempt to bypass the +standard input/output mechanism by reading directly from the keyboard or +writing directly to the screen). + +These operators ($>$, $>>$, $<$, and $|$) are supported by all shells (command +interpreters) under Unix, GNU/Linux, and MS-DOS (including those that run +within MS-DOS boxes or other types of terminal emulators under MS-Windows). For +further information, please refer to the documentation for your shell or +command interpreter. + +\vspace{5mm} +\noindent +{\large +\textbf{Where else can I find answers to my questions about this software?}} + +\noindent +If you haven't read the introduction to this guide yet, do so now. It answers +many frequently asked questions by describing the common behavior of many of +the WFDB applications. It also describes the typographic and organizational +conventions used in the remainder of this guide. + +Many more questions are asked and answered in the PhysioNet FAQ +(http://www.physionet.org/faq.shtml). + \end{document} diff -Naur wfdb-10.2.9/doc/wag-src/wfdbcal.5 wfdb-10.3.0/doc/wag-src/wfdbcal.5 --- wfdb-10.2.9/doc/wag-src/wfdbcal.5 Thu Aug 1 02:37:12 2002 +++ wfdb-10.3.0/doc/wag-src/wfdbcal.5 Mon Oct 28 17:37:09 2002 @@ -1,6 +1,6 @@ .TH WFDBCAL 5 "1 August 2002" "WFDB software 10.2.7" "WFDB Applications Guide" .SH NAME -wfdbcal \- Waveform Database calibration file format +wfdbcal \- WFDB calibration file format .SH DESCRIPTION .PP Programs compiled using the WFDB library (see \fBwfdb\fR(3)) require diff -Naur wfdb-10.2.9/doc/wag-src/wfdbdesc.1 wfdb-10.3.0/doc/wag-src/wfdbdesc.1 --- wfdb-10.2.9/doc/wag-src/wfdbdesc.1 Thu Aug 1 01:05:18 2002 +++ wfdb-10.3.0/doc/wag-src/wfdbdesc.1 Thu Oct 31 11:00:05 2002 @@ -1,4 +1,4 @@ -.TH WFDBDESC 1 "30 May 2002" "WFDB software 10.2.6" "WFDB applications" +.TH WFDBDESC 1 "30 May 2002" "WFDB 10.2.6" "WFDB Applications Guide" .SH NAME wfdbdesc \- read signal specifications .SH SYNOPSIS diff -Naur wfdb-10.2.9/doc/wag-src/wqrs.1 wfdb-10.3.0/doc/wag-src/wqrs.1 --- wfdb-10.2.9/doc/wag-src/wqrs.1 Wed Dec 31 19:00:00 1969 +++ wfdb-10.3.0/doc/wag-src/wqrs.1 Fri Nov 22 15:06:46 2002 @@ -0,0 +1,98 @@ +.TH WQRS 1 "22 November 2002" "WFDB 10.3.0" "WFDB Applications Guide" +.SH NAME +wqrs \- single-channel QRS detector based on length transform +.SH SYNOPSIS +\fBwqrs -r\fR \fIrecord\fR [ \fIoptions\fR ... ] +.SH DESCRIPTION +.PP +\fBwqrs\fR attempts to locate QRS complexes in an ECG signal in the +specified \fIrecord\fR. The detector algorithm is based on the length +transform. The output of \fBwqrs\fR is an annotation file (with +annotator name \fBwqrs\fR) in which all detected beats are labelled +normal; the annotation file will also contain optional J-point +annotations if the \fB-j\fR option (see below) is used. +.PP +\fBwqrs\fR can process records containing any number of signals, but +it uses only one signal for QRS detection (signal 0 by default; this +can be changed using the \fB-s\fR option, see below). \fBwqrs\fR is +optimized for use with adult human ECGs. For other ECGs, it may be +necessary to experiment with the sampling frequency as recorded in the +input record's header file (see \fBheader\fR(5)), the detector threshold +(which can be set using the \fB-m\fR option), and the time constants +indicated in the source file. +.PP +\fBwqrs\fR optionally uses the WFDB library's \fIsetifreq\fR function +to resample the input signal at 120 or 150 Hz (depending on the mains +frequency, which can be specified using the \fB-p\fR option). \fBwqrs\fR +performs well using input sampled at a range of rates up to 360 Hz and +possibly higher rates, but it has been designed and tested to work best +on signals sampled at 120 or 150 Hz. +.PP +\fIOptions\fR include: +.TP +\fB-d\fR +Dump the raw and length-transformed input samples in text format on the +standard output, but do not detect or annotate QRS complexes. +.TP +\fB-f\fR \fItime\fR +Begin at the specified \fItime\fR in \fIrecord\fR (default: the beginning of +\fIrecord\fR). +.TP +\fB-h\fR +Print a brief usage summary. +.TP +\fB-j\fR +Find and annotate J-points (QRS ends) as well as QRS onsets. +.TP +\fB-m\fR \fIthreshold\fR +Specify the detection \fIthreshold\fR (default: 100 microvolts); use higher +values to reduce false detections, or lower values to reduce the number of +missed beats. +.TP +\fB-p\fR \fIfrequency\fR +Specify the power line (mains) frequency used at the time of the recording, +in Hz (default: 60). \fBwqrs\fR will apply a notch filter of the specified +frequency to the input signal before length-transforming it. +.TP +\fB-R\fR +Resample the input at 120 Hz if the power line frequency is 60 Hz, or at +150 Hz otherwise. +.TP +\fB-s\fR \fIsignal\fR +Specify the \fIsignal\fR to be used for QRS detection (default: 0). +.TP +\fB-t\fR \fItime\fR +Process until the specified \fItime\fR in \fIrecord\fR (default: the end of the +\fIrecord\fR). +.TP +\fB-v\fR +Verbose mode: print information about the detector parameters. +.SH ENVIRONMENT +.PP +It may be necessary to set and export the shell variable \fBWFDB\fR (see +\fBsetwfdb\fR(1)). +.SH EXAMPLES +.PP +To mark QRS complexes in record 100 beginning 5 minutes from the start, ending +10 minutes and 35 seconds from the start, and using signal 1, use the command: +.br + \fBwqrs -r 100 -f 5:0 -t 10:35 -s 1\fR +.br +The output annotations may be read using (for example): +.br + \fBrdann -a wqrs -r 100\fR +.PP +To evaluate the performance of this program, run it on the entire record, by: +.br + \fBwqrs -r 100\fR +.br +and then compare its output with the reference annotations by: +.br + \fBbxb -r 100 -a atr wqrs\fR +.SH SEE ALSO +\fBbxb\fR(1), \fBecgpuwave\fR(1), \fBrdann\fR(1), \fBsetwfdb\fR(1), +\fBsqrs\fR(1) +.SH AUTHORS +Wei Zong (wzong@mit.edu) and George B. Moody (george@mit.edu). +.SH SOURCE +http://www.physionet.org/physiotools/wfdb/app/wqrs.c diff -Naur wfdb-10.2.9/doc/wpg/info/wpg wfdb-10.3.0/doc/wpg/info/wpg --- wfdb-10.2.9/doc/wpg/info/wpg Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg Tue Nov 26 02:06:55 2002 @@ -8,143 +8,145 @@  Indirect: wpg-1: 185 -wpg-2: 45795 -wpg-3: 94697 -wpg-4: 144138 -wpg-5: 192801 -wpg-6: 240952 -wpg-7: 285159 -wpg-8: 309751 +wpg-2: 47452 +wpg-3: 92902 +wpg-4: 138990 +wpg-5: 187735 +wpg-6: 234549 +wpg-7: 283495 +wpg-8: 312609  Tag Table: (Indirect) Node: Top185 -Node: Overview2015 -Node: Concepts 14383 -Node: Concepts 26370 -Node: Concepts 38349 -Node: Applications10301 -Node: Guide12192 -Node: Recent changes19538 -Node: Usage30471 -Node: print samples31512 -Node: compiling33181 -Node: other languages37957 -Node: WFDB path41409 -Node: running example44084 -Node: name restrictions44758 -Node: WFDB path syntax45795 -Node: exercises 151836 -Node: Functions54241 -Node: introduction to functions55232 -Node: selecting58137 -Node: annopen58560 -Node: isigopen61165 -Node: osigopen65823 -Node: osigfopen68037 -Node: wfdbinit69693 -Node: special input modes70978 -Node: setifreq71458 -Node: getifreq73667 -Node: setgvmode74152 -Node: getspf75627 -Node: signal and annotation I/O76170 -Node: getvec76653 -Node: getframe79449 -Node: putvec80772 -Node: getann82896 -Node: ungetann84365 -Node: putann85061 -Node: non-sequential86095 -Node: isigsettime86597 -Node: isgsettime87330 -Node: iannsettime87838 -Node: conversion89032 -Node: annstr and strann89662 -Node: timstr and strtim94697 -Node: datstr and strdat99447 -Node: aduphys and physadu100487 -Node: calibration103073 -Node: calopen103737 -Node: getcal104633 -Node: putcal105832 -Node: newcal106194 -Node: flushcal106713 -Node: miscellaneous functions107059 -Node: newheader108626 -Node: setheader109928 -Node: setmsheader111492 -Node: wfdbquit113032 -Node: iannclose and oannclose114232 -Node: wfdbquiet and wfdbverbose115123 -Node: wfdberror115613 -Node: sampfreq116604 -Node: setsampfreq117532 -Node: setbasetime118068 -Node: counter conversion118900 -Node: setwfdb121508 -Node: getwfdb124020 -Node: wfdbfile124744 -Node: wfdbflush125870 -Node: getinfo126165 -Node: putinfo127042 -Node: setibsize127783 -Node: setobsize128785 -Node: wfdbgetskew129807 -Node: wfdbsetskew131372 -Node: wfdbgetstart132014 -Node: wfdbsetstart133116 -Node: Data Types133754 -Node: WFDB_Siginfo structures135750 -Node: WFDB_Calinfo structures142093 -Node: WFDB_Anninfo structures144138 -Node: WFDB_Annotation structures146894 -Node: Annotation Codes149778 -Node: Mapping macros154438 -Node: Database Files156385 -Node: Header Files159072 -Node: Signal Files159939 -Node: Annotation Files160758 -Node: Calibration Files161167 -Node: AHA Format Files161932 -Node: Standard I/O163401 -Node: Multiplexed Signal Files164645 -Node: Multi-Frequency Records165826 -Node: Multi-Segment Records169076 -Node: Multiple Record Access171029 -Node: Special Files172474 -Node: Piped and Local Records175378 -Node: NETFILES177229 -Node: Annotation Order179854 -Node: Examples183257 -Node: Example 1184495 -Node: Example 2188549 -Node: Example 3190889 -Node: Example 4192801 -Node: Example 5195781 -Node: Example 6199997 -Node: Example 7203197 -Node: Example 8210174 -Node: Example 9218537 -Node: Example 10225305 -Node: Exercises232745 -Node: Glossary240952 -Node: Installation261287 -Node: Distribution262180 -Node: Unix installation262727 -Node: MS-Windows installation265124 -Node: Other installation268113 -Node: WFDB Applications269272 -Node: Using270268 -Node: Annotation I/O272073 -Node: Evaluation273714 -Node: Signal processing280637 -Node: Graphics283629 -Node: Extensions285159 -Node: Sources294023 -Node: Answers305989 -Node: Concept Index309751 -Node: Function and Macro Index340071 -Node: Copying345018 +Node: Overview2016 +Node: Concepts 14384 +Node: Concepts 26371 +Node: Concepts 38350 +Node: Applications10302 +Node: Guide12193 +Node: Recent changes19539 +Node: Usage32128 +Node: print samples33169 +Node: compiling34838 +Node: other languages39614 +Node: WFDB path43066 +Node: running example45741 +Node: name restrictions46415 +Node: WFDB path syntax47452 +Node: exercises 153493 +Node: Functions55898 +Node: introduction to functions56889 +Node: selecting59794 +Node: annopen60217 +Node: isigopen62822 +Node: osigopen67455 +Node: osigfopen69669 +Node: wfdbinit71325 +Node: special input modes72610 +Node: setifreq73090 +Node: getifreq75299 +Node: setgvmode75784 +Node: getspf77259 +Node: signal and annotation I/O77802 +Node: getvec78285 +Node: getframe81081 +Node: putvec82404 +Node: getann84528 +Node: ungetann85998 +Node: putann86694 +Node: non-sequential87728 +Node: isigsettime88287 +Node: isgsettime89020 +Node: iannsettime89528 +Node: sample90737 +Node: conversion92272 +Node: annstr and strann92902 +Node: timstr and strtim97937 +Node: datstr and strdat102687 +Node: aduphys and physadu103727 +Node: calibration106313 +Node: calopen106977 +Node: getcal107873 +Node: putcal109072 +Node: newcal109434 +Node: flushcal109953 +Node: miscellaneous functions110299 +Node: newheader111866 +Node: setheader113168 +Node: setmsheader114732 +Node: wfdbquit116272 +Node: iannclose and oannclose117472 +Node: wfdbquiet and wfdbverbose118363 +Node: wfdberror118853 +Node: sampfreq119844 +Node: setsampfreq120772 +Node: setbasetime121308 +Node: counter conversion122140 +Node: setwfdb124748 +Node: getwfdb127260 +Node: wfdbfile127984 +Node: wfdbflush129110 +Node: getinfo129405 +Node: putinfo130282 +Node: setibsize131023 +Node: setobsize132025 +Node: wfdbgetskew133047 +Node: wfdbsetskew134612 +Node: wfdbgetstart135254 +Node: wfdbsetstart136356 +Node: Data Types136994 +Node: WFDB_Siginfo structures138990 +Node: WFDB_Calinfo structures145333 +Node: WFDB_Anninfo structures147378 +Node: WFDB_Annotation structures150134 +Node: Annotation Codes153018 +Node: Mapping macros157678 +Node: Database Files159625 +Node: Header Files162312 +Node: Signal Files163179 +Node: Annotation Files163998 +Node: Calibration Files164407 +Node: AHA Format Files165172 +Node: Standard I/O166641 +Node: Multiplexed Signal Files167885 +Node: Multi-Frequency Records169066 +Node: Multi-Segment Records172316 +Node: Multiple Record Access174269 +Node: Special Files175714 +Node: Piped and Local Records178618 +Node: NETFILES180469 +Node: Annotation Order183094 +Node: Examples186497 +Node: Example 1187735 +Node: Example 2191789 +Node: Example 3194129 +Node: Example 4196041 +Node: Example 5199021 +Node: Example 6203237 +Node: Example 7206437 +Node: Example 8211978 +Node: Example 9220341 +Node: Example 10227109 +Node: Exercises234549 +Node: Glossary242756 +Node: Installation263091 +Node: Distribution264074 +Node: Unix installation264621 +Node: MacOS/X installation267015 +Node: MS-Windows installation267979 +Node: Other installation270971 +Node: WFDB Applications272130 +Node: Using273126 +Node: Annotation I/O274931 +Node: Evaluation276572 +Node: Signal processing283495 +Node: Graphics286487 +Node: Extensions288017 +Node: Sources296881 +Node: Answers308847 +Node: Concept Index312609 +Node: Function and Macro Index342929 +Node: Copying347974  End Tag Table diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-1 wfdb-10.3.0/doc/wpg/info/wpg-1 --- wfdb-10.2.9/doc/wpg/info/wpg-1 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-1 Tue Nov 26 02:06:55 2002 @@ -10,8 +10,8 @@ This guide documents the Waveform Database interface library (the WFDB library). This file contains the text of the Tenth Edition of the -`WFDB Programmer's Guide' (26 October 2002), with revisions for release -10.2.9 of the WFDB library. +`WFDB Programmer's Guide' (26 November 2002), with revisions for +release 10.3.0 of the WFDB library. * Menu: @@ -389,6 +389,46 @@ WFDB Software Package distribution, for information on any more recent changes that may not be described here. +Changes in version 10.3.0 +------------------------- + + Fixed bugs in `lib/sample.c' that caused improper accounting of +signal group numbers when reading from two or more records at the same +time (as in `nst'), a bug that caused a segfault in `nst', and a bug +that referenced uninitialized memory in `newheader' if `nsig' = 0. + + The WFDB Software Package has been ported to MacOS/X (Darwin), +version 10.2 (the port should also work under 10.1 but this has not +been tested and will not be supported). + + It is now possible to generate a shared WFDB library (DLL) under +MS-Windows using Cygwin/gcc. + + Added functions `sample' and `sample_valid' to the WFDB library (in +`lib/signal.c'). `sample(s, t)' returns the sample at time (sample +number) `t' from signal `s', handling all necessary buffering +internally and allowing the caller to treat the signal file as a +virtual array of randomly accessible samples. `sample_valid' can be +invoked to check if the most recent value returned by `sample' was +valid (e.g., to see if the end of the input was reached). For an +example of the use of these functions, see `app/wqrs.c'. + +Changes in version 10.2.9 +------------------------- + + Fixed a bug in example 9 in this guide (introduced in version +10.2.0). + + Updated `lib/wfdbdll.def' and the `Makefile.dos' files in several +directories. These have not been tested in recent years and may need +further revisions; feedback is welcome. + + Corrected persistent problems with generating PDF versions of the +manuals for the desired page size, and added hyperlinks to the PDF +version of this guide. + + (WFDB library version 10.2.8 was identical to 10.2.7.) + Changes in version 10.2.7 ------------------------- @@ -430,7 +470,7 @@ consistent conversions, however, it is necessary to round all values down (e.g., from -1.5 to -2 rather than up to -1). - Fixed a memory leak in wfdb_fclose() (in lib/wfdbio.h). Thanks to + Fixed a memory leak in `wfdb_fclose' (in `lib/wfdbio.h'). Thanks to Ion Gaztan~aga. Changes in version 10.2.5 diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-2 wfdb-10.3.0/doc/wpg/info/wpg-2 --- wfdb-10.2.9/doc/wpg/info/wpg-2 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-2 Tue Nov 26 02:06:55 2002 @@ -372,7 +372,6 @@ signal in record `100s' like this: #include - #include #include main() @@ -947,7 +946,7 @@ if (annopen("100s", &a, 1) < 0) exit(1); while (getann(0, &annot) == 0) - printf("%s %s\n", mstimstr(annot.time), annstr(annot.anntyp); + printf("%s %s\n", mstimstr(annot.time), annstr(annot.anntyp)); exit(0); } @@ -1030,6 +1029,7 @@ * isigsettime:: Setting time of next samples read. * isgsettime:: As above, but for one signal group only. * iannsettime:: Setting time of next annotations read. +* sample:: A random access interface to input signals.  File: wpg, Node: isigsettime, Next: isgsettime, Prev: non-sequential, Up: non-sequential @@ -1078,7 +1078,7 @@ one record is open simultaneously (*note Multiple Record Access::).  -File: wpg, Node: iannsettime, Prev: isgsettime, Up: non-sequential +File: wpg, Node: iannsettime, Next: sample, Prev: isgsettime, Up: non-sequential iannsettime ----------- @@ -1113,6 +1113,46 @@ library.  +File: wpg, Node: sample, Prev: iannsettime, Up: non-sequential + +sample and sample_valid +----------------------- + + WFDB_Sample sample(WFDB_Signal S, WFDB_Time T) + int sample_valid(void) + +*Return:* +n + (from `sample'): The value (in raw adus) of sample number T in + open signal S,if successful, or the value of the previous + successfully read sample. + +0 + (from `sample_valid'): The most recent value returned by `sample' + was invalid + +1 + (from `sample_valid'): The most recent value returned by `sample' + was valid + +The `sample' function allows the caller to read samples of the +currently open input signals in any order. The first argument is a +signal number (a non-negative integer between 0 and NSIG-1, where NSIG +is the number of open input signals), and the second is a time, +expressed as a non-negative sample number. If `sample' is invoked with +valid input arguments, the companion function `sample_valid' returns 1. + + There are three ways in which `sample' can be invoked with invalid +input arguments. In each case, `sample_valid' returns 0, but `sample' +attempts to return a reasonable value. If S is invalid, `sample' +returns the value of signal 0 at the specified time. If T is negative, +the returned value is that of sample number zero of the specified +signal. If T specifies a sample number beyond the end of the record, +the returned value is that of the last valid sample of the specified +signal. For an example of the use of `sample' and `sample_valid', +*note Example 7::. + + File: wpg, Node: conversion, Next: calibration, Prev: non-sequential, Up: Functions Conversion Functions @@ -1129,128 +1169,4 @@ * timstr and strtim:: time in sample intervals <-> HH:MM:SS string * datstr and strdat:: Julian date <-> DD/MM/YYYY string * aduphys and physadu:: ADC units <-> physical units - - -File: wpg, Node: annstr and strann, Next: timstr and strtim, Prev: conversion, Up: conversion - -annstr, anndesc, and ecgstr ---------------------------- - - char *annstr(int CODE) - char *anndesc(int CODE) - char *ecgstr(int CODE) - -*Return:* -(char *) - pointer to a printable string that describes the code, or `NULL' - -These functions translate the annotation code specified by their -argument into a string (*note Annotation Codes::). Illegal or -undefined codes are translated by `annstr' and `ecgstr' into decimal -numerals surrounded by brackets (e.g., `[55]'); `anndesc' returns `NULL' -in such cases. The strings returned by `annstr' are mnemonics (usually -only one character), which may be modified either by `setannstr' or by -the presence of "modification labels" in an input annotation file -(*note annstr and strann::). The strings returned by `anndesc' are -brief descriptive strings, usually those given in the table of -annotation codes (*note Annotation Codes::). The strings returned by -`ecgstr' are usually the same as those returned by `annstr', but they -can be modified only by `setecgstr', and not by the presence of -modification labels as for `annstr'. The intent is that `ecgstr' -should be used rather than `annstr' only when it is necessary that a -fixed set of mnemonics be used, independent of any modification labels. - - Here is a little program that prints a table of the codes, mnemonic -strings, and descriptions: - - #include - #include - #include - - main() - { - int i; - - printf("Code\tMnemonic\tDescription\n"); - for (i = 1; i <= ACMAX; i++) { - printf("%3d\t%s", i, annstr(i)); - if (anndesc(i) != NULL) - printf("\t\t%s", anndesc(i)); - printf("\n"); - } - } - -(See `http://www.physionet.org/physiotools/wfdb/examples/exannstr.c' -for a copy of this program.) - - `ACMAX' is defined in `'. The range from 1 through -`ACMAX' includes all legal annotation codes; if you run this program, -you will find some undefined but legal annotation codes in this range. -*Note Example 3::, for another illustration of the use of `annstr'. -(`annstr' and `anndesc' were first introduced in WFDB library version -5.3.) - -strann and strecg ------------------ - - int strann(char *STRING) - int strecg(char *STRING) - -*Return:* -(int) - annotation code - -These functions translate the null-terminated ASCII character strings to -which their arguments point into annotation codes. Illegal strings are -translated into `NOTQRS'. Input strings for `strann' and `strecg' -should match those returned by `annstr' and `ecgstr' respectively. -*Note Example 9::, for an illustration of the use of `strann'. -(`strann' was first introduced in WFDB library version 5.3.) - -setannstr, setanndesc, and setecgstr ------------------------------------- - - int setannstr(int CODE, char *STRING) - int setanndesc(int CODE, char *STRING) - int setecgstr(int CODE, char *STRING) - -*Return:* - 0 - Success - --1 - Failure: illegal `code' - -These functions modify translation tables used by functions that -convert between annotation codes and strings. `setannstr' modifies the -table shared by `annstr' and `strann'; `setanndesc' modifies the table -used by `anndesc'; and `setecgstr' modifies the table shared by -`ecgstr' and `strecg'. They may be used to redefine strings for -defined annotation codes as well as to define strings for undefined -annotation codes. For example, `setannstr(NORMAL, "\\267")' redefines -the string for normal beats as a PostScript bullet, `*' (`NORMAL' is -defined in `'). These functions do not copy their -string arguments, which must therefore be kept valid by the caller. - - An important difference between `setannstr' (or `setanndesc') and -`setecgstr' is that `annopen' and `wfdbinit' insert modification labels -in any output annotation files that are created _after_ invoking -`setannstr' or `setanndesc'; `setecgstr' does not have this side -effect. By using `setannstr' before `annopen', a WFDB application may -create annotation files with self-contained code tables, which can be -read properly by other WFDB applications without the need to inform them -explicitly about non-standard codes. For this scheme to work as -intended, all custom code mnemonics and descriptions must be defined -before the output annotation files are opened. - - By passing a negative value as CODE to `setannstr' or `setanndesc', -the translation for -CODE can be modified without triggering the -generation of a modification label. This feature can be useful for -programs that use alternate sets of mnemonics or descriptions for -speakers of different languages. - - Note that it is possible, though not desirable, to define identical -strings for two or more codes; the behavior of `strann' and `strecg' in -such cases is implementation-dependent. (`setannstr' and `setanndesc' -were first introduced in WFDB library version 5.3.) diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-3 wfdb-10.3.0/doc/wpg/info/wpg-3 --- wfdb-10.2.9/doc/wpg/info/wpg-3 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-3 Tue Nov 26 02:06:55 2002 @@ -6,6 +6,130 @@ END-INFO-DIR-ENTRY  +File: wpg, Node: annstr and strann, Next: timstr and strtim, Prev: conversion, Up: conversion + +annstr, anndesc, and ecgstr +--------------------------- + + char *annstr(int CODE) + char *anndesc(int CODE) + char *ecgstr(int CODE) + +*Return:* +(char *) + pointer to a printable string that describes the code, or `NULL' + +These functions translate the annotation code specified by their +argument into a string (*note Annotation Codes::). Illegal or +undefined codes are translated by `annstr' and `ecgstr' into decimal +numerals surrounded by brackets (e.g., `[55]'); `anndesc' returns `NULL' +in such cases. The strings returned by `annstr' are mnemonics (usually +only one character), which may be modified either by `setannstr' or by +the presence of "modification labels" in an input annotation file +(*note annstr and strann::). The strings returned by `anndesc' are +brief descriptive strings, usually those given in the table of +annotation codes (*note Annotation Codes::). The strings returned by +`ecgstr' are usually the same as those returned by `annstr', but they +can be modified only by `setecgstr', and not by the presence of +modification labels as for `annstr'. The intent is that `ecgstr' +should be used rather than `annstr' only when it is necessary that a +fixed set of mnemonics be used, independent of any modification labels. + + Here is a little program that prints a table of the codes, mnemonic +strings, and descriptions: + + #include + #include + #include + + main() + { + int i; + + printf("Code\tMnemonic\tDescription\n"); + for (i = 1; i <= ACMAX; i++) { + printf("%3d\t%s", i, annstr(i)); + if (anndesc(i) != NULL) + printf("\t\t%s", anndesc(i)); + printf("\n"); + } + } + +(See `http://www.physionet.org/physiotools/wfdb/examples/exannstr.c' +for a copy of this program.) + + `ACMAX' is defined in `'. The range from 1 through +`ACMAX' includes all legal annotation codes; if you run this program, +you will find some undefined but legal annotation codes in this range. +*Note Example 3::, for another illustration of the use of `annstr'. +(`annstr' and `anndesc' were first introduced in WFDB library version +5.3.) + +strann and strecg +----------------- + + int strann(char *STRING) + int strecg(char *STRING) + +*Return:* +(int) + annotation code + +These functions translate the null-terminated ASCII character strings to +which their arguments point into annotation codes. Illegal strings are +translated into `NOTQRS'. Input strings for `strann' and `strecg' +should match those returned by `annstr' and `ecgstr' respectively. +*Note Example 9::, for an illustration of the use of `strann'. +(`strann' was first introduced in WFDB library version 5.3.) + +setannstr, setanndesc, and setecgstr +------------------------------------ + + int setannstr(int CODE, char *STRING) + int setanndesc(int CODE, char *STRING) + int setecgstr(int CODE, char *STRING) + +*Return:* + 0 + Success + +-1 + Failure: illegal `code' + +These functions modify translation tables used by functions that +convert between annotation codes and strings. `setannstr' modifies the +table shared by `annstr' and `strann'; `setanndesc' modifies the table +used by `anndesc'; and `setecgstr' modifies the table shared by +`ecgstr' and `strecg'. They may be used to redefine strings for +defined annotation codes as well as to define strings for undefined +annotation codes. For example, `setannstr(NORMAL, "\\267")' redefines +the string for normal beats as a PostScript bullet, `*' (`NORMAL' is +defined in `'). These functions do not copy their +string arguments, which must therefore be kept valid by the caller. + + An important difference between `setannstr' (or `setanndesc') and +`setecgstr' is that `annopen' and `wfdbinit' insert modification labels +in any output annotation files that are created _after_ invoking +`setannstr' or `setanndesc'; `setecgstr' does not have this side +effect. By using `setannstr' before `annopen', a WFDB application may +create annotation files with self-contained code tables, which can be +read properly by other WFDB applications without the need to inform them +explicitly about non-standard codes. For this scheme to work as +intended, all custom code mnemonics and descriptions must be defined +before the output annotation files are opened. + + By passing a negative value as CODE to `setannstr' or `setanndesc', +the translation for -CODE can be modified without triggering the +generation of a modification label. This feature can be useful for +programs that use alternate sets of mnemonics or descriptions for +speakers of different languages. + + Note that it is possible, though not desirable, to define identical +strings for two or more codes; the behavior of `strann' and `strecg' in +such cases is implementation-dependent. (`setannstr' and `setanndesc' +were first introduced in WFDB library version 5.3.) + + File: wpg, Node: timstr and strtim, Next: datstr and strdat, Prev: annstr and strann, Up: conversion The next three functions convert between "standard time format" @@ -1166,181 +1290,4 @@ * WFDB_Calinfo structures:: Signal calibration specifications. * WFDB_Anninfo structures:: Annotator names and file types. * WFDB_Annotation structures:: Annotation contents. - - -File: wpg, Node: WFDB_Siginfo structures, Next: WFDB_Calinfo structures, Prev: Data Types, Up: Data Types - -Signal Information Structures -============================= - - The SIARRAY argument for `isigopen', `osigopen', `wfdbinit', and -`osigfopen' is a pointer to an array of objects of type `WFDB_Siginfo'. -The first three of these functions fill in the `WFDB_Siginfo' objects -to which SIARRAY points, but the caller must supply initialized -`WFDB_Siginfo' objects to `osigfopen'. Each object specifies the -attributes of a signal: - -`char *fname' - a pointer to a null-terminated string that names the file in which - samples of the associated signal are stored. Input signal files - are found by prefixing `fname' with each of the components of the - database path in turn (*note WFDB path::). `fname' may include - relative or absolute path specifications if necessary; the use of - an absolute pathname, combined with an initial null component in - `WFDB', reduces the time needed to find the signal file to a - minimum. If `fname' is `-', it refers to the standard input or - output. - -`char *desc' - a pointer to a null-terminated string without embedded newlines - (e.g., `ECG lead V1' or `trans-thoracic impedance'). The length of - the `desc' string is restricted to a maximum of `WFDB_MAXDSL' - (defined in `') characters, not including the null. - -`char *units' - a pointer to a null-terminated string without embedded whitespace. - The string specifies the physical units of the signal; if NULL, - the units are assumed to be millivolts. The length of the `units' - string is restricted to a maximum of `WFDB_MAXUSL' (defined in - `') characters (not including the null). - -`WFDB_Gain gain' - the number of analog-to-digital converter units (adus) per - physical unit (see previous item) relative to the original analog - signal; for an ECG, this is roughly equal to the amplitude of a - normal QRS complex. If `gain' is zero, no amplitude calibration - is available; in this case, a `gain' of `WFDB_DEFGAIN' (defined in - `') may be assumed. - -`WFDB_Sample initval' - the initial value of the associated signal (i.e., the value of - sample number 0). - -`WFDB_Group group' - the signal group number. All signals in a given group are stored - in the same file. If there are two or more signals in a group, - the file is called a "multiplexed signal file". Group numbers - begin at 0; arrays of `WFDB_Siginfo' structures are always kept - ordered with respect to the group number, so that signals - belonging to the same group are described by consecutive entries - in SIARRAY. - -`int fmt' - the signal storage format. The most commonly-used formats are - format 8 (8-bit first differences), format 16 (16-bit amplitudes), - and format 212 (pairs of 12-bit amplitudes bit-packed into byte - triplets). See `' for a complete list of supported - formats. All signals belonging to the same group must be stored - in the same format. - -`int spf' - the number of samples per frame. This is 1, for all except - oversampled signals in multi-frequency records, for which `spf' - may be any positive integer. Note that non-integer values are not - permitted (thus the frame rate must be chosen such that all - sampling frequencies used in the record are integer multiples of - the frame rate). - -`int bsize' - the block size, in bytes. For signal files that reside on Unix - character device special files (or their equivalents), the `bsize' - field indicates how many bytes must be read or written at a time - (*note Special Files::). For ordinary disk files, `bsize' is zero. - All signals belonging to a given group have the same `bsize'. - -`int adcres' - the ADC resolution in bits. Typical ADCs have resolutions between - 8 and 16 bits inclusive. - -`int adczero' - the ADC output given an input that falls exactly at the center of - the ADC range (normally 0 VDC). Bipolar ADCs produce two's - complement output; for these, `adczero' is usually zero. For the - MIT DB, however, an offset binary ADC was used, and `adczero' was - 1024. - -`int baseline' - the value of ADC output that would map to 0 physical units input. - The value of `adczero' is not synonymous with that of `baseline' - (the isoelectric or physical zero level of the signal); the - `baseline' is a characteristic of the _signal_, while `adczero' is - a characteristic of the _digitizer_. The value of `baseline' need - not necessarily lie within the output range of the ADC; for - example, if the `units' are `degrees_Kelvin', and the ADC range is - 200-300 degrees Kelvin, `baseline' corresponds to absolute zero, - and lies well outside the range of values actually produced by the - ADC. - -`long nsamp' - the number of samples in the signal. (Exception: in - multi-frequency records, `nsamp' is the number of samples divided - by `spf', see above, i.e., the number of frames.) All signals in - a given record must have the same `nsamp'. If `nsamp' is zero, - the number of samples is unspecified, and the `cksum' (see the - next item) is not used; this is useful for specifying signals that - are obtained from pipes, for which the length may not be known. - -`int cksum' - a 16-bit checksum of all samples. This field is not usually - accessed by application programs; `newheader' records checksums - calculated by `putvec' when it creates a new `hea' file, and - `getvec' compares checksums that it calculates against `cksum' at - the end of the record, provided that the entire record was read - through without skipping samples. - - The number of `WFDB_Siginfo' structures in SIARRAY is given by the -NSIG argument of the functions that open signal files. Input and -output signal numbers are assigned beginning with 0 in the order in -which the signals are given in SIARRAY. Note that input signal 0 and -output signal 0 are distinct. Input signal numbers are supplied to -`aduphys', `physadu', `adumuv', and `muvadu' in their first arguments. -*Note Example 5::, for an illustration of how to read signal -specifications from `WFDB_Siginfo' structures. - - -File: wpg, Node: WFDB_Calinfo structures, Next: WFDB_Anninfo structures, Prev: WFDB_Siginfo structures, Up: Data Types - -Calibration Information Structures -================================== - - The CAL argument for `getcal' and `putcal' is a pointer to an object -of type `WFDB_Calinfo'. A `WFDB_Calinfo' object contains information -about signals of a specified type: - -`char *sigtype' - a pointer to a null-terminated string without embedded tabs or - newlines. This field describes the type(s) of signals to which - the calibration specifications apply. Usually, `sigtype' is an - exact match to (or a prefix of) the `desc' field of the - `WFDB_Siginfo' object that describes a matching signal. - -`char *units' - a pointer to a null-terminated string without embedded whitespace. - This field specifies the physical units of signals to which the - calibration specifications apply. Usually, the `units' field of a - `WFDB_Calinfo' structure must exactly match the `units' field of - the `WFDB_Siginfo' structure that describes a matching signal. - -`double scale' - the customary plotting scale, in physical units per centimeter. - WFDB applications that produce graphical output may use `scale' as - a default. Except in unusual circumstances, signals of different - types should be plotted at equal multiples of their respective - `scale's. - -`double low' -`double high' - values (in physical units) corresponding to the low and high - levels of a calibration pulse. If the signal is AC-coupled (see - below), `low' is zero, and `high' is the pulse amplitude. - -`int caltype' - a small integer that specifies the shape of the calibration pulse - (see `' for definitions). `caltype' is even if - signals of the corresponding `sigtype' are AC-coupled, and odd if - they are DC-coupled. - - The calibration list is a memory-resident linked list of -`WFDB_Calinfo' structures. It is accessible only via `calopen', -`getcal', `putcal', `newcal', and `flushcal'. diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-4 wfdb-10.3.0/doc/wpg/info/wpg-4 --- wfdb-10.2.9/doc/wpg/info/wpg-4 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-4 Tue Nov 26 02:06:55 2002 @@ -6,6 +6,183 @@ END-INFO-DIR-ENTRY  +File: wpg, Node: WFDB_Siginfo structures, Next: WFDB_Calinfo structures, Prev: Data Types, Up: Data Types + +Signal Information Structures +============================= + + The SIARRAY argument for `isigopen', `osigopen', `wfdbinit', and +`osigfopen' is a pointer to an array of objects of type `WFDB_Siginfo'. +The first three of these functions fill in the `WFDB_Siginfo' objects +to which SIARRAY points, but the caller must supply initialized +`WFDB_Siginfo' objects to `osigfopen'. Each object specifies the +attributes of a signal: + +`char *fname' + a pointer to a null-terminated string that names the file in which + samples of the associated signal are stored. Input signal files + are found by prefixing `fname' with each of the components of the + database path in turn (*note WFDB path::). `fname' may include + relative or absolute path specifications if necessary; the use of + an absolute pathname, combined with an initial null component in + `WFDB', reduces the time needed to find the signal file to a + minimum. If `fname' is `-', it refers to the standard input or + output. + +`char *desc' + a pointer to a null-terminated string without embedded newlines + (e.g., `ECG lead V1' or `trans-thoracic impedance'). The length of + the `desc' string is restricted to a maximum of `WFDB_MAXDSL' + (defined in `') characters, not including the null. + +`char *units' + a pointer to a null-terminated string without embedded whitespace. + The string specifies the physical units of the signal; if NULL, + the units are assumed to be millivolts. The length of the `units' + string is restricted to a maximum of `WFDB_MAXUSL' (defined in + `') characters (not including the null). + +`WFDB_Gain gain' + the number of analog-to-digital converter units (adus) per + physical unit (see previous item) relative to the original analog + signal; for an ECG, this is roughly equal to the amplitude of a + normal QRS complex. If `gain' is zero, no amplitude calibration + is available; in this case, a `gain' of `WFDB_DEFGAIN' (defined in + `') may be assumed. + +`WFDB_Sample initval' + the initial value of the associated signal (i.e., the value of + sample number 0). + +`WFDB_Group group' + the signal group number. All signals in a given group are stored + in the same file. If there are two or more signals in a group, + the file is called a "multiplexed signal file". Group numbers + begin at 0; arrays of `WFDB_Siginfo' structures are always kept + ordered with respect to the group number, so that signals + belonging to the same group are described by consecutive entries + in SIARRAY. + +`int fmt' + the signal storage format. The most commonly-used formats are + format 8 (8-bit first differences), format 16 (16-bit amplitudes), + and format 212 (pairs of 12-bit amplitudes bit-packed into byte + triplets). See `' for a complete list of supported + formats. All signals belonging to the same group must be stored + in the same format. + +`int spf' + the number of samples per frame. This is 1, for all except + oversampled signals in multi-frequency records, for which `spf' + may be any positive integer. Note that non-integer values are not + permitted (thus the frame rate must be chosen such that all + sampling frequencies used in the record are integer multiples of + the frame rate). + +`int bsize' + the block size, in bytes. For signal files that reside on Unix + character device special files (or their equivalents), the `bsize' + field indicates how many bytes must be read or written at a time + (*note Special Files::). For ordinary disk files, `bsize' is zero. + All signals belonging to a given group have the same `bsize'. + +`int adcres' + the ADC resolution in bits. Typical ADCs have resolutions between + 8 and 16 bits inclusive. + +`int adczero' + the ADC output given an input that falls exactly at the center of + the ADC range (normally 0 VDC). Bipolar ADCs produce two's + complement output; for these, `adczero' is usually zero. For the + MIT DB, however, an offset binary ADC was used, and `adczero' was + 1024. + +`int baseline' + the value of ADC output that would map to 0 physical units input. + The value of `adczero' is not synonymous with that of `baseline' + (the isoelectric or physical zero level of the signal); the + `baseline' is a characteristic of the _signal_, while `adczero' is + a characteristic of the _digitizer_. The value of `baseline' need + not necessarily lie within the output range of the ADC; for + example, if the `units' are `degrees_Kelvin', and the ADC range is + 200-300 degrees Kelvin, `baseline' corresponds to absolute zero, + and lies well outside the range of values actually produced by the + ADC. + +`long nsamp' + the number of samples in the signal. (Exception: in + multi-frequency records, `nsamp' is the number of samples divided + by `spf', see above, i.e., the number of frames.) All signals in + a given record must have the same `nsamp'. If `nsamp' is zero, + the number of samples is unspecified, and the `cksum' (see the + next item) is not used; this is useful for specifying signals that + are obtained from pipes, for which the length may not be known. + +`int cksum' + a 16-bit checksum of all samples. This field is not usually + accessed by application programs; `newheader' records checksums + calculated by `putvec' when it creates a new `hea' file, and + `getvec' compares checksums that it calculates against `cksum' at + the end of the record, provided that the entire record was read + through without skipping samples. + + The number of `WFDB_Siginfo' structures in SIARRAY is given by the +NSIG argument of the functions that open signal files. Input and +output signal numbers are assigned beginning with 0 in the order in +which the signals are given in SIARRAY. Note that input signal 0 and +output signal 0 are distinct. Input signal numbers are supplied to +`aduphys', `physadu', `adumuv', and `muvadu' in their first arguments. +*Note Example 5::, for an illustration of how to read signal +specifications from `WFDB_Siginfo' structures. + + +File: wpg, Node: WFDB_Calinfo structures, Next: WFDB_Anninfo structures, Prev: WFDB_Siginfo structures, Up: Data Types + +Calibration Information Structures +================================== + + The CAL argument for `getcal' and `putcal' is a pointer to an object +of type `WFDB_Calinfo'. A `WFDB_Calinfo' object contains information +about signals of a specified type: + +`char *sigtype' + a pointer to a null-terminated string without embedded tabs or + newlines. This field describes the type(s) of signals to which + the calibration specifications apply. Usually, `sigtype' is an + exact match to (or a prefix of) the `desc' field of the + `WFDB_Siginfo' object that describes a matching signal. + +`char *units' + a pointer to a null-terminated string without embedded whitespace. + This field specifies the physical units of signals to which the + calibration specifications apply. Usually, the `units' field of a + `WFDB_Calinfo' structure must exactly match the `units' field of + the `WFDB_Siginfo' structure that describes a matching signal. + +`double scale' + the customary plotting scale, in physical units per centimeter. + WFDB applications that produce graphical output may use `scale' as + a default. Except in unusual circumstances, signals of different + types should be plotted at equal multiples of their respective + `scale's. + +`double low' +`double high' + values (in physical units) corresponding to the low and high + levels of a calibration pulse. If the signal is AC-coupled (see + below), `low' is zero, and `high' is the pulse amplitude. + +`int caltype' + a small integer that specifies the shape of the calibration pulse + (see `' for definitions). `caltype' is even if + signals of the corresponding `sigtype' are AC-coupled, and odd if + they are DC-coupled. + + The calibration list is a memory-resident linked list of +`WFDB_Calinfo' structures. It is accessible only via `calopen', +`getcal', `putcal', `newcal', and `flushcal'. + + File: wpg, Node: WFDB_Anninfo structures, Next: WFDB_Annotation structures, Prev: WFDB_Calinfo structures, Up: Data Types Annotator Information Structures @@ -821,236 +998,4 @@ * Example 8:: Creating a new WFDB record. * Example 9:: A signal averager. * Example 10:: A QRS detector. - - -File: wpg, Node: Example 1, Next: Example 2, Prev: Examples, Up: Examples - -Example 1: An Annotation Filter -================================ - - The following program copies an annotation file, changing all QRS -annotations to `NORMAL' and deleting all non-QRS annotations. - - 1 #include - 2 #include - 3 #include - 4 - 5 main() - 6 { - 7 WFDB_Anninfo an[2]; - 8 char record[8], iann[10], oann[10]; - 9 WFDB_Annotation annot; - 10 - 11 printf("Type record name: "); - 12 fgets(record, 8, stdin); record[strlen(record)-1] = '\0'; - 13 printf("Type input annotator name: "); - 14 fgets(iann, 10, stdin); iann[strlen(iann)-1] = '\0'; - 15 printf("Type output annotator name: "); - 16 fgets(oann, 10, stdin); oann[strlen(oann)-1] = '\0'; - 17 an[0].name = iann; an[0].stat = WFDB_READ; - 18 an[1].name = oann; an[1].stat = WFDB_WRITE; - 19 if (annopen(record, an, 2) < 0) exit(1); - 20 while (getann(0, &annot) == 0) - 21 if (isqrs(annot.anntyp)) { - 22 annot.anntyp = NORMAL; - 23 if (putann(0, &annot) < 0) break; - 24 } - 25 wfdbquit(); - 26 } - -(See `http://www.physionet.org/physiotools/wfdb/examples/example1.c' -for a copy of this program.) - -*Notes:* - -_Line 2:_ - All programs that use the WFDB library must include - `'. - -_Line 3:_ - The `#include' statement makes available not only the mapping - macros, one of which will be used in line 21, but also the - annotation code symbols in `', one of which will - be needed in line 22. - -_Line 7:_ - Since there will be two annotators (one each for input and output), - the array of `WFDB_Anninfo' objects has two members. - -_Line 9:_ - This structure will be filled in by `getann', modified, and passed - to `putann' for output. - -_Lines 11-16:_ - The record name and the annotator names are filled into the - character arrays. The code in lines 12, 14, and 16 illustrates a - C idiom for reading a string of limited length; the second - statement in each of these lines replaces the trailing newline - character (which `fgets' copies into the string) with a null. - String arguments to WFDB library functions should not include - newline characters. - -_Lines 17-18:_ - Pointers to the character arrays (strings) containing the annotator - names are filled into the `name' fields of the array of - `WFDB_Anninfo' objects. Note that the `name' fields are only - pointers and do not contain storage for the strings themselves. - If this is not clear to you, review the discussion of pointers and - arrays in `K&R', pp. 97-100. The input annotator is to be read, - the output annotator is to be written. `WFDB_READ' and - `WFDB_WRITE' are defined in `'. - -_Line 19:_ - Note that the first and second arguments of `annopen' are the - names of the respective arrays; thus `annopen' receives pointers - rather than values in its argument list. - -_Line 20:_ - An annotation is read from annotator 0 into `annot'. The `&' is - necessary since `getann' requires a pointer to the structure in - order to be able to modify its contents. When `getann' returns a - negative value, no more annotations remain to be read and the loop - ends. - -_Line 21:_ - The macro `isqrs' is defined in `'; `isqrs(X)' is - true if X is an annotation code that denotes a QRS complex, false - if X is not a QRS annotation code. - -_Line 22:_ - `NORMAL' is defined in `'. - -_Line 23:_ - The call to `putann' now writes the modified annotation in the - output annotator 0 file. As for `getann', a pointer to `annot' - must be passed using the `&' operator. - -_Line 25:_ - All files are closed prior to exiting. This is mandatory since the - program creates an output file with `putann'. - - -File: wpg, Node: Example 2, Next: Example 3, Prev: Example 1, Up: Examples - -Example 2: An Annotation Translator -=================================== - - This program translates the `atr' annotations for the record named -in its argument into an AHA-format annotation file with the annotator -name `aha'. - - 1 #include - 2 #include - 3 - 4 main(argc, argv) - 5 int argc; - 6 char *argv[]; - 7 { - 8 WFDB_Anninfo an[2]; - 9 WFDB_Annotation annot; - 10 - 11 if (argc < 2) { - 12 fprintf(stderr, "usage: %s record\n", argv[0]); - 13 exit(1); - 14 } - 15 an[0].name = "atr"; an[0].stat = WFDB_READ; - 16 an[1].name = "aha"; an[1].stat = WFDB_AHA_WRITE; - 17 if (annopen(argv[1], an, 2) < 0) exit(2); - 18 while (getann(0, &annot) == 0 && putann(0, &annot) == 0) - 19 ; - 20 wfdbquit(); - 21 exit(0); - 22 } - -(See `http://www.physionet.org/physiotools/wfdb/examples/example2.c' -for a copy of this program.) - -*Notes:* - -_Lines 4-6:_ - If this doesn't look familiar, see `K&R', pp. 114-115. - -_Lines 11-14:_ - This is the standard idiom for producing those cryptic error - messages for which Unix programs are notorious; `argv[0]' is the - name by which the program was invoked. - -_Lines 15-16:_ - These lines set up the annotator information. Input annotator 0 - is the `atr' annotation file, and output annotator 0 will be - written in AHA format. - -_Line 17:_ - If we can't read the input or write the output, quit with an error - message from `annopen'. - -_Line 18:_ - Here's where the work is done. The format translation is handled - entirely by `getann' and `putann'. The loop ends normally when - `getann' reaches the end of the input file, or prematurely if - there is a read or write error. - -_Line 21:_ - Since we have carefully defined non-zero exit codes for the various - errors that this program might encounter, we also define this - successful exit here. If this program is run as part of a Unix - shell script, the exit codes are accessible to the shell, which - can determine what to do next as a result. If this line were - omitted (as in example 1), the exit code would be undefined. - - -File: wpg, Node: Example 3, Next: Example 4, Prev: Example 2, Up: Examples - -Example 3: An Annotation Printer -================================ - - This program prints annotations in readable form. Its first -argument is an annotator name, and its second argument is a record name. - - 1 #include - 2 #include - 3 - 4 main(argc, argv) - 5 int argc; - 6 char *argv[]; - 7 { - 8 WFDB_Anninfo a; - 9 WFDB_Annotation annot; - 10 - 11 if (argc < 3) { - 12 fprintf(stderr, "usage: %s annotator record\n", argv[0]); - 13 exit(1); - 14 } - 15 a.name = argv[1]; a.stat = WFDB_READ; - 16 (void)sampfreq(argv[2]); - 17 if (annopen(argv[2], &a, 1) < 0) exit(2); - 18 while (getann(0, &annot) == 0) - 19 printf("%s (%ld) %s %d %d %d %s\n", - 20 timstr(-(annot.time)), - 21 annot.time, - 22 annstr(annot.anntyp), - 23 annot.subtyp, annot.chan, annot.num, - 24 (annot.aux != NULL && *annot.aux > 0) ? - 25 annot.aux+1 : ""); - 26 exit(0); - 27 } - -(See `http://www.physionet.org/physiotools/wfdb/examples/example3.c' -for a copy of this program.) - -*Notes:* -_Line 16:_ - The invocation of `sampfreq' here sets the internal variables - needed by `timstr' below. - -_Line 20:_ - This line gives the annotation time as a time of day. If the base - time is omitted in the header file, or if we used - `timstr(annot.time)' instead, we would obtain the elapsed time from - the beginning of the record. - -_Lines 24-25:_ - This expression evaluates to an empty string unless the `aux' - string is non-empty. It makes the assumption that `aux' is a - printable ASCII string; the printable part follows the length byte. diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-5 wfdb-10.3.0/doc/wpg/info/wpg-5 --- wfdb-10.2.9/doc/wpg/info/wpg-5 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-5 Tue Nov 26 02:06:55 2002 @@ -6,6 +6,238 @@ END-INFO-DIR-ENTRY  +File: wpg, Node: Example 1, Next: Example 2, Prev: Examples, Up: Examples + +Example 1: An Annotation Filter +================================ + + The following program copies an annotation file, changing all QRS +annotations to `NORMAL' and deleting all non-QRS annotations. + + 1 #include + 2 #include + 3 #include + 4 + 5 main() + 6 { + 7 WFDB_Anninfo an[2]; + 8 char record[8], iann[10], oann[10]; + 9 WFDB_Annotation annot; + 10 + 11 printf("Type record name: "); + 12 fgets(record, 8, stdin); record[strlen(record)-1] = '\0'; + 13 printf("Type input annotator name: "); + 14 fgets(iann, 10, stdin); iann[strlen(iann)-1] = '\0'; + 15 printf("Type output annotator name: "); + 16 fgets(oann, 10, stdin); oann[strlen(oann)-1] = '\0'; + 17 an[0].name = iann; an[0].stat = WFDB_READ; + 18 an[1].name = oann; an[1].stat = WFDB_WRITE; + 19 if (annopen(record, an, 2) < 0) exit(1); + 20 while (getann(0, &annot) == 0) + 21 if (isqrs(annot.anntyp)) { + 22 annot.anntyp = NORMAL; + 23 if (putann(0, &annot) < 0) break; + 24 } + 25 wfdbquit(); + 26 } + +(See `http://www.physionet.org/physiotools/wfdb/examples/example1.c' +for a copy of this program.) + +*Notes:* + +_Line 2:_ + All programs that use the WFDB library must include + `'. + +_Line 3:_ + The `#include' statement makes available not only the mapping + macros, one of which will be used in line 21, but also the + annotation code symbols in `', one of which will + be needed in line 22. + +_Line 7:_ + Since there will be two annotators (one each for input and output), + the array of `WFDB_Anninfo' objects has two members. + +_Line 9:_ + This structure will be filled in by `getann', modified, and passed + to `putann' for output. + +_Lines 11-16:_ + The record name and the annotator names are filled into the + character arrays. The code in lines 12, 14, and 16 illustrates a + C idiom for reading a string of limited length; the second + statement in each of these lines replaces the trailing newline + character (which `fgets' copies into the string) with a null. + String arguments to WFDB library functions should not include + newline characters. + +_Lines 17-18:_ + Pointers to the character arrays (strings) containing the annotator + names are filled into the `name' fields of the array of + `WFDB_Anninfo' objects. Note that the `name' fields are only + pointers and do not contain storage for the strings themselves. + If this is not clear to you, review the discussion of pointers and + arrays in `K&R', pp. 97-100. The input annotator is to be read, + the output annotator is to be written. `WFDB_READ' and + `WFDB_WRITE' are defined in `'. + +_Line 19:_ + Note that the first and second arguments of `annopen' are the + names of the respective arrays; thus `annopen' receives pointers + rather than values in its argument list. + +_Line 20:_ + An annotation is read from annotator 0 into `annot'. The `&' is + necessary since `getann' requires a pointer to the structure in + order to be able to modify its contents. When `getann' returns a + negative value, no more annotations remain to be read and the loop + ends. + +_Line 21:_ + The macro `isqrs' is defined in `'; `isqrs(X)' is + true if X is an annotation code that denotes a QRS complex, false + if X is not a QRS annotation code. + +_Line 22:_ + `NORMAL' is defined in `'. + +_Line 23:_ + The call to `putann' now writes the modified annotation in the + output annotator 0 file. As for `getann', a pointer to `annot' + must be passed using the `&' operator. + +_Line 25:_ + All files are closed prior to exiting. This is mandatory since the + program creates an output file with `putann'. + + +File: wpg, Node: Example 2, Next: Example 3, Prev: Example 1, Up: Examples + +Example 2: An Annotation Translator +=================================== + + This program translates the `atr' annotations for the record named +in its argument into an AHA-format annotation file with the annotator +name `aha'. + + 1 #include + 2 #include + 3 + 4 main(argc, argv) + 5 int argc; + 6 char *argv[]; + 7 { + 8 WFDB_Anninfo an[2]; + 9 WFDB_Annotation annot; + 10 + 11 if (argc < 2) { + 12 fprintf(stderr, "usage: %s record\n", argv[0]); + 13 exit(1); + 14 } + 15 an[0].name = "atr"; an[0].stat = WFDB_READ; + 16 an[1].name = "aha"; an[1].stat = WFDB_AHA_WRITE; + 17 if (annopen(argv[1], an, 2) < 0) exit(2); + 18 while (getann(0, &annot) == 0 && putann(0, &annot) == 0) + 19 ; + 20 wfdbquit(); + 21 exit(0); + 22 } + +(See `http://www.physionet.org/physiotools/wfdb/examples/example2.c' +for a copy of this program.) + +*Notes:* + +_Lines 4-6:_ + If this doesn't look familiar, see `K&R', pp. 114-115. + +_Lines 11-14:_ + This is the standard idiom for producing those cryptic error + messages for which Unix programs are notorious; `argv[0]' is the + name by which the program was invoked. + +_Lines 15-16:_ + These lines set up the annotator information. Input annotator 0 + is the `atr' annotation file, and output annotator 0 will be + written in AHA format. + +_Line 17:_ + If we can't read the input or write the output, quit with an error + message from `annopen'. + +_Line 18:_ + Here's where the work is done. The format translation is handled + entirely by `getann' and `putann'. The loop ends normally when + `getann' reaches the end of the input file, or prematurely if + there is a read or write error. + +_Line 21:_ + Since we have carefully defined non-zero exit codes for the various + errors that this program might encounter, we also define this + successful exit here. If this program is run as part of a Unix + shell script, the exit codes are accessible to the shell, which + can determine what to do next as a result. If this line were + omitted (as in example 1), the exit code would be undefined. + + +File: wpg, Node: Example 3, Next: Example 4, Prev: Example 2, Up: Examples + +Example 3: An Annotation Printer +================================ + + This program prints annotations in readable form. Its first +argument is an annotator name, and its second argument is a record name. + + 1 #include + 2 #include + 3 + 4 main(argc, argv) + 5 int argc; + 6 char *argv[]; + 7 { + 8 WFDB_Anninfo a; + 9 WFDB_Annotation annot; + 10 + 11 if (argc < 3) { + 12 fprintf(stderr, "usage: %s annotator record\n", argv[0]); + 13 exit(1); + 14 } + 15 a.name = argv[1]; a.stat = WFDB_READ; + 16 (void)sampfreq(argv[2]); + 17 if (annopen(argv[2], &a, 1) < 0) exit(2); + 18 while (getann(0, &annot) == 0) + 19 printf("%s (%ld) %s %d %d %d %s\n", + 20 timstr(-(annot.time)), + 21 annot.time, + 22 annstr(annot.anntyp), + 23 annot.subtyp, annot.chan, annot.num, + 24 (annot.aux != NULL && *annot.aux > 0) ? + 25 annot.aux+1 : ""); + 26 exit(0); + 27 } + +(See `http://www.physionet.org/physiotools/wfdb/examples/example3.c' +for a copy of this program.) + +*Notes:* +_Line 16:_ + The invocation of `sampfreq' here sets the internal variables + needed by `timstr' below. + +_Line 20:_ + This line gives the annotation time as a time of day. If the base + time is omitted in the header file, or if we used + `timstr(annot.time)' instead, we would obtain the elapsed time from + the beginning of the record. + +_Lines 24-25:_ + This expression evaluates to an empty string unless the `aux' + string is non-empty. It makes the assumption that `aux' is a + printable ASCII string; the printable part follows the length byte. + + File: wpg, Node: Example 4, Next: Example 5, Prev: Example 3, Up: Examples Example 4: Generating an R-R Interval Histogram @@ -285,14 +517,13 @@ Example 7: A General-Purpose FIR Filter ======================================== - This program illustrates a useful technique for obtaining something -close to random access to signals, a technique that is particularly -useful for implementing digital filters. The first argument is the -record name, the second and third arguments are the start time and the -duration of the segment to be filtered, and the rest of the arguments -are finite-impulse-response (FIR) filter coefficients. For example, if -this program were compiled into an executable program called `filter', -it might be used by + This program illustrates the use of `sample' to obtain random access +to signals, a technique that is particularly useful for implementing +digital filters. The first argument is the record name, the second and +third arguments are the start time and the duration of the segment to +be filtered, and the rest of the arguments are finite-impulse-response +(FIR) filter coefficients. For example, if this program were compiled +into an executable program called `filter', it might be used by filter 100 5:0 20 .2 .2 .2 .2 .2 which would apply a five-point moving average (rectangular window) @@ -302,149 +533,118 @@ 1 #include 2 #include - 3 #define BUFLN 512 - 4 int nsig, sample_ok = 1; - 5 WFDB_Sample *sbuf; - 6 - 7 sample(s, t) - 8 int s; - 9 long t; - 10 { - 11 static long tt = -1L; - 12 - 13 if (t <= tt - BUFLN) - 14 fprintf(stderr, "sample: buffer too short\n"); - 15 while (t > tt) - 16 if (getvec(sbuf + nsig * ((++tt)&(BUFLN-1))) < 0) - 17 sample_ok = 0; - 18 return (*(sbuf + nsig * (t&(BUFLN-1)) + s)); - 19 } - 20 - 21 main(argc, argv) - 22 int argc; - 23 char *argv[]; - 24 { - 25 double *c, one = 1.0, vv, atof(); - 26 int i, j, nc = argc - 4; - 27 long nsamp, t; - 28 static WFDB_Sample *v; - 29 static WFDB_Siginfo *s; - 30 - 31 if (argc < 4) { - 32 fprintf(stderr, - 33 "usage: %s record start duration [ coefficients ... ]\n", - 34 argv[0]); - 35 exit(1); + 3 + 4 main(argc, argv) + 5 int argc; + 6 char *argv[]; + 7 { + 8 double *c, one = 1.0, vv, atof(); + 9 int i, j, nc = argc - 4, nsig; + 10 long nsamp, t; + 11 static WFDB_Sample *v; + 12 static WFDB_Siginfo *s; + 13 + 14 if (argc < 4) { + 15 fprintf(stderr, + 16 "usage: %s record start duration [ coefficients ... ]\n", + 17 argv[0]); + 18 exit(1); + 19 } + 20 if (nc < 1) { + 21 nc = 1; c = &one; + 22 } + 23 else if ((c = (double *)calloc(nc, sizeof(double))) == NULL) { + 24 fprintf(stderr, "%s: too many coefficients\n", argv[0]); + 25 exit(2); + 26 } + 27 for (i = 0; i < nc; i++) + 28 c[i] = atof(argv[i+4]); + 29 if ((nsig = isigopen(argv[1], NULL, 0)) < 1) + 30 exit(3); + 31 s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); + 32 v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); + 33 if (s == NULL || v == NULL) { + 34 fprintf(stderr, "insufficient memory\n"); + 35 exit(3); 36 } - 37 if (nc < 1) { - 38 nc = 1; c = &one; - 39 } - 40 else if (nc >= BUFLN || - 41 (c = (double *)calloc(nc, sizeof(double))) == NULL) { - 42 fprintf(stderr, "%s: too many coefficients\n", argv[0]); - 43 exit(2); - 44 } - 45 for (i = 0; i < nc; i++) - 46 c[i] = atof(argv[i+4]); - 47 if ((nsig = isigopen(argv[1], NULL, 0)) < 1) - 48 exit(3); - 49 s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); - 50 v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); - 51 sbuf = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)*BUFLN); - 52 if (s == NULL || v == NULL || sbuf == NULL) { - 53 fprintf(stderr, "insufficient memory\n"); - 54 exit(3); - 55 } - 56 if (isigopen(argv[1], s, nsig) != nsig) - 57 exit(3); - 58 if (isigsettime(strtim(argv[2])) < 0) - 59 exit(4); - 60 if ((nsamp = strtim(argv[3])) < 1) { - 61 fprintf(stderr, "%s: inappropriate value for duration\n", - 62 argv[0]); - 63 exit(5); - 64 } - 65 if (osigopen("16l", s, nsig) != nsig) - 66 exit(6); - 67 - 68 for (t = 0; t < nsamp && sample_ok; t++) { - 69 for (j = 0; j < nsig; j++) { - 70 for (i = 0, vv = 0.; i < nc; i++) - 71 if (c[i] != 0.) vv += c[i]*sample(j, t+i); - 72 v[j] = (int)vv; - 73 } - 74 if (putvec(v) < 0) break; - 75 } - 76 - 77 (void)newheader("out"); - 78 wfdbquit(); - 79 exit(0); - 80 } + 37 if (isigopen(argv[1], s, nsig) != nsig) + 38 exit(3); + 39 if (isigsettime(strtim(argv[2])) < 0) + 40 exit(4); + 41 if ((nsamp = strtim(argv[3])) < 1) { + 42 fprintf(stderr, "%s: inappropriate value for duration\n", + 43 argv[0]); + 44 exit(5); + 45 } + 46 if (osigopen("16l", s, nsig) != nsig) + 47 exit(6); + 48 + 49 (void)sample(0, 0L); + 50 for (t = 0; t < nsamp && sample_valid(); t++) { + 51 for (j = 0; j < nsig; j++) { + 52 for (i = 0, vv = 0.; i < nc; i++) + 53 if (c[i] != 0.) vv += c[i]*sample(j, t+i); + 54 v[j] = (int)vv; + 55 } + 56 if (putvec(v) < 0) break; + 57 } + 58 + 59 (void)newheader("out"); + 60 wfdbquit(); + 61 exit(0); + 62 } (See `http://www.physionet.org/physiotools/wfdb/examples/example7.c' for a copy of this program.) *Notes:* -_Line 3:_ - `BUFLN' must be a power of 2 (why? see lines 16 and 18), and it - should be larger than the length of the filter (i.e., the caller - should not look back further than `BUFLN-1' samples into the past, - relative to the most recent sample that has been read). - -_Lines 7-19:_ - This function supplies input samples to the `main' routine as - needed, and frees the `main' routine of the need to read them in - strict time order. The `sample' function returns the sample from - signal `s' with adjusted sample number `t' (i.e., relative to the - beginning of the segment to be processed), either by retrieving it - from a circular buffer of samples recently read, or by reading it - using `getvec'. The ugly-looking `getvec' argument is simply the - next slot in the circular buffer; note that `tt' is an internal - "clock" for `sample', which records the adjusted sample number of - the most recently read sample. In this program, the test in line - 13 is redundant (why?) and might be removed for efficiency's sake. - -_Lines 37-39:_ +_Lines 20-22:_ If no coefficients are provided on the command line, the program will simply copy the selected segment of the input signals. -_Lines 40-46:_ +_Lines 23-28:_ If there are more coefficients than there are samples in the circular buffer, or if memory cannot be allocated for the coefficient vector, the program cannot work properly, so it exits - with an error message. In lines 45 and 46, the ASCII strings that + with an error message. In lines 27 and 28, the ASCII strings that represent the coefficients are converted to `double' format and stored in the coefficient vector. -_Lines 47-59:_ +_Lines 29-40:_ The record name is `argv[1]', and the start time is `argv[2]'; if the record can't be opened, or the start time is inappropriate, the program exits. See the previous example for details on how `isigopen' is used. -_Lines 60-64:_ +_Lines 41-45:_ The DURATION argument should be a time interval in HH:MM:SS format; `strtim' converts it to the appropriate number of samples. -_Lines 65-66:_ +_Lines 46-47:_ The output signals will be written to files in the current directory according to the specifications for record `16l' (*note Piped and Local Records::). If we can't write as many output signals as there are input signals, the program exits. -_Lines 68-75:_ +_Line 49:_ + Here, `signal' is invoked only for its side effect; assuming that + any samples can be read from the specified record, `sample(0, 0L)' + returns a valid sample, so that the value returned by + `sample_valid()' is true (1). + +_Lines 50-57:_ Here's where the work is done. The outer loop is executed once per sample vector, the middle loop once per signal, and the inner loop - once per coefficient. In line 71, we retrieve an input sample, + once per coefficient. In line 53, we retrieve an input sample, multiply it by a filter coefficient, and add it to a running sum. - The sum (`vv') is initialized to zero in line 70 before we begin, - and is converted to an `int' in line 72 when we are finished. Once + The sum (`vv') is initialized to zero in line 52 before we begin, + and is converted to an `int' in line 54 when we are finished. Once an entire sample vector has been filtered, it is written out in - line 74. The entire process is repeated up to `nsamp' times, or + line 56. The entire process is repeated up to `nsamp' times, or until we run out of input samples. -_Line 77:_ +_Line 59:_ The program creates a header file for record `out', using the signal specifications from record `16l' and the sampling frequency from the input record. @@ -965,174 +1165,4 @@ _Lines 86-88:_ At the end of the loop, the samples are shifted through the `tN' variables and another sample is read. - - -File: wpg, Node: Exercises, Next: Glossary, Prev: Examples, Up: Top - -Exercises -********* - - These exercises are based on the material in the previous chapters. -Answers to some of them are at the back of the book, but try to work -through them first. - - 1. Type in the first program from the previous chapter, compile it, - and run it. If you know that you will need to read WFDB files - from non-standard locations, remember to set and export the - environment variable `WFDB' (*note WFDB path::). It is a good - idea to include this step in your `.profile', `.cshrc', or - `autoexec.bat'. As input, try record `100s', input annotator - `atr', and output annotator `normal'. The program should finish - in five seconds or less. The annotations will have been written - into a file called `100s.nor' in the current directory. Now type - "`rdann -r 100s -a atr'" and observe the output for a few seconds, - then try "`rdann -r 100s -a nor'" and notice the difference. - - 2. Modify the program from the previous exercise so that the non-QRS - annotations are put into a second output annotation file. - Remember that you will need three annotation files in all (one - input and two output). - - 3. The next five short exercises are to be worked out on paper, - although you may wish to check your work on the computer. All of - them assume that we are given a signal sampled at 100 Hz with the - following specifications: - fname = "signal.dat" - desc = "BP" - units = "mmHg" - gain = 10 - initval = 80 - group = 0 - fmt = 212 - spf = 1 - bsize = 0 - adcres = 12 - adczero = 0 - baseline = -300 - nsamp = 1000000 - cksum = 3109 - For starters, convert a sample value of 280 into physical units. - - 4. Convert 120 mmHg into adus. - - 5. What are the maximum and minimum possible sample values in adu? in - mmHg? - - 6. How large is `signal.dat', in bytes? How much space could we save - if we converted it to format 8 (eight-bit first-differences)? - What is the maximum slew rate (in mmHg/second) that we can - represent in that format? - - 7. Oops! We have just discovered that the maximum slew rate in our - signal is 1500 mmHg/sec. Is there any way to store it at full - precision in one of the supported formats, that saves space - compared to its present format? - - 8. Figure out how to plot or display the first 1000 points from - signal 0 of a record in amplitude vs. time format. You may wish - to begin with the example program from the first chapter. Arrange - for the record name to be read from the command line (see `K&R', - pp. 114-115, if you don't know how to do this). - - 9. Try plotting VCGs by modifying the program from the previous - exercise to plot pairs of samples from each of two signals rather - than sample number/value pairs. - - 10. Modify the program from the previous exercise, or Example 2 from - the previous chapter, so that you can specify a segment of the - record to be processed with start and end times. For example, the - command - YOUR-PROGRAM RECORD 10:0 10:10 - should skip the first ten minutes, then process the next ten - seconds of signals from RECORD. - - 11. Wesley Q. Phortran, IV, wrote this program to print beat times (in - minutes and seconds) and R-R intervals for the reference - annotation file of record `100'. Why doesn't it work? - 1 #include - 2 - 3 main() - 4 { - 5 WFDB_Annotation *annot; - 6 WFDB_Anninfo ai; - 7 int t; - 8 - 9 ai.name = "atr"; - 10 ai.stat = WFDB_READ; - 11 if (annopen(100, ai, 1)) { - 12 while (getann(1, annot)) { - 13 printf("%s\t(%d)\t%s\n", timstr(annot.time), - 14 annot.time, mstimstr(annot.time - t)); - 15 t = annot.time; - 16 } - 17 } - 18 } - Extra credit: Without actually trying it out, what _does_ it - produce on the standard output? - - 12. Using `isigsettime' on a format 8 signal introduces a random offset - into the signal, since the contents of a format 8 signal file are - first differences rather than amplitudes. For an AC-coupled - signal such as an ECG, this is usually inconsequential, but a - DC-coupled signal such as a blood pressure signal is usually - useful only if absolute levels are known. If we store such a - signal in format 8, we must read it sequentially from the - beginning in order to get correct sample values. If we intend to - do a lot of non-sequential processing of such a signal, it may be - worthwhile to build a table containing the correct sample values - at periodic intervals; then we can use `isigsettime' to skip to a - sample in the table, and read forward sequentially from that - point. Write a program to build such a table, and wrappers for - `isigsettime' and `getvec' to give random access to format 8 - signal files without introducing offset errors. On your system, - how many sample intervals should be allowed between table entries - in order to obtain an `isigsettime' equivalent that executes in an - average of 100 msec or less? - - 13. This exercise assumes that you have access to the MIT-BIH - Arrhythmia Database, either on a CD-ROM or via PhysioNet. Since - the 360 Hz sampling frequency used in that database is an integer - multiple of 60 Hz, it is quite easy to design a 60 Hz notch filter - that can be applied to the database. Write a program that filters - two input signals and writes out the filtered data using `putvec' - (*note Example 7::, for a model program). Try it out on MIT-BIH - record `122' (or use record `mitdb/x_mitdb/x_122' from PhysioNet). - Use your programs from the previous exercises to display your - output. - - 14. If you used Example 7 as a model in the previous exercise, you may - have noticed that it is quite slow. Make it faster by arranging - for `sample' to return a pointer to a vector of samples from all - signals (thereby reducing the number of function calls). Speed it - up further by defining a macro that calls the function only if the - proper sample vector is not already in the circular buffer; - otherwise the macro should evaluate to a pointer to the correct - sample vector. - - 15. Prof. Nottin Ventedhier says, "Real programmers don't use - inefficient library I/O routines -- they write their own, in - assembly language." Implement a version of the QRS detector in - Example 10 _without_ using the WFDB library. (To keep it simple, - assume that only one input format -- of your choice -- needs to be - supported.) How much faster than the original is your version? - - 16. (Non-trivial) Write a QRS detector that is independent of sampling - frequency. Some useful constants (for adult human ECGs): average - normal QRS duration = 80 milliseconds, average QRS amplitude = 1 - millivolt, average R-R interval = 1 second; assume that upper and - lower limits for these quantities are within a factor of 3 of the - average values. Run your detector on MIT-BIH Arrhythmia Database - record `200'. (This record is available on PhysioNet. If you - have a NETFILES-enabled WFDB library, use the default WFDB path, - and open record `mitdb/200'; otherwise, download the record from - `http://www.physionet.org/physiobank/database/mitdb/'.) Read the - documentation on the annotation comparator, `bxb', and figure out - how to use it to compare the annotation file produced by your - program against the reference annotator `atr'. How does your - detector compare to Example 10? - - 17. If the previous exercise was too easy, modify your detector so - that the annotations it generates match those in the `atr' file. - Copying the `atr' file is not permitted. You may find this rather - difficult. Good luck! diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-6 wfdb-10.3.0/doc/wpg/info/wpg-6 --- wfdb-10.2.9/doc/wpg/info/wpg-6 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-6 Tue Nov 26 02:06:55 2002 @@ -6,6 +6,176 @@ END-INFO-DIR-ENTRY  +File: wpg, Node: Exercises, Next: Glossary, Prev: Examples, Up: Top + +Exercises +********* + + These exercises are based on the material in the previous chapters. +Answers to some of them are at the back of the book, but try to work +through them first. + + 1. Type in the first program from the previous chapter, compile it, + and run it. If you know that you will need to read WFDB files + from non-standard locations, remember to set and export the + environment variable `WFDB' (*note WFDB path::). It is a good + idea to include this step in your `.profile', `.cshrc', or + `autoexec.bat'. As input, try record `100s', input annotator + `atr', and output annotator `normal'. The program should finish + in five seconds or less. The annotations will have been written + into a file called `100s.nor' in the current directory. Now type + "`rdann -r 100s -a atr'" and observe the output for a few seconds, + then try "`rdann -r 100s -a nor'" and notice the difference. + + 2. Modify the program from the previous exercise so that the non-QRS + annotations are put into a second output annotation file. + Remember that you will need three annotation files in all (one + input and two output). + + 3. The next five short exercises are to be worked out on paper, + although you may wish to check your work on the computer. All of + them assume that we are given a signal sampled at 100 Hz with the + following specifications: + fname = "signal.dat" + desc = "BP" + units = "mmHg" + gain = 10 + initval = 80 + group = 0 + fmt = 212 + spf = 1 + bsize = 0 + adcres = 12 + adczero = 0 + baseline = -300 + nsamp = 1000000 + cksum = 3109 + For starters, convert a sample value of 280 into physical units. + + 4. Convert 120 mmHg into adus. + + 5. What are the maximum and minimum possible sample values in adu? in + mmHg? + + 6. How large is `signal.dat', in bytes? How much space could we save + if we converted it to format 8 (eight-bit first-differences)? + What is the maximum slew rate (in mmHg/second) that we can + represent in that format? + + 7. Oops! We have just discovered that the maximum slew rate in our + signal is 1500 mmHg/sec. Is there any way to store it at full + precision in one of the supported formats, that saves space + compared to its present format? + + 8. Figure out how to plot or display the first 1000 points from + signal 0 of a record in amplitude vs. time format. You may wish + to begin with the example program from the first chapter. Arrange + for the record name to be read from the command line (see `K&R', + pp. 114-115, if you don't know how to do this). + + 9. Try plotting VCGs by modifying the program from the previous + exercise to plot pairs of samples from each of two signals rather + than sample number/value pairs. + + 10. Modify the program from the previous exercise, or Example 2 from + the previous chapter, so that you can specify a segment of the + record to be processed with start and end times. For example, the + command + YOUR-PROGRAM RECORD 10:0 10:10 + should skip the first ten minutes, then process the next ten + seconds of signals from RECORD. + + 11. Wesley Q. Phortran, IV, wrote this program to print beat times (in + minutes and seconds) and R-R intervals for the reference + annotation file of record `100'. Why doesn't it work? + 1 #include + 2 + 3 main() + 4 { + 5 WFDB_Annotation *annot; + 6 WFDB_Anninfo ai; + 7 int t; + 8 + 9 ai.name = "atr"; + 10 ai.stat = WFDB_READ; + 11 if (annopen(100, ai, 1)) { + 12 while (getann(1, annot)) { + 13 printf("%s\t(%d)\t%s\n", timstr(annot.time), + 14 annot.time, mstimstr(annot.time - t)); + 15 t = annot.time; + 16 } + 17 } + 18 } + Extra credit: Without actually trying it out, what _does_ it + produce on the standard output? + + 12. Using `isigsettime' on a format 8 signal introduces a random offset + into the signal, since the contents of a format 8 signal file are + first differences rather than amplitudes. For an AC-coupled + signal such as an ECG, this is usually inconsequential, but a + DC-coupled signal such as a blood pressure signal is usually + useful only if absolute levels are known. If we store such a + signal in format 8, we must read it sequentially from the + beginning in order to get correct sample values. If we intend to + do a lot of non-sequential processing of such a signal, it may be + worthwhile to build a table containing the correct sample values + at periodic intervals; then we can use `isigsettime' to skip to a + sample in the table, and read forward sequentially from that + point. Write a program to build such a table, and wrappers for + `isigsettime' and `getvec' to give random access to format 8 + signal files without introducing offset errors. On your system, + how many sample intervals should be allowed between table entries + in order to obtain an `isigsettime' equivalent that executes in an + average of 100 msec or less? + + 13. This exercise assumes that you have access to the MIT-BIH + Arrhythmia Database, either on a CD-ROM or via PhysioNet. Since + the 360 Hz sampling frequency used in that database is an integer + multiple of 60 Hz, it is quite easy to design a 60 Hz notch filter + that can be applied to the database. Write a program that filters + two input signals and writes out the filtered data using `putvec' + (*note Example 7::, for a model program). Try it out on MIT-BIH + record `122' (or use record `mitdb/x_mitdb/x_122' from PhysioNet). + Use your programs from the previous exercises to display your + output. + + 14. If you used Example 7 as a model in the previous exercise, you may + have noticed that it is quite slow. Make it faster by arranging + for `sample' to return a pointer to a vector of samples from all + signals (thereby reducing the number of function calls). Speed it + up further by defining a macro that calls the function only if the + proper sample vector is not already in the circular buffer; + otherwise the macro should evaluate to a pointer to the correct + sample vector. + + 15. Prof. Nottin Ventedhier says, "Real programmers don't use + inefficient library I/O routines -- they write their own, in + assembly language." Implement a version of the QRS detector in + Example 10 _without_ using the WFDB library. (To keep it simple, + assume that only one input format -- of your choice -- needs to be + supported.) How much faster than the original is your version? + + 16. (Non-trivial) Write a QRS detector that is independent of sampling + frequency. Some useful constants (for adult human ECGs): average + normal QRS duration = 80 milliseconds, average QRS amplitude = 1 + millivolt, average R-R interval = 1 second; assume that upper and + lower limits for these quantities are within a factor of 3 of the + average values. Run your detector on MIT-BIH Arrhythmia Database + record `200'. (This record is available on PhysioNet. If you + have a NETFILES-enabled WFDB library, use the default WFDB path, + and open record `mitdb/200'; otherwise, download the record from + `http://www.physionet.org/physiobank/database/mitdb/'.) Read the + documentation on the annotation comparator, `bxb', and figure out + how to use it to compare the annotation file produced by your + program against the reference annotator `atr'. How does your + detector compare to Example 10? + + 17. If the previous exercise was too easy, modify your detector so + that the annotations it generates match those in the `atr' file. + Copying the `atr' file is not permitted. You may find this rather + difficult. Good luck! + + File: wpg, Node: Glossary, Next: Installation, Prev: Exercises, Up: Top Glossary @@ -481,6 +651,8 @@ Software Package. * Unix installation:: Installing the WFDB Software Package on Unix, GNU/Linux, and similar systems. +* MacOS/X installation:: Installing the WFDB Software Package under + MacOS/X (Darwin). * MS-Windows installation:: Installing the WFDB Software Package on MS-Windows PCs. * Other installation:: Installing the WFDB Software Package on other systems. @@ -499,7 +671,7 @@ operating systems, are also usually available there.  -File: wpg, Node: Unix installation, Next: MS-Windows installation, Prev: Distribution, Up: Installation +File: wpg, Node: Unix installation, Next: MacOS/X installation, Prev: Distribution, Up: Installation Unix, GNU/Linux, and similar operating systems ============================================== @@ -554,7 +726,34 @@ will generally require between 1 and 10 minutes.  -File: wpg, Node: MS-Windows installation, Next: Other installation, Prev: Unix installation, Up: Installation +File: wpg, Node: MacOS/X installation, Next: MS-Windows installation, Prev: Unix installation, Up: Installation + +Mac OS/X (Darwin) +================= + + The WFDB Software Package has been successfully compiled under Mac +OS/X 10.2 (Darwin 6.0.1). It should also work under 10.1, but this has +not been tested. + + Before compiling the WFDB Software Package, download and install: + + * Mac OS/X Developer Tools (from + `http://developer.apple.com/macosx/') + + * XDarwin (from Fink, `http://fink.sourceforge.net/'; sources from + `http://www.xdarwin.org/') + + Now follow the instructions in the previous section for Unix or +GNU/Linux. + + At this time, an incomplete port of XView to Darwin is available from +the GNU-Darwin project (`http://gnu-darwin.sourceforge.net/'). You may +wish to see if a complete XView port is available; if so, it should be +possible to compile WAVE under Mac OS/X as part of the installation of +the WFDB Software Package. + + +File: wpg, Node: MS-Windows installation, Next: Other installation, Prev: MacOS/X installation, Up: Installation MS-Windows ========== @@ -864,102 +1063,4 @@ directory of the MIT-BIH Arrhythmia Database CD-ROM. These records are among those specified as standard test material by EC38 (section 4.2.14.2) and EC57 (section 3.2). - - -File: wpg, Node: Signal processing, Next: Graphics, Prev: Evaluation, Up: WFDB Applications - -Signal Processing Applications -============================== - - rdsamp -r RECORD [ OPTIONS ... ] - wrsamp -r RECORD [ OPTIONS ... ] - snip -i INPUT-RECORD -n NEW-RECORD [ OPTIONS ... ] - xform -i INPUT-RECORD [ OPTIONS ... ] - fir [ OPTIONS ... ] -c COEFFICIENT ... - sigamp -r RECORD [ OPTIONS ...] - sqrs -r RECORD [ OPTIONS ... ] - sample [ OPTIONS ... ] - calsig -r RECORD [ OPTIONS ... ] - - `rdsamp' prints samples from the specified record; `-f' and `-t' -options may be used to specify a range of sample numbers, and a subset -of signal numbers may be selected using the `-s' option. The output of -`rdsamp', or any similar text, can be converted into a WFDB record -using `wrsamp'. - - To copy an excerpt of a longer record, use `snip', which creates new -header and signal files for NEW-RECORD in the current directory. The -beginning and end of the excerpt are specified using `-f' and `-t' -options as for `rdsamp'. Annotator names may follow a `-a' option; in -this case excerpts from the specified annotation files are copied as -well (the annotations are appropriately time-shifted). - - `xform' is a more general version of `snip'; its main uses are for -reformatting, rescaling, and sampling rate conversion. You may create a -`hea' file specifying the desired format, sampling frequency, ADC zero -levels, signal gains, etc., and supply it to `xform' using the `-o' -option; if you do not do so, `xform' obtains the required information -interactively. `xform' accepts all of the options used by `snip', as -well as several others. - - Program `fir' is a general-purpose FIR filter for WFDB records, -similar to the one discussed in chapter 6 (*note Example 7::). - - `sigamp' measures signal amplitudes (either baseline-corrected RMS -amplitudes or peak-to-peak amplitudes); it may be useful for -calibrating signals (together with `calsig') or for determining signal -gains for `nst'. - - `sqrs' is a slightly modified version of the QRS detector discussed -in chapter 6 (*note Example 10::). Options allow specification of the -signal and interval to be analyzed and the detection threshold. - - Program `sample' is an MS-DOS application that uses a Microstar -Laboratories DAP 1200- or 2400-series ISA (AT bus) analog interface -board (*note Sources::) to generate database records from analog -signals, or to generate analog signals from database records. If you -wish to use other hardware for these purposes, refer to chapter 6 -(*note Example 8::) and to the source for `sample' as models. - - If you create your own database records using `sample' or other -means, program `calsig' may be useful for determining signal gains and -offsets if your signals include standard calibration pulses or -identifiable signal levels. `calsig' incorporates two independent -algorithms for measuring calibration pulses; it rewrites header files -based on its measurements. - - -File: wpg, Node: Graphics, Prev: Signal processing, Up: WFDB Applications - -Graphical Applications -====================== - - wave -r RECORD [ -a ANNOTATOR ] - view RECORD ANNOTATOR - wview RECORD ANNOTATOR - pschart [ [ OPTIONS ... ] SCRIPT ... ] - psfd [ [ OPTIONS ... ] SCRIPT ... ] - - `wave' is an X Window System client application for viewing and -editing WFDB records. (`wave' is not included in the WFDB software -package, but is available separately; *note Sources::.) `wave' can be -run on Unix systems, and can be accessed remotely using networked PCs or -other systems for which X11 servers are available. Run `wave' without -any arguments to obtain instructions for printing its on-line manual. - - `view', included on the MIT-BIH Arrhythmia Database and European ST-T -Database CD-ROMs, among others, is an MS-DOS application for viewing -WFDB records on CGA, EGA, VGA, SVGA, XGA, or Hercules graphics-capable -PCs. See `bin.doc' in the `bin' directory of the CD-ROM for more -information. - - `wview', included on recent (1995 and later) CD-ROMs and also -available separately (*note Sources::, is an MS-Windows application for -viewing WFDB records. It has most of the display capabilities of -`wave', but lacks support for annotation editing. - - `pschart' and `psfd' produce annotated "chart recordings" and -"full-disclosure" plots that can be printed on PostScript devices. -These programs were used to prepare the `MIT-BIH Arrhythmia Database -Directory' and the `European ST-T Database Directory'. diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-7 wfdb-10.3.0/doc/wpg/info/wpg-7 --- wfdb-10.2.9/doc/wpg/info/wpg-7 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-7 Tue Nov 26 02:06:55 2002 @@ -6,6 +6,104 @@ END-INFO-DIR-ENTRY  +File: wpg, Node: Signal processing, Next: Graphics, Prev: Evaluation, Up: WFDB Applications + +Signal Processing Applications +============================== + + rdsamp -r RECORD [ OPTIONS ... ] + wrsamp -r RECORD [ OPTIONS ... ] + snip -i INPUT-RECORD -n NEW-RECORD [ OPTIONS ... ] + xform -i INPUT-RECORD [ OPTIONS ... ] + fir [ OPTIONS ... ] -c COEFFICIENT ... + sigamp -r RECORD [ OPTIONS ...] + sqrs -r RECORD [ OPTIONS ... ] + sample [ OPTIONS ... ] + calsig -r RECORD [ OPTIONS ... ] + + `rdsamp' prints samples from the specified record; `-f' and `-t' +options may be used to specify a range of sample numbers, and a subset +of signal numbers may be selected using the `-s' option. The output of +`rdsamp', or any similar text, can be converted into a WFDB record +using `wrsamp'. + + To copy an excerpt of a longer record, use `snip', which creates new +header and signal files for NEW-RECORD in the current directory. The +beginning and end of the excerpt are specified using `-f' and `-t' +options as for `rdsamp'. Annotator names may follow a `-a' option; in +this case excerpts from the specified annotation files are copied as +well (the annotations are appropriately time-shifted). + + `xform' is a more general version of `snip'; its main uses are for +reformatting, rescaling, and sampling rate conversion. You may create a +`hea' file specifying the desired format, sampling frequency, ADC zero +levels, signal gains, etc., and supply it to `xform' using the `-o' +option; if you do not do so, `xform' obtains the required information +interactively. `xform' accepts all of the options used by `snip', as +well as several others. + + Program `fir' is a general-purpose FIR filter for WFDB records, +similar to the one discussed in chapter 6 (*note Example 7::). + + `sigamp' measures signal amplitudes (either baseline-corrected RMS +amplitudes or peak-to-peak amplitudes); it may be useful for +calibrating signals (together with `calsig') or for determining signal +gains for `nst'. + + `sqrs' is a slightly modified version of the QRS detector discussed +in chapter 6 (*note Example 10::). Options allow specification of the +signal and interval to be analyzed and the detection threshold. + + Program `sample' is an MS-DOS application that uses a Microstar +Laboratories DAP 1200- or 2400-series ISA (AT bus) analog interface +board (*note Sources::) to generate database records from analog +signals, or to generate analog signals from database records. If you +wish to use other hardware for these purposes, refer to chapter 6 +(*note Example 8::) and to the source for `sample' as models. + + If you create your own database records using `sample' or other +means, program `calsig' may be useful for determining signal gains and +offsets if your signals include standard calibration pulses or +identifiable signal levels. `calsig' incorporates two independent +algorithms for measuring calibration pulses; it rewrites header files +based on its measurements. + + +File: wpg, Node: Graphics, Prev: Signal processing, Up: WFDB Applications + +Graphical Applications +====================== + + wave -r RECORD [ -a ANNOTATOR ] + view RECORD ANNOTATOR + wview RECORD ANNOTATOR + pschart [ [ OPTIONS ... ] SCRIPT ... ] + psfd [ [ OPTIONS ... ] SCRIPT ... ] + + `wave' is an X Window System client application for viewing and +editing WFDB records. (`wave' is not included in the WFDB software +package, but is available separately; *note Sources::.) `wave' can be +run on Unix systems, and can be accessed remotely using networked PCs or +other systems for which X11 servers are available. Run `wave' without +any arguments to obtain instructions for printing its on-line manual. + + `view', included on the MIT-BIH Arrhythmia Database and European ST-T +Database CD-ROMs, among others, is an MS-DOS application for viewing +WFDB records on CGA, EGA, VGA, SVGA, XGA, or Hercules graphics-capable +PCs. See `bin.doc' in the `bin' directory of the CD-ROM for more +information. + + `wview', included on recent (1995 and later) CD-ROMs and also +available separately (*note Sources::, is an MS-Windows application for +viewing WFDB records. It has most of the display capabilities of +`wave', but lacks support for annotation editing. + + `pschart' and `psfd' produce annotated "chart recordings" and +"full-disclosure" plots that can be printed on PostScript devices. +These programs were used to prepare the `MIT-BIH Arrhythmia Database +Directory' and the `European ST-T Database Directory'. + + File: wpg, Node: Extensions, Next: Sources, Prev: WFDB Applications, Up: Top Extensions diff -Naur wfdb-10.2.9/doc/wpg/info/wpg-8 wfdb-10.3.0/doc/wpg/info/wpg-8 --- wfdb-10.2.9/doc/wpg/info/wpg-8 Sat Oct 26 22:35:58 2002 +++ wfdb-10.3.0/doc/wpg/info/wpg-8 Tue Nov 26 02:06:55 2002 @@ -607,6 +607,8 @@ * putinfo (4.0): putinfo. * putvec: putvec. * sampfreq: sampfreq. +* sample (10.3.0): sample. +* sample_valid (10.3.0): sample. * setanndesc (5.3): annstr and strann. * setannpos (6.0): Mapping macros. * setannstr (5.3): annstr and strann. @@ -651,7 +653,7 @@ WFDB Programmer's Guide Tenth Edition (revised and with additions for WFDB library version -10.2.9) 26 October 2002 +10.3.0) 26 November 2002 George B. Moody diff -Naur wfdb-10.2.9/doc/wpg-src/Makefile wfdb-10.3.0/doc/wpg-src/Makefile --- wfdb-10.2.9/doc/wpg-src/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/doc/wpg-src/Makefile Tue Nov 26 13:40:19 2002 @@ -65,12 +65,12 @@ # wpg.info' again. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -87,13 +87,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -202,6 +202,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/doc/wpg-src/ctotexi.c wfdb-10.3.0/doc/wpg-src/ctotexi.c --- wfdb-10.2.9/doc/wpg-src/ctotexi.c Fri Dec 14 11:35:49 2001 +++ wfdb-10.3.0/doc/wpg-src/ctotexi.c Sat Nov 23 22:56:18 2002 @@ -21,6 +21,7 @@ (MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software, please visit PhysioNet (http://www.physionet.org/). _______________________________________________________________________________ +*/ #include diff -Naur wfdb-10.2.9/doc/wpg-src/wpg0.tex wfdb-10.3.0/doc/wpg-src/wpg0.tex --- wfdb-10.2.9/doc/wpg-src/wpg0.tex Sun Oct 27 00:03:23 2002 +++ wfdb-10.3.0/doc/wpg-src/wpg0.tex Tue Nov 26 02:06:04 2002 @@ -488,6 +488,43 @@ WFDB Software Package distribution, for information on any more recent changes that may not be described here. +@unnumberedsubsec Changes in version 10.3.0 + +Fixed bugs in @file{lib/sample.c} that caused improper accounting of signal +group numbers when reading from two or more records at the same time (as in +@file{nst}), a bug that caused a segfault in @file{nst}, and a bug that +referenced uninitialized memory in @code{newheader} if @code{nsig} = 0. + +The WFDB Software Package has been ported to MacOS/X (Darwin), +version 10.2 (the port should also work under 10.1 but this +has not been tested and will not be supported). + +It is now possible to generate a shared WFDB library (DLL) +under MS-Windows using Cygwin/gcc. + +Added functions @code{sample} and @code{sample_valid} to the WFDB library +(in @file{lib/signal.c}). @code{sample(s, t)} returns the sample at +time (sample number) @code{t} from signal @code{s}, handling all +necessary buffering internally and allowing the caller to treat the +signal file as a virtual array of randomly accessible samples. +@code{sample_valid} can be invoked to check if the most recent value +returned by @code{sample} was valid (e.g., to see if the end of the +input was reached). For an example of the use of these functions, see +@file{app/wqrs.c}. + +@unnumberedsubsec Changes in version 10.2.9 + +Fixed a bug in example 9 in this guide (introduced in version 10.2.0). + +Updated @file{lib/wfdbdll.def} and the @file{Makefile.dos} files in several +directories. These have not been tested in recent years and may need further +revisions; feedback is welcome. + +Corrected persistent problems with generating PDF versions of the manuals for +the desired page size, and added hyperlinks to the PDF version of this guide. + +(WFDB library version 10.2.8 was identical to 10.2.7.) + @unnumberedsubsec Changes in version 10.2.7 Added a workaround to @code{wfdb_fclose} (in @file{lib/wfdbio.c}) so that @@ -531,7 +568,7 @@ conversions, however, it is necessary to round all values down (e.g., from -1.5 to -2 rather than up to -1). -Fixed a memory leak in wfdb_fclose() (in lib/wfdbio.h). Thanks to +Fixed a memory leak in @code{wfdb_fclose} (in @file{lib/wfdbio.h}). Thanks to Ion Gazta@~naga. @unnumberedsubsec Changes in version 10.2.5 @@ -1536,7 +1573,6 @@ @c @group @example #include -#include #include main() @@ -2363,6 +2399,7 @@ * isigsettime:: Setting time of next samples read. * isgsettime:: As above, but for one signal group only. * iannsettime:: Setting time of next annotations read. +* sample:: A random access interface to input signals. @end menu @c @group @@ -2427,7 +2464,7 @@ one record is open simultaneously (@pxref{Multiple Record Access}). @c @group -@node iannsettime, , isgsettime, non-sequential +@node iannsettime, sample, isgsettime, non-sequential @unnumberedsubsec iannsettime @findex iannsettime @cindex annotations (non-sequential access) @@ -2471,6 +2508,51 @@ before using @code{iannsettime}. The bug was corrected in version 4.0 of the library. +@c @group +@node sample, , iannsettime, non-sequential +@unnumberedsubsec sample and sample_valid +@findex sample (10.3.0) +@findex sample_valid (10.3.0) + +@example +WFDB_Sample sample(WFDB_Signal @var{s}, WFDB_Time @var{t}) +int sample_valid(void) +@end example +@noindent +@strong{Return:} +@table @asis +@item @i{n} +(from @code{sample}): The value (in raw adus) of sample number @var{t} +in open signal @var{s},if successful, or the value of the previous +successfully read sample. +@item @t{0} +(from @code{sample_valid}): The most recent value returned by +@code{sample} was invalid +@item @t{1} +(from @code{sample_valid}): The most recent value returned by +@code{sample} was valid +@end table +@c @end group + +@noindent +The @code{sample} function allows the caller to read samples of the +currently open input signals in any order. The first argument is a +signal number (a non-negative integer between 0 and @var{nsig}-1, +where @var{nsig} is the number of open input signals), and the second +is a time, expressed as a non-negative sample number. If @code{sample} +is invoked with valid input arguments, the companion function +@code{sample_valid} returns 1. + +There are three ways in which @code{sample} can be invoked with invalid +input arguments. In each case, @code{sample_valid} returns 0, but +@code{sample} attempts to return a reasonable value. If @var{s} is +invalid, @code{sample} returns the value of signal 0 at the specified +time. If @var{t} is negative, the returned value is that of sample +number zero of the specified signal. If @var{t} specifies a sample +number beyond the end of the record, the returned value is that of the +last valid sample of the specified signal. For an example of the use +of @code{sample} and @code{sample_valid}, @pxref{Example 7}. + @page @node conversion, calibration, non-sequential, Functions @section Conversion Functions @@ -5990,8 +6072,8 @@ @cindex digital filter @cindex filter (digital) -This program illustrates a useful technique for obtaining something -close to random access to signals, a technique that is particularly +This program illustrates the use of @code{sample} to obtain random +access to signals, a technique that is particularly useful for implementing digital filters. The first argument is the record name, the second and third arguments are the start time and the duration of the segment to be filtered, and the rest of the arguments @@ -6010,84 +6092,66 @@ @example @i{1} #include @i{2} #include - @i{3} #define BUFLN 512 - @i{4} int nsig, sample_ok = 1; - @i{5} WFDB_Sample *sbuf; - @i{6} - @i{7} sample(s, t) - @i{8} int s; - @i{9} long t; -@i{10} @{ -@i{11} static long tt = -1L; -@i{12} -@i{13} if (t <= tt - BUFLN) -@i{14} fprintf(stderr, "sample: buffer too short\n"); -@i{15} while (t > tt) -@i{16} if (getvec(sbuf + nsig * ((++tt)&(BUFLN-1))) < 0) -@i{17} sample_ok = 0; -@i{18} return (*(sbuf + nsig * (t&(BUFLN-1)) + s)); -@i{19} @} -@i{20} -@i{21} main(argc, argv) -@i{22} int argc; -@i{23} char *argv[]; -@i{24} @{ -@i{25} double *c, one = 1.0, vv, atof(); -@i{26} int i, j, nc = argc - 4; -@i{27} long nsamp, t; -@i{28} static WFDB_Sample *v; -@i{29} static WFDB_Siginfo *s; -@i{30} -@i{31} if (argc < 4) @{ -@i{32} fprintf(stderr, -@i{33} "usage: %s record start duration [ coefficients ... ]\n", -@i{34} argv[0]); -@i{35} exit(1); + @i{3} + @i{4} main(argc, argv) + @i{5} int argc; + @i{6} char *argv[]; + @i{7} @{ + @i{8} double *c, one = 1.0, vv, atof(); + @i{9} int i, j, nc = argc - 4, nsig; +@i{10} long nsamp, t; +@i{11} static WFDB_Sample *v; +@i{12} static WFDB_Siginfo *s; +@i{13} +@i{14} if (argc < 4) @{ +@i{15} fprintf(stderr, +@i{16} "usage: %s record start duration [ coefficients ... ]\n", +@i{17} argv[0]); +@i{18} exit(1); +@i{19} @} +@i{20} if (nc < 1) @{ +@i{21} nc = 1; c = &one; +@i{22} @} +@i{23} else if ((c = (double *)calloc(nc, sizeof(double))) == NULL) @{ +@i{24} fprintf(stderr, "%s: too many coefficients\n", argv[0]); +@i{25} exit(2); +@i{26} @} +@i{27} for (i = 0; i < nc; i++) +@i{28} c[i] = atof(argv[i+4]); +@i{29} if ((nsig = isigopen(argv[1], NULL, 0)) < 1) +@i{30} exit(3); +@i{31} s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); +@i{32} v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); +@i{33} if (s == NULL || v == NULL) @{ +@i{34} fprintf(stderr, "insufficient memory\n"); +@i{35} exit(3); @i{36} @} -@i{37} if (nc < 1) @{ -@i{38} nc = 1; c = &one; -@i{39} @} -@i{40} else if (nc >= BUFLN || -@i{41} (c = (double *)calloc(nc, sizeof(double))) == NULL) @{ -@i{42} fprintf(stderr, "%s: too many coefficients\n", argv[0]); -@i{43} exit(2); -@i{44} @} -@i{45} for (i = 0; i < nc; i++) -@i{46} c[i] = atof(argv[i+4]); -@i{47} if ((nsig = isigopen(argv[1], NULL, 0)) < 1) -@i{48} exit(3); -@i{49} s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); -@i{50} v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); -@i{51} sbuf = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)*BUFLN); -@i{52} if (s == NULL || v == NULL || sbuf == NULL) @{ -@i{53} fprintf(stderr, "insufficient memory\n"); -@i{54} exit(3); -@i{55} @} -@i{56} if (isigopen(argv[1], s, nsig) != nsig) -@i{57} exit(3); -@i{58} if (isigsettime(strtim(argv[2])) < 0) -@i{59} exit(4); -@i{60} if ((nsamp = strtim(argv[3])) < 1) @{ -@i{61} fprintf(stderr, "%s: inappropriate value for duration\n", -@i{62} argv[0]); -@i{63} exit(5); -@i{64} @} -@i{65} if (osigopen("16l", s, nsig) != nsig) -@i{66} exit(6); -@i{67} -@i{68} for (t = 0; t < nsamp && sample_ok; t++) @{ -@i{69} for (j = 0; j < nsig; j++) @{ -@i{70} for (i = 0, vv = 0.; i < nc; i++) -@i{71} if (c[i] != 0.) vv += c[i]*sample(j, t+i); -@i{72} v[j] = (int)vv; -@i{73} @} -@i{74} if (putvec(v) < 0) break; -@i{75} @} -@i{76} -@i{77} (void)newheader("out"); -@i{78} wfdbquit(); -@i{79} exit(0); -@i{80} @} +@i{37} if (isigopen(argv[1], s, nsig) != nsig) +@i{38} exit(3); +@i{39} if (isigsettime(strtim(argv[2])) < 0) +@i{40} exit(4); +@i{41} if ((nsamp = strtim(argv[3])) < 1) @{ +@i{42} fprintf(stderr, "%s: inappropriate value for duration\n", +@i{43} argv[0]); +@i{44} exit(5); +@i{45} @} +@i{46} if (osigopen("16l", s, nsig) != nsig) +@i{47} exit(6); +@i{48} +@i{49} (void)sample(0, 0L); +@i{50} for (t = 0; t < nsamp && sample_valid(); t++) @{ +@i{51} for (j = 0; j < nsig; j++) @{ +@i{52} for (i = 0, vv = 0.; i < nc; i++) +@i{53} if (c[i] != 0.) vv += c[i]*sample(j, t+i); +@i{54} v[j] = (int)vv; +@i{55} @} +@i{56} if (putvec(v) < 0) break; +@i{57} @} +@i{58} +@i{59} (void)newheader("out"); +@i{60} wfdbquit(); +@i{61} exit(0); +@i{62} @} @end example @noindent @@ -6098,71 +6162,57 @@ @strong{Notes:} @table @emph -@item Line 3: -@code{BUFLN} must be a power of 2 (why? see lines 16 and 18), and it -should be larger than the length of the filter (i.e., the caller should -not look back further than @code{BUFLN-1} samples into the past, -relative to the most recent sample that has been read). - -@item Lines 7--19: -This function supplies input samples to the @code{main} routine as -needed, and frees the @code{main} routine of the need to read them in -strict time order. The @code{sample} function returns the sample from -signal @code{s} with adjusted sample number @code{t} (i.e., relative to -the beginning of the segment to be processed), either by retrieving it -from a circular buffer of samples recently read, or by reading it using -@code{getvec}. The ugly-looking @code{getvec} argument is simply the -next slot in the circular buffer; note that @code{tt} is an internal -``clock'' for @code{sample}, which records the adjusted sample number of -the most recently read sample. In this program, the test in line 13 is -redundant (why?) and might be removed for efficiency's sake. - -@item Lines 37--39: +@item Lines 20--22: If no coefficients are provided on the command line, the program will simply copy the selected segment of the input signals. -@item Lines 40--46: +@item Lines 23--28: If there are more coefficients than there are samples in the circular buffer, or if memory cannot be allocated for the coefficient vector, the program cannot work properly, so it exits with an error message. In -lines 45 and 46, the ASCII strings that represent the coefficients are +lines 27 and 28, the ASCII strings that represent the coefficients are converted to @code{double} format and stored in the coefficient vector. -@item Lines 47--59: +@item Lines 29--40: The record name is @code{argv[1]}, and the start time is @code{argv[2]}; if the record can't be opened, or the start time is inappropriate, the program exits. See the previous example for details on how @code{isigopen} is used. -@item Lines 60--64: +@item Lines 41--45: The @var{duration} argument should be a time interval in @var{HH:MM:SS} format; @code{strtim} converts it to the appropriate number of samples. -@item Lines 65--66: +@item Lines 46--47: The output signals will be written to files in the current directory according to the specifications for record @file{16l} (@pxref{Piped and Local Records}). If we can't write as many output signals as there are input signals, the program exits. -@item Lines 68--75: +@item Line 49: +Here, @code{signal} is invoked only for its side effect; assuming that +any samples can be read from the specified record, @code{sample(0, 0L)} +returns a valid sample, so that the value returned by +@code{sample_valid()} is true (1). + +@item Lines 50--57: Here's where the work is done. The outer loop is executed once per sample vector, the middle loop once per signal, and the inner loop -once per coefficient. In line 71, we retrieve an input sample, +once per coefficient. In line 53, we retrieve an input sample, multiply it by a filter coefficient, and add it to a running sum. -The sum (@code{vv}) is initialized to zero in line 70 before we begin, and is -converted to an @code{int} in line 72 when we are finished. Once -an entire sample vector has been filtered, it is written out in line 74. +The sum (@code{vv}) is initialized to zero in line 52 before we begin, and is +converted to an @code{int} in line 54 when we are finished. Once +an entire sample vector has been filtered, it is written out in line 56. The entire process is repeated up to @code{nsamp} times, or until we run out of input samples. -@item Line 77: +@item Line 59: The program creates a header file for record @file{out}, using the signal specifications from record @file{16l} and the sampling frequency from the input record. @end table - @node Example 8, Example 9, Example 7, Examples @unnumberedsec Example 8: Creating a New Database Record @cindex creating a record @@ -7436,6 +7486,8 @@ Software Package. * Unix installation:: Installing the WFDB Software Package on Unix, GNU/Linux, and similar systems. +* MacOS/X installation:: Installing the WFDB Software Package under + MacOS/X (Darwin). * MS-Windows installation:: Installing the WFDB Software Package on MS-Windows PCs. * Other installation:: Installing the WFDB Software Package on other systems. @@ -7451,7 +7503,7 @@ quick-start guides including installation notes for popular operating systems, are also usually available there. -@node Unix installation, MS-Windows installation, Distribution, Installation +@node Unix installation, MacOS/X installation, Distribution, Installation @unnumberedsec Unix, GNU/Linux, and similar operating systems @cindex libwww @@ -7510,7 +7562,32 @@ Depending on the speed of your system and of your C compiler, @samp{make} will generally require between 1 and 10 minutes. -@node MS-Windows installation, Other installation, Unix installation, Installation +@node MacOS/X installation, MS-Windows installation, Unix installation, Installation +@unnumberedsec Mac OS/X (Darwin) + +The WFDB Software Package has been successfully compiled under Mac OS/X +10.2 (Darwin 6.0.1). It should also work under 10.1, but this has not +been tested. + +Before compiling the WFDB Software Package, download and install: + +@itemize @bullet +@item +Mac OS/X Developer Tools (from @uref{http://developer.apple.com/macosx/}) +@item +XDarwin (from Fink, @uref{http://fink.sourceforge.net/}; sources from +@uref{http://www.xdarwin.org/}) +@end itemize + +Now follow the instructions in the previous section for Unix or GNU/Linux. + +At this time, an incomplete port of XView to Darwin is available from +the GNU-Darwin project (@uref{http://gnu-darwin.sourceforge.net/}). You +may wish to see if a complete XView port is available; if so, it should +be possible to compile WAVE under Mac OS/X as part of the installation +of the WFDB Software Package. + +@node MS-Windows installation, Other installation, MacOS/X installation, Installation @unnumberedsec MS-Windows If you have not already done so, install the Cygwin development environment diff -Naur wfdb-10.2.9/doc/wug-src/Makefile wfdb-10.3.0/doc/wug-src/Makefile --- wfdb-10.2.9/doc/wug-src/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/doc/wug-src/Makefile Tue Nov 26 13:40:19 2002 @@ -55,12 +55,12 @@ # PostScript 'make wug.ps' (requires latex and dvips) # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -77,13 +77,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -192,6 +192,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/examples/Makefile wfdb-10.3.0/examples/Makefile --- wfdb-10.2.9/examples/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/examples/Makefile Tue Nov 26 13:40:19 2002 @@ -34,12 +34,12 @@ # `make clean' to remove them. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -56,13 +56,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -171,6 +171,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/examples/example7.c wfdb-10.3.0/examples/example7.c --- wfdb-10.2.9/examples/example7.c Sun Oct 14 19:50:36 2001 +++ wfdb-10.3.0/examples/example7.c Sat Nov 23 22:46:20 2002 @@ -1,29 +1,12 @@ #include #include -#define BUFLN 512 -int nsig, sample_ok = 1; -WFDB_Sample *sbuf; - -sample(s, t) -int s; -long t; -{ - static long tt = -1L; - - if (t <= tt - BUFLN) - fprintf(stderr, "sample: buffer too short\n"); - while (t > tt) - if (getvec(sbuf + nsig * ((++tt)&(BUFLN-1))) < 0) - sample_ok = 0; - return (*(sbuf + nsig * (t&(BUFLN-1)) + s)); -} main(argc, argv) int argc; char *argv[]; { double *c, one = 1.0, vv, atof(); - int i, j, nc = argc - 4; + int i, j, nc = argc - 4, nsig; long nsamp, t; static WFDB_Sample *v; static WFDB_Siginfo *s; @@ -37,8 +20,7 @@ if (nc < 1) { nc = 1; c = &one; } - else if (nc >= BUFLN || - (c = (double *)calloc(nc, sizeof(double))) == NULL) { + else if ((c = (double *)calloc(nc, sizeof(double))) == NULL) { fprintf(stderr, "%s: too many coefficients\n", argv[0]); exit(2); } @@ -48,8 +30,7 @@ exit(3); s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); - sbuf = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample) * BUFLN); - if (s == NULL || v == NULL || sbuf == NULL) { + if (s == NULL || v == NULL) { fprintf(stderr, "insufficient memory\n"); exit(3); } @@ -65,7 +46,8 @@ if (osigopen("16l", s, nsig) != nsig) exit(6); - for (t = 0; t < nsamp && sample_ok; t++) { + (void)sample(0, 0L); + for (t = 0; t < nsamp && sample_valid(); t++) { for (j = 0; j < nsig; j++) { for (i = 0, vv = 0.; i < nc; i++) if (c[i] != 0.) vv += c[i]*sample(j, t+i); diff -Naur wfdb-10.2.9/examples/pgain.c wfdb-10.3.0/examples/pgain.c --- wfdb-10.2.9/examples/pgain.c Sat Oct 26 08:45:59 2002 +++ wfdb-10.3.0/examples/pgain.c Thu Nov 14 19:06:52 2002 @@ -1,4 +1,3 @@ -#include #include main() diff -Naur wfdb-10.2.9/examples/stdev.c wfdb-10.3.0/examples/stdev.c --- wfdb-10.2.9/examples/stdev.c Sun Nov 25 02:44:29 2001 +++ wfdb-10.3.0/examples/stdev.c Sun Nov 17 15:15:01 2002 @@ -1,8 +1,8 @@ /* file: stdev.c G. Moody 19 August 1996 - Last revised: 25 November 2001 + Last revised: 17 November 2002 ------------------------------------------------------------------------------- stdev: sample application for use with WAVE -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -87,9 +87,9 @@ argv[0], s); exit(2); } - if ((si = (WFDB_Siginfo *)malloc(i, sizeof(WFDB_Siginfo))) == NULL || - (v0 = (WFDB_Sample *)malloc(i, sizeof(WFDB_Sample))) == NULL || - (v1 = (WFDB_Sample *)malloc(i, sizeof(WFDB_Sample))) == NULL) { + if ((si = (WFDB_Siginfo *)malloc(i * sizeof(WFDB_Siginfo))) == NULL || + (v0 = (WFDB_Sample *)malloc(i * sizeof(WFDB_Sample))) == NULL || + (v1 = (WFDB_Sample *)malloc(i * sizeof(WFDB_Sample))) == NULL) { fprintf(stderr, "%s: insufficient memory\n", argv[0]); exit(3); } diff -Naur wfdb-10.2.9/lib/Makefile wfdb-10.3.0/lib/Makefile --- wfdb-10.2.9/lib/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/lib/Makefile Tue Nov 26 13:40:19 2002 @@ -33,12 +33,12 @@ # type `make slib'. # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -54,7 +54,7 @@ # _____________________________________________________________________________ # file: linux-slib.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # This section contains settings suitable for generating an ELF-format shared # library under Linux. @@ -124,6 +124,10 @@ BUILDLIB = gcc -shared -Wl,-soname,$(WFDBLIB_SONAME) `$(LWC) --libs` \ -o $(WFDBLIB) +# BUILDLIB_LDFLAGS is a list of arguments appended to BUILDLIB following +# the list of *.o files (for most platforms, BUILDLIB_LDFLAGS is empty). +BUILDLIB_LDFLAGS = + # LDCONFIG is the name of the program needed to refresh the system's cached # index of shared libraries. LDCONFIG = /sbin/ldconfig @@ -161,7 +165,7 @@ @$(LDCONFIG) || echo Warning: "$(LDCONFIG)" was unsuccessful #______________________________________________________________________________ # file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 21 November 2002 # This section of the Makefile should not need to be changed. INCLUDES = $(INCDIR)/wfdb/wfdb.h $(INCDIR)/wfdb/ecgcodes.h \ @@ -175,7 +179,7 @@ # `make' or `make all': build the WFDB library all: $(OFILES) - $(BUILDLIB) $(OFILES) + $(BUILDLIB) $(OFILES) $(BUILDLIB_LDFLAGS) # `make install': install the WFDB library and headers install: $(INCLUDES) $(LIBDIR) all diff -Naur wfdb-10.2.9/lib/Makefile.tpl wfdb-10.3.0/lib/Makefile.tpl --- wfdb-10.2.9/lib/Makefile.tpl Sat Oct 26 14:53:36 2002 +++ wfdb-10.3.0/lib/Makefile.tpl Thu Nov 21 21:45:22 2002 @@ -1,5 +1,5 @@ # file: Makefile.tpl G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 21 November 2002 # This section of the Makefile should not need to be changed. INCLUDES = $(INCDIR)/wfdb/wfdb.h $(INCDIR)/wfdb/ecgcodes.h \ @@ -13,7 +13,7 @@ # `make' or `make all': build the WFDB library all: $(OFILES) - $(BUILDLIB) $(OFILES) + $(BUILDLIB) $(OFILES) $(BUILDLIB_LDFLAGS) # `make install': install the WFDB library and headers install: $(INCLUDES) $(LIBDIR) all diff -Naur wfdb-10.2.9/lib/signal.c wfdb-10.3.0/lib/signal.c --- wfdb-10.2.9/lib/signal.c Mon Jun 17 18:43:03 2002 +++ wfdb-10.3.0/lib/signal.c Fri Nov 22 23:20:08 2002 @@ -1,5 +1,5 @@ /* file: signal.c G. Moody 13 April 1989 - Last revised: 17 June 2002 wfdblib 10.2.6 + Last revised: 22 November 2002 wfdblib 10.3.0 WFDB library functions for signals _______________________________________________________________________________ @@ -87,7 +87,8 @@ muvadu (converts microvolts to ADC units) aduphys [6.0] (converts ADC units to physical units) physadu [6.0] (converts physical units to ADC units) - + sample [10.3.0](get a sample from a given signal at a given time) + sample_valid [10.3.0](verify that last value returned by sample was valid) (Numbers in brackets in the list above indicate the first version of the WFDB library that included the corresponding function. Functions not so marked have been included in all published versions of the WFDB library.) @@ -275,6 +276,9 @@ static int gvmode = -1; /* getvec mode (WFDB_HIGHRES or WFDB_LOWRES once initialized) */ static int gvc; /* getvec sample-within-frame counter */ +WFDB_Sample *sbuf = NULL; /* buffer used by sample() */ +static int sample_vflag; /* if non-zero, last value returned by sample() + was valid */ /* These variables relate to output signals. */ static unsigned maxosig; /* max number of output signals */ @@ -874,6 +878,11 @@ struct igdata *ig; if (nisig == 0) return; + if (sbuf) { + (void)free(sbuf); + sbuf = NULL; + sample_vflag = 0; + } if (isd) { while (nisig) if (is = isd[--nisig]) { @@ -1530,7 +1539,7 @@ return (-1); /* failed, nisig is unchanged, allocisig emits error */ else nsig = nn; - nn = nigroups + hsd[nsig-1]->info.group + 1; + nn = nigroups + hsd[nsig-nisig-1]->info.group + 1; if (allocigroup(nn) != nn) return (-1); /* failed, allocigroup emits error */ else @@ -1589,7 +1598,7 @@ wfdb_error("isigopen: insufficient memory\n"); return (-3); } - is->info.group = g; + is->info.group = nigroups + g; is->skew = hs->skew; hs = hsd[++si]; is = isd[nisig + ++s]; @@ -2236,7 +2245,7 @@ if (bcount != 0.0) (void)wfdb_fprintf(oheader, "(%g)", bcount); } - (void)wfdb_fprintf(oheader, " %ld", siarray[0].nsamp); + (void)wfdb_fprintf(oheader, " %ld", nsig > 0 ? siarray[0].nsamp : 0L); if (btime != 0L || bdate != (WFDB_Date)0) { if (btime % 1000 == 0) (void)wfdb_fprintf(oheader, " %s", @@ -2815,6 +2824,61 @@ return ((int)(v + 0.5) + b); else return ((int)(v - 0.5) + b); +} + +/* sample(s, t) provides buffered random access to the input signals. The +arguments are the signal number (s) and the sample number (t); the returned +value is the sample from signal s at time t. On return, the global variable +sample_vflag is true (non-zero) if the returned value is valid, false (zero) +otherwise. The caller must open the input signals and must set the global +variable nisig to the number of input signals before invoking sample(). Once +this has been done, the caller may request samples in any order. */ + +#define BUFLN 4096 /* must be a power of 2, see sample() */ + +WFDB_Sample sample(WFDB_Signal s, WFDB_Time t) +{ + static WFDB_Time tt; + + /* Allocate the sample buffer on the first call. */ + if (sbuf == NULL) { + sbuf= (WFDB_Sample *)malloc((unsigned)nisig*BUFLN*sizeof(WFDB_Sample)); + if (sbuf) tt = (WFDB_Time)-1L; + else { + (void)fprintf(stderr, "sample(): insufficient memory\n"); + exit(2); + } + } + if (t < 0L) t = 0L; + /* If the caller has requested a sample that is no longer in the buffer, + or if the caller has requested a sample that is further ahead than the + length of the buffer, we need to reset the signal file pointer(s). + If we do this, we must be sure that the buffer is refilled so that + any subsequent requests for samples between t - BUFLN+1 and t will + receive correct responses. */ + if (t <= tt - BUFLN || t > tt + BUFLN) { + tt = t - BUFLN; + if (tt < 0L) tt = -1L; + else if (isigsettime(tt-1) < 0) exit(2); + } + /* If the requested sample is not yet in the buffer, read and buffer + more samples. If we reach the end of the record, clear sample_vflag + and return the last valid value. */ + while (t > tt) + if (getvec(sbuf + nisig * ((++tt)&(BUFLN-1))) < 0) { + --tt; + sample_vflag = 0; + return (*(sbuf + nisig * (tt&(BUFLN-1)) + s)); + } + /* The requested sample is in the buffer. Set sample_vflag and + return the requested sample. */ + sample_vflag = 1; + return (*(sbuf + nisig * (t&(BUFLN-1)) + s)); +} + +int sample_valid(void) +{ + return (sample_vflag); } /* Private functions (for use by other WFDB library functions only). */ diff -Naur wfdb-10.2.9/lib/wfdb.h wfdb-10.3.0/lib/wfdb.h --- wfdb-10.2.9/lib/wfdb.h Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/lib/wfdb.h Tue Nov 26 13:40:19 2002 @@ -1,5 +1,5 @@ /* file: wfdb.h G. Moody 13 June 1983 - Last revised: 26 October 2002 wfdblib 10.2.9 + Last revised: 14 November 2002 wfdblib 10.3.0 WFDB library type, constant, structure, and function interface definitions _______________________________________________________________________________ @@ -32,8 +32,8 @@ /* WFDB library version. */ #define WFDB_MAJOR 10 -#define WFDB_MINOR 2 -#define WFDB_RELEASE 9 +#define WFDB_MINOR 3 +#define WFDB_RELEASE 0 #define WFDB_NETFILES 1 /* if 1, library includes code for HTTP, FTP clients */ /* Determine what type of compiler is being used. */ @@ -333,6 +333,43 @@ #ifdef wfdb_KRC #undef wfdb_KRC #undef signed +#endif + +/* Include some useful function declarations. This section includes standard + header files if available and provides alternative declarations for those + platforms that need them. + + The ANSI/ISO C standard requires conforming compilers to predefine __STDC__. + Non-conforming compilers for MS-Windows may or may not predefine _WINDOWS; + if you use such a compiler, you may need to define _WINDOWS manually. */ + +#if defined(__STDC__) || defined(_WINDOWS) +# include +#else +extern double atof(); +extern long atol(); +extern char *getenv(); +extern void exit(); +typedef long time_t; +# ifndef NOMALLOC_H +# include +# else +extern char *malloc(), *calloc(), *realloc(); +# endif +# ifdef ISPRINTF +extern int sprintf(); +# else +# ifndef MSDOS +extern char *sprintf(); +# endif +# endif +#endif + +#ifndef BSD +# include +#else /* for Berkeley UNIX only */ +# include +# define strchr index #endif #endif diff -Naur wfdb-10.2.9/lib/wfdblib.h wfdb-10.3.0/lib/wfdblib.h --- wfdb-10.2.9/lib/wfdblib.h Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/lib/wfdblib.h Tue Nov 26 13:40:19 2002 @@ -1,5 +1,5 @@ /* file: wfdblib.h G. Moody 13 April 1989 - Last revised: 17 June 2002 wfdblib 10.2.6 + Last revised: 14 November 2002 wfdblib 10.3.0 External definitions for WFDB library private functions _______________________________________________________________________________ @@ -246,43 +246,6 @@ #define wfdb_getc(wp) getc(wp->fp) #define wfdb_putc(c, wp) putc(c, wp->fp) -#endif - -/* The following block is needed only to declare the values returned by - getenv() (char * unless otherwise defined in stdlib.h), malloc() (either - char * or void *) and sprintf() (either int or char *). The object code - should be correct even if these declarations are not. */ -#if defined(__STDC__) || defined(_WINDOWS) -# include -#else -extern char *getenv(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -# ifdef ISPRINTF -extern int sprintf(); -# else -# ifndef MSDOS -extern char *sprintf(); -# endif -# endif -#endif - -/* Declare the values returned by atof() and atol() (not needed for ANSI C or - Microsoft Windows C compilers, which have these declarations in stdlib.h, - included above). */ -#if !defined(__STDC__) && !defined(_WINDOWS) -extern double atof(); -extern long atol(); -#endif - -#ifndef BSD -# include -#else /* for Berkeley UNIX only */ -# include -# define strchr index #endif #ifdef _WINDOWS diff -Naur wfdb-10.2.9/lib/wfdblib.h0 wfdb-10.3.0/lib/wfdblib.h0 --- wfdb-10.2.9/lib/wfdblib.h0 Mon Jun 17 09:50:22 2002 +++ wfdb-10.3.0/lib/wfdblib.h0 Thu Nov 14 17:07:27 2002 @@ -1,5 +1,5 @@ /* file: wfdblib.h G. Moody 13 April 1989 - Last revised: 17 June 2002 wfdblib 10.2.6 + Last revised: 14 November 2002 wfdblib 10.3.0 External definitions for WFDB library private functions _______________________________________________________________________________ @@ -246,43 +246,6 @@ #define wfdb_getc(wp) getc(wp->fp) #define wfdb_putc(c, wp) putc(c, wp->fp) -#endif - -/* The following block is needed only to declare the values returned by - getenv() (char * unless otherwise defined in stdlib.h), malloc() (either - char * or void *) and sprintf() (either int or char *). The object code - should be correct even if these declarations are not. */ -#if defined(__STDC__) || defined(_WINDOWS) -# include -#else -extern char *getenv(); -# ifndef NOMALLOC_H -# include -# else -extern char *malloc(); -# endif -# ifdef ISPRINTF -extern int sprintf(); -# else -# ifndef MSDOS -extern char *sprintf(); -# endif -# endif -#endif - -/* Declare the values returned by atof() and atol() (not needed for ANSI C or - Microsoft Windows C compilers, which have these declarations in stdlib.h, - included above). */ -#if !defined(__STDC__) && !defined(_WINDOWS) -extern double atof(); -extern long atol(); -#endif - -#ifndef BSD -# include -#else /* for Berkeley UNIX only */ -# include -# define strchr index #endif #ifdef _WINDOWS diff -Naur wfdb-10.2.9/psd/Makefile wfdb-10.3.0/psd/Makefile --- wfdb-10.2.9/psd/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/psd/Makefile Tue Nov 26 13:40:19 2002 @@ -32,12 +32,12 @@ # directory). # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -54,13 +54,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -169,6 +169,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/psd/coherence.c wfdb-10.3.0/psd/coherence.c --- wfdb-10.2.9/psd/coherence.c Sun Jan 30 04:13:20 2000 +++ wfdb-10.3.0/psd/coherence.c Sun Nov 17 15:13:39 2002 @@ -1,9 +1,9 @@ /* file: coherence.c G. Moody 22 December 1993 - Last revised: 5 May 1999 + Last revised: 17 November 2002 ------------------------------------------------------------------------------- coherence: Coherence and cross-spectral power estimation -Copyright (C) 1999 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -72,8 +72,16 @@ */ #include -#include #include +#if defined(__STDC__) || defined(_WINDOWS) +# include +#else +# ifndef NOMALLOC_H +# include +# else +extern char *calloc(); +# endif +#endif /* Function types. */ int load(); diff -Naur wfdb-10.2.9/wave/Makefile wfdb-10.3.0/wave/Makefile --- wfdb-10.2.9/wave/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/wave/Makefile Tue Nov 26 13:40:19 2002 @@ -45,12 +45,12 @@ # just type `make' (from within this directory). # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -67,13 +67,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -183,6 +183,40 @@ # uncomment the next line. # STRIP = : +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... + # `make' (with no target specified) will be equivalent to `make all'. make-all: all @@ -194,7 +228,7 @@ echo "Nothing to be done for lib-post-uninstall" # _____________________________________________________________________________ # file: Makefile.tpl G. Moody 31 May 2000 -# Last revised: 18 July 2002 +# Last revised: 21 November 2002 # Change the settings below as appropriate for your setup. # Choose directories in which to install WAVE and its ancillary files by @@ -223,37 +257,6 @@ # RESDIR specifies the directory in which X11 client resource files are kept. RESDIR = $(WFDBROOT)/lib/X11/app-defaults - -# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. -# This is usually /usr/openwin. -OPENWINHOME = /usr/openwin - -# OWINCDIR is the directory in which the `xview' directory containing XView -# *.h files is found. -OWINCDIR = $(OPENWINHOME)/include - -# OWLIBDIR is the directory in which the XView library is found. -OWLIBDIR = $(OPENWINHOME)/lib - -# WCFLAGS is the set of C compiler options. -WCFLAGS = $(CFLAGS) -I$(OWINCDIR) - -# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help -# functions in "help.c" (recommended under Linux). -HELPOBJ = help.o -# Otherwise, use the version in libxview by uncommenting the next line: -# HELPOBJ = - -# WLDFLAGS is the set of loader options appended to the C compiler command line -# to specify loading the WFDB, XView, and Xlib libraries. -WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 -# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: -# WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib \ -# /usr/openwin/lib/libxview.a /usr/openwin/lib/libolgx.a -lX11 -# This setting avoids incompatibilities with the shared (dynamic) libraries. -# If you use another version of Linux, or another OS, and have difficulty -# related to WAVE's Analysis commands window, try this workaround, and let -# me know if it works (or if it doesn't work). # It should not be necessary to modify anything below this line. # ----------------------------------------------------------------------------- diff -Naur wfdb-10.2.9/wave/Makefile.tpl wfdb-10.3.0/wave/Makefile.tpl --- wfdb-10.2.9/wave/Makefile.tpl Thu Jul 18 20:41:26 2002 +++ wfdb-10.3.0/wave/Makefile.tpl Thu Nov 21 20:21:51 2002 @@ -1,5 +1,5 @@ # file: Makefile.tpl G. Moody 31 May 2000 -# Last revised: 18 July 2002 +# Last revised: 21 November 2002 # Change the settings below as appropriate for your setup. # Choose directories in which to install WAVE and its ancillary files by @@ -28,37 +28,6 @@ # RESDIR specifies the directory in which X11 client resource files are kept. RESDIR = $(WFDBROOT)/lib/X11/app-defaults - -# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. -# This is usually /usr/openwin. -OPENWINHOME = /usr/openwin - -# OWINCDIR is the directory in which the `xview' directory containing XView -# *.h files is found. -OWINCDIR = $(OPENWINHOME)/include - -# OWLIBDIR is the directory in which the XView library is found. -OWLIBDIR = $(OPENWINHOME)/lib - -# WCFLAGS is the set of C compiler options. -WCFLAGS = $(CFLAGS) -I$(OWINCDIR) - -# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help -# functions in "help.c" (recommended under Linux). -HELPOBJ = help.o -# Otherwise, use the version in libxview by uncommenting the next line: -# HELPOBJ = - -# WLDFLAGS is the set of loader options appended to the C compiler command line -# to specify loading the WFDB, XView, and Xlib libraries. -WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 -# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: -# WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib \ -# /usr/openwin/lib/libxview.a /usr/openwin/lib/libolgx.a -lX11 -# This setting avoids incompatibilities with the shared (dynamic) libraries. -# If you use another version of Linux, or another OS, and have difficulty -# related to WAVE's Analysis commands window, try this workaround, and let -# me know if it works (or if it doesn't work). # It should not be necessary to modify anything below this line. # ----------------------------------------------------------------------------- diff -Naur wfdb-10.2.9/wave/wave.c wfdb-10.3.0/wave/wave.c --- wfdb-10.2.9/wave/wave.c Sun Oct 14 14:23:27 2001 +++ wfdb-10.3.0/wave/wave.c Thu Nov 14 19:12:53 2002 @@ -1,10 +1,10 @@ /* file: wave.c G. Moody 27 April 1990 - Last revised: 14 October 2001 + Last revised: 14 November 2002 main() function for WAVE ------------------------------------------------------------------------------- WAVE: Waveform analyzer, viewer, and editor -Copyright (C) 2001 George B. Moody +Copyright (C) 2002 George B. Moody This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -28,8 +28,6 @@ #include "wave.h" #include "xvwave.h" -#include /* for realloc declaration */ -#include /* for strchr declaration */ #include /* for getpid declaration */ /* Spot help files for WAVE are located in HELPDIR/wave. Their names are diff -Naur wfdb-10.2.9/wave/xview-patches wfdb-10.3.0/wave/xview-patches --- wfdb-10.2.9/wave/xview-patches Fri Oct 26 12:56:19 2001 +++ wfdb-10.3.0/wave/xview-patches Wed Oct 30 11:27:43 2002 @@ -35,42 +35,33 @@ #define MP_I386 8 /* Pixrect is for 386 architecture */ #define MP_STATIC 16 /* Pixrect is a static pixrect */ -#endif i386 -+#endif ++#endif /* i386 */ #define MP_FONT 32 /* Pixrect is a part of a Pixfont */ /* (hint to pr_batchrop) */ -@@ -111,7 +111,7 @@ - # define IDENT(x) x - # define CAT(a,b) IDENT(a)b - # endif /* __STDC__ */ --#endif /* CAT */ -+#endif - - #define mpr_static(name, w, h, d, image) \ - struct mpr_data CAT(name,_data) = \ @@ -144,18 +144,18 @@ int mem_put(); int mem_vector(); Pixrect *mem_region(); -#endif KERNEL -+#endif ++#endif /* KERNEL */ int mem_putcolormap(); int mem_putattributes(); #ifndef KERNEL int mem_getcolormap(); int mem_getattributes(); -#endif KERNEL -+#endif ++#endif /* KERNEL */ #else /* NEWPIXMEM */ #define MP_NOTMPR(pr) (0) extern struct pixrectops mem_ops; int mem_destroy(); -#endif NEWPIXMEM -+#endif ++#endif /* NEWPIXMEM */ -#endif !memvar_DEFINED -+#endif ++#endif /* !memvar_DEFINED */ diff -Naur pixrect-/pixfont.h pixrect/pixfont.h --- pixrect-/pixfont.h Mon Jun 5 04:39:17 2000 +++ pixrect/pixfont.h Fri Oct 12 14:05:49 2001 @@ -79,7 +70,7 @@ #define prs_ttext(prpos, op, pf, str) \ pr_ttext((prpos).pr, (prpos).pos.x, (prpos).pos.y, pf, str) -#endif lint -+#endif ++#endif /* lint */ Pixfont *pf_open(); Pixfont *pf_open_private(); @@ -88,7 +79,7 @@ #define PIXFONT Pixfont -#endif pixfont_DEFINED -+#endif ++#endif /* pixfont_DEFINED */ diff -Naur pixrect-/pixrect.h pixrect/pixrect.h --- pixrect-/pixrect.h Mon Jun 5 04:39:17 2000 +++ pixrect/pixrect.h Fri Oct 12 14:03:31 2001 @@ -97,7 +88,7 @@ */ extern Pixrect *pr_open(); -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ /* * Pixrect ops vector, used by pr_ macros below to call the appropriate @@ -106,21 +97,21 @@ int (*pro_vector)(); Pixrect * (*pro_region)(); -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ int (*pro_putcolormap)(); #ifndef KERNEL int (*pro_getcolormap)(); -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ int (*pro_putattributes)(); #ifndef KERNEL int (*pro_getattributes)(); -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ #ifdef KERNEL int (*pro_nop)(); /* place holder */ -#endif KERNEL -+#endif ++#endif /* KERNEL */ }; #if !defined(lint) || defined(KERNEL) @@ -129,10 +120,10 @@ #define pr_getattributes(pr, planes) \ (*(pr)->pr_ops->pro_getattributes)((pr), (planes)) -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ -#else !lint || KERNEL -+#else ++#else /* !lint || KERNEL */ extern pr_rop(); extern pr_stencil(); @@ -141,7 +132,7 @@ extern pr_getattributes(); -#endif lint -+#endif ++#endif /* lint */ /* * Several of the above operations return a common, distinguished value when @@ -150,7 +141,7 @@ pro_line((pr), (x0), (y0), (x1), (y1), (brush), (tex), (op), 0) -#else !lint || KERNEL -+#else ++#else /* !lint || KERNEL */ extern prs_rop(); extern prs_stencil(); @@ -159,7 +150,7 @@ extern pr_line(); -#endif !lint || KERNEL -+#endif ++#endif /* !lint || KERNEL */ @@ -168,11 +159,10 @@ (*(pr)->pr_ops->pro_getcolormap)((pr), PR_FORCE_UPDATE | (ind), \ (cnt), (red), (grn), (blu)) -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ --#endif /* !_pixrect_pixrect_h */ -+#endif + #endif /* !_pixrect_pixrect_h */ diff -Naur pixrect-/pr_line.h pixrect/pr_line.h --- pixrect-/pr_line.h Mon Jun 5 04:39:17 2000 +++ pixrect/pr_line.h Fri Oct 12 14:06:54 2001 @@ -181,7 +171,7 @@ } Pr_brush; -#endif pr_line_h_DEFINED -+#endif ++#endif /* pr_line_h_DEFINED */ @@ -193,7 +183,7 @@ extern void pr_set_planes(); -#endif pr_planegroups_DEFINED -+#endif ++#endif /* pr_planegroups_DEFINED */ diff -Naur pixrect-/pr_util.h pixrect/pr_util.h --- pixrect-/pr_util.h Mon Jun 5 04:39:17 2000 +++ pixrect/pr_util.h Fri Oct 12 14:04:36 2001 @@ -202,12 +192,12 @@ }; \ asm("dbra d6,label"); -#else mc68000 -+#else ++#else /* mc68000 */ #define rop_slowloop(n, op) \ { register int _loop = (n); \ while (--_loop >= 0) { op; } } -#endif mc68000 -+#endif ++#endif /* mc68000 */ #ifdef mc68010 #define cases8(n, op) \ @@ -216,10 +206,10 @@ case 0: break; \ } } -#else mc68010 -+#else ++#else /* mc68010 */ #define rop_fastloop rop_slowloop -#endif mc68010 -+#endif ++#endif /* mc68010 */ /* * Alloctype(datatype) allocates a datatype structure using calloc @@ -228,10 +218,10 @@ #ifndef KERNEL Pixrect *pr_makefromfd(); -#endif !KERNEL -+#endif ++#endif /* !KERNEL */ -#endif pr_util_DEFINED -+#endif ++#endif /* pr_util_DEFINED */ diff -Naur pixrect-/traprop.h pixrect/traprop.h --- pixrect-/traprop.h Mon Jun 5 04:39:17 2000 +++ pixrect/traprop.h Fri Oct 12 14:06:02 2001 @@ -240,4 +230,4 @@ }; -#endif traprop_DEFINED -+#endif ++#endif /* traprop_DEFINED */ diff -Naur wfdb-10.2.9/wave/xvwave.c wfdb-10.3.0/wave/xvwave.c --- wfdb-10.2.9/wave/xvwave.c Fri Oct 11 15:21:43 2002 +++ wfdb-10.3.0/wave/xvwave.c Thu Nov 14 19:13:59 2002 @@ -1,5 +1,5 @@ /* file: xvwave.c G. Moody 27 April 1990 - Last revised: 11 October 2002 + Last revised: 14 November 2002 XView support functions for WAVE ------------------------------------------------------------------------------- @@ -32,16 +32,15 @@ #include "bitmaps.h" #include /* for struct passwd definition */ #include /* for SIGUSR1 definition */ -#include /* for strchr definition */ #include /* for getpid definition */ #include #include /* for Xv_singlecolor definition */ #include #include #include -#include /* new */ +#include #include -#include /* new */ +#include #include #include diff -Naur wfdb-10.2.9/waverc/Makefile wfdb-10.3.0/waverc/Makefile --- wfdb-10.2.9/waverc/Makefile Sun Oct 27 00:05:34 2002 +++ wfdb-10.3.0/waverc/Makefile Tue Nov 26 13:40:19 2002 @@ -25,12 +25,12 @@ # please visit PhysioNet (http://www.physionet.org/). # _____________________________________________________________________________ # file: version.def G. Moody 24 May 2000 -# Last revised: 26 October 2002 +# Last revised: 25 November 2002 # Each release of the WFDB Software Package is identified by a three-part # version number, defined here: MAJOR = 10 -MINOR = 2 -RELEASE = 9 +MINOR = 3 +RELEASE = 0 VERSION = $(MAJOR).$(MINOR).$(RELEASE) # RPMRELEASE can be incremented if changes are made between official @@ -47,13 +47,13 @@ # Definitions generated by 'configure' -PACKAGE = wfdb-10.2.9 -LONGDATE = 27 October 2002 -SHORTDATE = OCTOBER 2002 +PACKAGE = wfdb-10.3.0 +LONGDATE = 26 November 2002 +SHORTDATE = NOVEMBER 2002 # _____________________________________________________________________________ # file: linux.def G. Moody 31 May 2000 -# Last revised: 17 December 2001 +# Last revised: 21 November 2002 # 'make' definitions for compiling the WFDB Software Package under Linux # Choose a value for WFDBROOT to determine where the WFDB Software Package will @@ -162,6 +162,40 @@ # To retain the symbol tables for debugging, comment out the previous line, and # uncomment the next line. # STRIP = : + +# ........................................................................... +# This section of definitions is used only when compiling WAVE, which is +# possible only if the XView and Xlib libraries and include files have been +# installed. + +# OPENWINHOME specifies the root directory of the OpenWindows hierarchy. +# This is usually /usr/openwin. +OPENWINHOME = /usr/openwin + +# OWINCDIR is the directory in which the `xview' directory containing XView +# *.h files is found. +OWINCDIR = $(OPENWINHOME)/include + +# OWLIBDIR is the directory in which the XView library is found. +OWLIBDIR = $(OPENWINHOME)/lib + +# WCFLAGS is the set of C compiler options to use when compiling WAVE. +WCFLAGS = $(CFLAGS) -I$(OWINCDIR) + +# HELPOBJ can be set to "help.o" if you wish to recompile the XView spot help +# functions in "wave/help.c" (recommended under Linux). +HELPOBJ = help.o +# Otherwise, use the version in libxview by uncommenting the next line: +# HELPOBJ = + +# WLDFLAGS is the set of loader options appended to the C compiler command line +# to specify loading the WFDB, XView, and Xlib libraries. +WLDFLAGS = $(LDFLAGS) -L$(OWLIBDIR) -L/usr/X11R6/lib -lxview -lolgx -lX11 +# Users of Red Hat Linux 5.0 or 5.1 (not later versions), use this instead: +# WLDFLAGS = $(LDFLAGS) -L/usr/X11R6/lib $(OWLIBDIR)/libxview.a \ +# $(OWLIBDIR)/libolgx.a -lX11 +# This setting avoids incompatibilities with the shared (dynamic) libraries. +# ........................................................................... # `make' (with no target specified) will be equivalent to `make all'. make-all: all diff -Naur wfdb-10.2.9/wfdb.spec wfdb-10.3.0/wfdb.spec --- wfdb-10.2.9/wfdb.spec Thu Aug 8 12:50:29 2002 +++ wfdb-10.3.0/wfdb.spec Tue Nov 26 03:08:12 2002 @@ -54,7 +54,7 @@ /usr/bin/cshsetwfdb /usr/bin/ecgeval /usr/bin/edf2mit -/usr/bin/epic +/usr/bin/epicmp /usr/bin/fft /usr/bin/fir /usr/bin/hrfft @@ -69,6 +69,7 @@ /usr/bin/md2a /usr/bin/memse /usr/bin/mfilt +/usr/bin/mit2edf /usr/bin/mrgann /usr/bin/mxm /usr/bin/nst @@ -87,6 +88,7 @@ /usr/bin/sampfreq /usr/bin/setwfdb /usr/bin/sigamp +/usr/bin/sigavg /usr/bin/skewedit /usr/bin/snip /usr/bin/sortann @@ -104,6 +106,7 @@ /usr/bin/wfdb-config /usr/bin/wfdbdesc /usr/bin/wfdbwhich +/usr/bin/wqrs /usr/bin/wrann /usr/bin/wrsamp /usr/bin/xform