EDFlib for Java

EDFlib for Java is a programming library to read and write EDF+ and BDF+ files written in pure Java. (It also reads old-type EDF/BDF files.)
EDF means European Data Format. BDF is the 24-bits version of EDF.
For a C/C++ version, look here. For a Python version, look here.


Versions

Feedback to: teuniz@protonmail.com


Other EDF software


Notes:

In EDF, the sensitivity (e.g. uV/bit) and offset are stored using four parameters:
digital maximum and minimum, and physical maximum and minimum.
Here, digital means the raw data coming from a sensor or ADC. Physical means the units like uV.
The sensitivity in units/bit is calculated as follows:

units per bit = (physical max - physical min) / (digital max - digital min)

The digital offset is calculated as follows:

offset = (physical max / units per bit) - digital max

For a better explanation about the relation between digital data and physical data, read the document Coding Schemes Used with Data Converters.

note: An EDF file usually contains multiple so-called datarecords. One datarecord usually has a duration of one second (this is the default but it is not mandatory!).
In that case a file with a duration of five minutes contains 300 datarecords. The duration of a datarecord can be freely choosen but, if possible, use values from
0.1 to 1 second for easier handling. Just make sure that the total size of one datarecord, expressed in bytes, does not exceed 10MByte (15MBytes for BDF(+)).

The recommendation of a maximum datarecordsize of 61440 bytes in the EDF and EDF+ specification was usefull in the time people were still using DOS as their main operating system.
Using DOS and fast (near) pointers (16-bit pointers), the maximum allocatable block of memory was 64KByte.
This is not a concern anymore so the maximum datarecord size now is limited to 10MByte for EDF(+) and 15MByte for BDF(+).
This helps to accommodate for higher samplingrates used by modern, fast Analog to Digital Converters.

EDF header character encoding: The EDF specification says that only ASCII characters are allowed.
EDFlib will automatically convert characters with accents, umlauts, tilde, etc. to their "normal" equivalent without the accent/umlaut/tilde/etc.

The description/name of an EDF+ annotation on the other hand, is encoded in UTF-8.


Notes:

Annotationsignals

EDFplus and BDFplus store the annotations in one or more signals (in order to be backwards compatibel with EDF and BDF).
The counting of the signals in the file starts at 0. Signals used for annotations are skipped.
This means that the annotationsignal(s) in the file are hided.
Use annotationslist.size(), annotationslist.get().onset, annotationslist.get().duration and annotationslist.get().description
to get the information in the annotations.

So, when a file contains 5 signals and the third signal is used to store the annotations, the library will
report that there are only 4 signals in the file.
The library will "map" the signalnumbers as follows: 0->0, 1->1, 2->3, 3->4.
This way you don't need to worry about which signals are annotationsignals. The library will do it for you.

Writing annotations

In order to keep the resulting filesize acceptable, EDFlib limits the maximum annotation description length at 40 bytes.

Can I read or write discontinuous files?

No. Discontinuous files can be converted to continuous files using EDFbrowser.

Maximum size of patient- and recording info

Originally, EDF has two headerfields reserved for the patientname and the recording info.
Both fields can each contain 80 bytes. EDF+ and BDF+ have divided these fields in subfields in order
to identify administrationcode, birthdate, etc. Because of backwards compatibility with EDF and BDF,
these subfields ared divided in two groups. Both groups have to share 80 bytes minus some other bytes
used for other purpose like startdate. The following table shows how many bytes are available for the
two groups. Birthdate takes 10 bytes.

72 bytes are available for: patientname patientcode birthdate patient_additional
42 bytes are available for: admincode technician equipment recording_additional


EDFlib will perform a maximum size check for these two groups and prevent against writing too many bytes
into the header.


How do I jump to n seconds from the start of the file when I read a file?


If n is an integer (has no fraction):


long offset;

if((edf_in.getLongDataRecordDuration() % EDFreader.EDFLIB_TIME_DIMENSION) == 0)
{
  offset = (n / (edf_in.getLongDataRecordDuration() / EDFreader.EDFLIB_TIME_DIMENSION)) * edf_in.getSmplsPerRecord(signum);
}
else
{
  offset = (long)(((double)n / ((double)edf_in.getLongDataRecordDuration() / (double)EDFreader.EDFLIB_TIME_DIMENSION)) * (double)edf_in.getSmplsPerRecord(signum));
}

edf_in.seek(signum, offset, EDFreader.EDFSEEK_SET);

If n has a fraction:


long offset;

offset = (long)(((double)n / ((double)edf_in.getLongDataRecordDuration() / (double)EDFreader.EDFLIB_TIME_DIMENSION)) * (double)edf_in.getSmplsPerRecord(signum));

edf_in.seek(signum, offset, EDFreader.EDFSEEK_SET);


More info