[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

D. Extensions

This section may be helpful if you wish to extend the capabilities of the WFDB library, or if you wish to port it to another environment. In order to make use of the information in this section, you should have the WFDB library sources (see section Sources). The sources are distributed among four ‘include’ (‘.h’) files and five ‘.c’ files:

 
wfdb.h         Constant and structure definitions, and function prototypes
ecgcodes.h     Annotation codes
ecgmap.h       Annotation code mapping macros
wfdblib.h      External definitions for private WFDB library functions

wfdbinit.c     Functions wfdbinit, wfdbquit, and wfdbflush
signal.c       Functions for signals
calib.c        Functions for signal calibration
annot.c        Functions for annotations
wfdbio.c       Low-level I/O and operating system-dependent functions

The first three of these files are the standard ‘include’ files that are usually obtained by ‘#include <wfdb/file.h>’ statements. When modifying the WFDB library, however, make any necessary changes in the copies of these files that are kept in the library source directory. Install the modified versions of the ‘.h’ files in the system’s ‘include’ directory after installing the modified WFDB library.

The cleanest mechanism for adding additional fields to ‘hea’ files is to include them in ‘info’ strings (see section getinfo), rather than by modifying the code that reads and writes ‘hea’ files (in ‘signal.c’).

A common problem is the need to import signal files generated by other software. Often this problem can be solved by writing a format conversion program that uses input functions provided with the other software to read the signal files, and putvec to write them in one of the formats supported by the WFDB library. This solution is unlikely to be satisfactory if you have many large signal files to import, however, and you may wish to arrange for getvec to read the imported files directly. This may be done by defining a new signal file format, as outlined below.

To define a new format for signal files, choose a numeric code to represent your format. (Values between 900 and 999 are reserved for user-defined signal file format codes.) In ‘wfdb.h’, add your format code to FMT_LIST and increment NFMTS. In ‘signal.c’, define functions (macros if possible for efficiency) for reading and writing single samples; these should be named rnnn and wnnn, where nnn is your format code. Follow the examples in ‘signal.c’; it will almost certainly be easier to make use of the existing macros r8 and w8 than to begin from scratch. Add additional case statements in getvec and putvec, again following the existing models. You will also need to add a case in isgsettime, including a formula to determine the number of bytes needed per sample, given the number of signals multiplexed. (All currently-defined formats use fixed-length encoding. If you wish to implement variable-length encoding, it may be easiest to implement an indexed-search method for isgsettime in such cases.) If the ADC resolution exceeds the number of bits in a C int on your system, change the typedef for ‘WFDB_Sample’ in ‘<wfdb/wfdb.h>’ as necessary; be aware that this change is likely to require additional changes to application programs (use ‘lint’ or an ANSI C compiler to check your code).

Although the WFDB library generally assumes that signal files are “pure”, it is possible to read imported signal files that contain prologs (data that precede the first sample). To do so, you must construct a header file in which the format fields encode the length of the prolog in bytes (you can do this manually, or use wfdbsetstart, see section wfdbsetstart, for this purpose). For example, a signal file with a 512-byte prolog followed by format 16 samples would be specified using ‘16+512’ in the format field or fields (if the file contains more than one signal, the format fields for all signals in the file must be identical). Note that this facility is provided only for signal file import; the WFDB library is not equipped to create signal files with embedded prologs.

In a similar fashion, though with substantially more effort in most cases, you may define a new format for annotation files. Add additional stat values for reading and writing to the list in ‘wfdb.h’. In ‘annot.c’, add additional case statements and code to annopen, getann, putann, and wfdb_anclose. If you are designing a new format, you may wish to specify a ‘magic number’ with which your files will begin, to allow annopen to recognize the format automatically; a good choice of such a number is one in which the first byte is non-zero (to distinguish it from AHA format files) and the high six bits of the second byte are zero (to distinguish it from WFDB format files).

Some users may wish to define additional annotation codes. An easy and portable way to accomplish this is to use setannstr and setanndesc within programs that create your annotation files, before opening them using annopen (or wfdbinit). Annotation files created in this way contain modification labels at the beginning that document the non-standard code definitions, and that permit them to be read properly by standard WFDB applications. Another solution is to modify the WFDB library. This method has the disadvantage that all of your applications that read annotation files must be recompiled, and they may no longer read standard annotation files properly. If despite this disadvantage you prefer to modify the WFDB library, begin by defining symbolic names and numeric values for your new codes in ‘ecgcodes.h’. (Values between 42 and 49 are reserved for user-defined annotation codes. Unused values less than 42 may be assigned in future versions of the WFDB library, and values greater than 49 are reserved to indicate the presence of optional fields such as subtyp.) Next, decide how the new codes are to be mapped by isqrs, map1, map2, mamap, and annpos, and set the appropriate entries in each of the code map arrays in ‘ecgmap.h’. Finally, add mnemonic and descriptive strings for the new codes in the cstring, astring, and tstring arrays in ‘annot.c’.

The modular design of the library makes it fairly easy to remove unneeded functionality in order to conserve memory for special applications. The ‘calib.c’ package is not referenced by any other WFDB library modules. For signal processing applications that do not involve annotations, the entire ‘annot.c’ package may be removed (with trivial modifications to the functions in ‘wfdbinit.c’). If you wish to add functions to the library, you will find that it will be easier to maintain your modified version and to merge updates if you preserve the existing arrangement of functions, which requires no global variables. Rather than defining global variables, consider implementing query functions (global-scope functions that read or write local variables). If you wish to define new types of binary files, consider using the low-level I/O routines in ‘wfdbio.c’ for reading and writing them in a machine-independent format.

Porting the WFDB library to another environment is a straightforward operation if an ANSI C compiler is available in the target environment. Since all direct access to database files is performed using the (private) function wfdb_open, it is possible to include file name translation in that function if needed, to accommodate file naming schemes that may be imposed by the operating system or other requirements. If the notion of environment variables is foreign to the target environment, getwfdb can be modified to read the WFDB path from a file. You may wish to modify the private function wfdb_error (which is responsible for all error reporting from WFDB library functions) if the ‘standard error output’ is unavailable or inadequate for use in the target environment. All of these functions are contained within ‘wfdbio.c’; it is unlikely that any other code will require changes for a port.

If you encounter errors while compiling ‘signal.c’, you may wish to try using the functions provided in that file as alternatives to the standard macros r16 and w16; the fully-expanded versions of these macros are quite complex and are known to cause difficulty for at least one (now obsolete) C compiler. (Define the symbol ‘BROKEN_CC’ while compiling ‘signal.c’ in order to obtain the function versions of r16 and w16.) While compiling ‘signal.c’, it may be necessary to disable code optimization for some C compilers; no current compilers are known to have such limitations, however.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

George B. Moody (george@mit.edu)