EDF / EDF+ / BDF / BDF+
EDF and BDF store polygraphic time-series data in a fixed-width header followed by fixed-size data records. EDF stores signed 16-bit samples; BDF uses the same header geometry and stores signed 24-bit samples. EDF+ and BDF+ add structured identification fields, standardized labels, annotations, and continuous/discontinuous timeline markers.
The word signal in the format specifications means one channel in a
data record.
Source map
Section titled “Source map”| Source | Authority and scope |
|---|---|
| EDF specification | Base EDF header and data-record layout |
| EDF+ specification | Normative EDF+ differences, structured fields, TAL grammar, and time keeping |
| EDF+ standard texts | Obligatory EDF+ signal labels, dimensions, polarity rules, and annotation texts |
| EDF programming guidelines | Explicitly non-normative implementation guidance and clarifications |
| BioSemi BDF description | Base BDF identification, 24-bit sample layout, and BioSemi header profile |
| BDF+ format description | BDF+ differences from EDF+; the author states that this description is not affiliated with BioSemi |
Rules attributed to the programming guidelines are recommendations or clarifications rather than additions to the normative EDF/EDF+ specifications.
Format family
Section titled “Format family”| Dialect | Extension | Version bytes | Main reserved prefix |
Ordinary sample |
|---|---|---|---|---|
| EDF | .edf / .EDF |
30 20 20 20 20 20 20 20 |
Free local text or spaces | signed 16-bit little-endian |
| EDF+C | .edf / .EDF |
30 20 20 20 20 20 20 20 |
EDF+C |
signed 16-bit little-endian |
| EDF+D | .edf / .EDF |
30 20 20 20 20 20 20 20 |
EDF+D |
signed 16-bit little-endian |
| BDF | .bdf / .BDF |
FF 42 49 4F 53 45 4D 49 |
24BIT in the BioSemi profile |
signed 24-bit little-endian |
| BDF+C | .bdf / .BDF |
FF 42 49 4F 53 45 4D 49 |
BDF+C |
signed 24-bit little-endian |
| BDF+D | .bdf / .BDF |
FF 42 49 4F 53 45 4D 49 |
BDF+D |
signed 24-bit little-endian |
C means that every data record begins exactly where the preceding
record ends. D permits gaps between data records. A base EDF reader
can frame EDF+D bytes but presents the records as continuous and
therefore loses the gaps. BDF+ applies the same compatibility model to
BDF readers.
The BioSemi acquisition profile for base BDF places a Trigger/Status channel last.
File structure
Section titled “File structure”A file contains:
- one main 256-byte header;
- ten banded per-signal header arrays totaling
256 * signal_countbytes; record_countfixed-size data records.
The total header size is
header_bytes = 256 * (signal_count + 1)Within every data record, channels are stored channel-major: all samples of channel 0, followed by all samples of channel 1, and so on. Channels are not interleaved sample-by-sample.
Header encoding
Section titled “Header encoding”Header fields have fixed byte widths and do not contain terminators.
Content is left-justified and unused bytes are filled with ASCII space
0x20. A value must not spill into the following field. The format
does not define a safe semantic truncation rule for over-width
structured or numeric values.
EDF+ requires printable US-ASCII 0x20..0x7E throughout the header.
BDF+ inherits this rule except for the first version byte, which is
0xFF. UTF-8 is used only for annotation text in data records.
Header numbers:
- use no digit grouping;
- use
.rather than,as the decimal separator; - use a leading
-for negative values; - may use scientific
Enotation according to the non-normative programming guidelines; - remain plain integer strings in fields whose value is defined as an integer.
TAL Onset and Duration fields use a stricter grammar and never permit
E notation.
Main header
Section titled “Main header”| Offset | Size | Field | Content |
|---|---|---|---|
| 0 | 8 | version |
EDF bytes 0 or BDF bytes 0xFFBIOSEMI |
| 8 | 80 | patient_id |
Local patient identification |
| 88 | 80 | recording_id |
Local recording identification |
| 168 | 8 | start_date |
dd.mm.yy |
| 176 | 8 | start_time |
hh.mm.ss |
| 184 | 8 | header_bytes |
Total header length |
| 192 | 44 | reserved |
Base-format local value or plus dialect tag |
| 236 | 8 | record_count |
Number of data records |
| 244 | 8 | record_duration |
Duration of one data record in seconds |
| 252 | 4 | signal_count |
Number of channels, including annotations signals |
version
Section titled “version”EDF, EDF+C, and EDF+D use the eight ASCII bytes "0 ".
BDF, BDF+C, and BDF+D use one non-ASCII byte 0xFF followed by the
seven ASCII bytes BIOSEMI:
FF 42 49 4F 53 45 4D 49patient_id
Section titled “patient_id”Base EDF and base BDF treat the 80-byte field as local text.
EDF+ requires four leading space-separated subfields:
- patient administration code;
- sex,
ForM; - birth date in
dd-MMM-yyyyform; - patient name.
Additional local subfields may follow. BDF+ describes the same layout
as five conceptual parts by naming the trailing content
additional info.
Month names are uppercase English abbreviations:
JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DECSubfields contain no spaces. Internal spaces are replaced with another
character such as _. Unknown, inapplicable, or anonymized subfields
are represented by X.
Examples:
MCH-0234567 F 02-MAY-1951 Haagse_HarryX X X Xrecording_id
Section titled “recording_id”Base EDF and base BDF treat the 80-byte field as local text.
EDF+ and BDF+ begin with:
Startdate <dd-MMM-yyyy> <administration-code> <technician-code> <equipment-code>Additional recording information may follow. Unknown fields use X:
Startdate X X X XSpaces inside individual codes are replaced with another character.
start_date
Section titled “start_date”start_date uses dd.mm.yy. EDF+ defines the two-digit year window:
85..99means1985..1999;00..84means2000..2084;- after 2084, the last two bytes are the literal
yyand the four-digit date comes fromrecording_id.
start_time
Section titled “start_time”start_time uses hh.mm.ss and contains local wall-clock time at the
patient’s location. The format stores no timezone identifier or UTC
offset.
For plus dialects, start_date and start_time identify the absolute
whole second containing the beginning of the first data record. The
first time-keeping TAL carries any fractional offset within that
second.
header_bytes
Section titled “header_bytes”This ASCII integer must equal:
256 * (signal_count + 1)reserved
Section titled “reserved”The first five bytes select a plus dialect:
| Prefix | Meaning |
|---|---|
EDF+C |
Continuous EDF+ |
EDF+D |
Discontinuous EDF+ |
BDF+C |
Continuous BDF+ |
BDF+D |
Discontinuous BDF+ |
The remaining 39 bytes of a plus header are spaces. Base EDF permits
local text in this field. The BioSemi base BDF profile uses 24BIT.
record_count
Section titled “record_count”This field is an ASCII integer. Base EDF and BDF use -1 when the
count is unknown. Plus dialects permit -1 only while a recording is
being written; a closed plus file contains the actual non-negative
record count.
record_duration
Section titled “record_duration”This field is an ASCII number of seconds.
Base EDF recommends a whole number of seconds and a maximum data-record size of 61,440 bytes. A duration below one second is recommended when a one-second record would exceed that size.
EDF+:
- makes the 61,440-byte record limit mandatory;
- permits a positive duration below one second without the base EDF qualification;
- permits zero only for an annotations-only file or for the EDF+D case where every ordinary channel contributes one sample per record at arbitrary record times.
BDF+ permits any representable duration greater than zero and sets a 15 MB maximum data-record size.
signal_count
Section titled “signal_count”This ASCII integer counts every ordinary and annotations channel. Annotations channels occupy normal entries in all ten per-signal header bands and in every data record.
Per-signal header bands
Section titled “Per-signal header bands”The per-signal header is banded rather than interleaved. All labels come first, then all transducer fields, and so on.
| # | Base offset | Width per signal | Field |
|---|---|---|---|
| 1 | 256 |
16 | label[i] |
| 2 | 256 + 16 * ns |
80 | transducer[i] |
| 3 | 256 + 96 * ns |
8 | physical_dim[i] |
| 4 | 256 + 104 * ns |
8 | physical_min[i] |
| 5 | 256 + 112 * ns |
8 | physical_max[i] |
| 6 | 256 + 120 * ns |
8 | digital_min[i] |
| 7 | 256 + 128 * ns |
8 | digital_max[i] |
| 8 | 256 + 136 * ns |
80 | prefiltering[i] |
| 9 | 256 + 216 * ns |
8 | samples_per_record[i] |
| 10 | 256 + 224 * ns |
32 | signal_reserved[i] |
The byte following band 10 is 256 + 256 * ns and therefore equals
header_bytes.
The 16-byte label identifies a channel. EDF+ standard texts use:
<signal-type> <specification>Examples include ECG II, EEG Fpz-Cz, Resp nasal, and
Temp rectal.
The exact labels EDF Annotations and BDF Annotations are reserved
for their corresponding plus annotation channels. They must not be
used by ordinary channels.
transducer
Section titled “transducer”The 80-byte field describes the sensor, such as AgAgCl electrode or
thermistor. It is all spaces for an annotations channel.
physical_dim
Section titled “physical_dim”The 8-byte field contains the physical unit: an optional SI prefix
followed by a base unit. ECG channels normally use V, mV, or uV.
The prefix multiplies the base unit by a power of ten. Case is
significant, so M is mega while m is milli:
| Prefix | Power | Name |
|---|---|---|
K |
3 | kilo |
m |
-3 | milli |
u |
-6 | micro |
n |
-9 | nano |
These are the prefixes seen in ECG dimensions; the EDF+ standard texts
define the full SI set. The micro prefix is the ASCII letter u, not
the non-ASCII micro sign, because header bytes stay in printable
US-ASCII. Powers use ^. Evaluation order is prefix, then power, then
multiplication, then division, so Km^2 is (1000 m)^2, not
1000 * m^2.
An uncalibrated ordinary channel uses spaces. An annotations channel also uses spaces.
physical_min and physical_max
Section titled “physical_min and physical_max”These ASCII numbers identify the physical values corresponding to
digital_min and digital_max. They must differ. A negative-gain
channel uses physical_max < physical_min; the digital extrema remain
ordered.
Annotations channels may use any two distinct representable values.
-1 and 1 are conventional.
digital_min and digital_max
Section titled “digital_min and digital_max”These fields are ASCII integers and must satisfy:
digital_max > digital_minOrdinary EDF channels use values representable by signed 16-bit
samples, -32768..32767. Ordinary BDF channels use values
representable by signed 24-bit samples,
-8388608..8388607.
Annotations-channel extrema are fixed:
| Dialect | digital_min |
digital_max |
|---|---|---|
| EDF+ | -32768 |
32767 |
| BDF+ | -8388608 |
8388607 |
prefiltering
Section titled “prefiltering”This 80-byte field describes filters and relevant acquisition processing. EDF+ recommends forms such as:
HP:0.1Hz LP:75Hz N:50HzIt is all spaces for an annotations channel.
samples_per_record
Section titled “samples_per_record”For an ordinary channel, this positive ASCII integer is the number of stored samples in every data record. For positive record duration:
sample_rate[i] = samples_per_record[i] / record_durationDifferent channels may have different values and therefore different sample rates.
For an annotations channel, the field reserves character storage:
| Dialect | Bytes available in one data record |
|---|---|
| EDF+ | 2 * samples_per_record |
| BDF+ | 3 * samples_per_record |
The nominal 2-byte or 3-byte sample grouping has no meaning to the TAL parser; annotation characters remain in byte order.
signal_reserved
Section titled “signal_reserved”Plus dialects fill this 32-byte field with spaces. Annotation channels also require spaces.
Data records
Section titled “Data records”For record record_index:
channel[0][0 .. samples_per_record[0] - 1]channel[1][0 .. samples_per_record[1] - 1]...channel[ns - 1][0 .. samples_per_record[ns - 1] - 1]Record size is:
EDF record bytes = 2 * sum(samples_per_record[i])BDF record bytes = 3 * sum(samples_per_record[i])The body starts at header_bytes. For a known record count, its
expected size is record_count * record_bytes.
EDF samples
Section titled “EDF samples”Each ordinary sample is a signed 16-bit two’s-complement integer in little-endian byte order:
least-significant byte, most-significant byteBDF samples
Section titled “BDF samples”Each ordinary sample is a signed 24-bit two’s-complement integer in little-endian byte order:
bits 0..7, bits 8..15, bits 16..23The stored range is -8388608..8388607.
Sample timing
Section titled “Sample timing”Samples of one ordinary channel are equally spaced inside each data record. The first sample occurs at the onset given by that record’s time-keeping TAL.
In a +C file, record k + 1 begins at:
onset[k] + record_durationIn a +D file, the next onset may be later. Records remain in temporal
order in the file.
Digital-to-physical scaling
Section titled “Digital-to-physical scaling”The four extrema define an affine map:
gain = (physical_max - physical_min) / (digital_max - digital_min)
physical = physical_min + (digital - digital_min) * gainThe inverse used by an encoder is:
digital = round( (physical - physical_min) / gain + digital_min)The stored digital value must remain inside the declared digital range. Negative gain is represented by reversed physical extrema, not by reversed digital extrema.
Plus identification and annotations
Section titled “Plus identification and annotations”EDF+ and BDF+ both require at least one annotations channel even when there are no user annotations. The channel exists because the first annotations signal stores the onset of every data record.
Required header values:
| Field | EDF+ | BDF+ |
|---|---|---|
label |
EDF Annotations |
BDF Annotations |
transducer |
spaces | spaces |
physical_dim |
spaces | spaces |
physical_min/max |
distinct values | distinct values |
digital_min |
-32768 |
-8388608 |
digital_max |
32767 |
8388607 |
prefiltering |
spaces | spaces |
signal_reserved |
spaces | spaces |
The labels shown include the trailing space that fills the 16-byte field.
Multiple annotations channels are permitted by the formats. The first one is the time-keeping channel.
TAL encoding
Section titled “TAL encoding”An annotations buffer contains Time-stamped Annotation Lists:
TAL = Onset (0x15 Duration)? 0x14 (Annotation 0x14)* 0x00Onset = ("+" | "-") Digits ("." Digits)?Duration = Digits ("." Digits)?Digits = digit { digit }Annotation = UTF-8 textControl bytes:
| Byte | Meaning |
|---|---|
0x14 |
Ends the timestamp and each annotation |
0x15 |
Separates Onset from Duration |
0x00 |
Terminates the TAL and fills unused bytes |
Onset always begins with + or -. Duration has no sign. Neither
field permits exponent notation. Fractional precision is arbitrary
within the available annotation bytes.
Annotation text uses UTF-8. Bytes 0x14 and 0x00 cannot occur inside
the text. Other C0 controls are forbidden except TAB 0x09, LF 0x0A,
and CR 0x0D.
A recurring event uses the same annotation text on every occurrence so that software can group its instances; distinct events use distinct texts.
A TAL, including its terminating 0x00, fits entirely in one data
record. Unused annotation bytes are 0x00.
TAL examples
Section titled “TAL examples”An atrial-fibrillation episode of 8.2 s starting 12.5 s after file start carries an onset, a duration, and one annotation:
"+12.5" 0x15 "8.2" 0x14 "Atrial fibrillation" 0x14 0x00An instantaneous boundary marker omits the duration:
"+0" 0x14 "Recording starts" 0x14 0x00An event before the record start uses a negative onset:
"-0.5" 0x15 "3.0" 0x14 "Asystole" 0x14 0x00Annotations sharing one timestamp pack into a single TAL; here one
event is bound to two leads with @@:
"+12.5" 0x15 "8.2" 0x14 "Atrial fibrillation@@ECG II" 0x14 "Atrial fibrillation@@ECG V1" 0x14 0x00Time-keeping TAL
Section titled “Time-keeping TAL”The first TAL of the first annotations channel starts at byte zero in every data record. Its first annotation is empty:
Onset 0x14 0x14 0x00Onset is the number of seconds from the whole-second
start_date/start_time reference to the first ordinary sample in
that record.
The first record begins at +0.X, where X is its fractional offset
inside the header’s whole second. When X is zero, +0 is valid.
If a record has no ordinary channels, the same TAL contains a non-empty annotation immediately after the empty time-keeping annotation to name the event defining the record onset.
Event placement
Section titled “Event placement”EDF+ requires an annotation related to information in one particular data record to be stored in that record. A pre-interval event still follows the record’s time-keeping TAL.
BDF+ explicitly relaxes this placement rule: a record-related annotation need not be stored in the related record. All other TAL framing and time-keeping rules remain applicable.
An event spanning several data records is annotated once, in the record that contains its onset, and is not repeated in the following records.
Continuous and discontinuous timing
Section titled “Continuous and discontinuous timing”EDF+C and BDF+C require contiguous data records. Their
time-keeping TALs still exist and state every record onset.
EDF+D and BDF+D permit gaps. The gap after record k is:
onset[k + 1] - onset[k] - record_durationfor positive record duration. The onset sequence, rather than record index alone, defines absolute time in a discontinuous file.
Within a continuous segment, data records remain adjacent. A gap begins a separate segment.
Standard ECG labels
Section titled “Standard ECG labels”EDF+ standard texts are obligatory for EDF+ and inherited by BDF+ except where the BDF+ description specifies a difference.
An ECG channel label uses ECG followed by a recognized lead:
ECG I ECG II ECG IIIECG aVR ECG aVL ECG aVF ECG -aVRECG V1 ECG V2 ECG V3 ECG V4 ECG V5 ECG V6ECG V2R ECG V3R ECG V4RECG V7 ECG V8 ECG V9ECG X ECG Y ECG ZThe complete value is left-justified and space-padded to 16 bytes.
Lead semantics:
I,II,IIIare the bipolar limb leads;aVR,aVL,aVFare the augmented limb leads;-aVRis the inverted augmented-vector lead;V1..V6are the standard precordial leads;V2R,V3R,V4Rare the right-sided precordial leads;V7,V8,V9are the posterior precordial leads;X,Y,Zare the orthogonal Frank leads.
For EEG, EOG, EMG, and other electrode-pair labels, the physical value
is the potential at the first electrode minus the potential at the
second electrode. When a reference cannot be represented accurately
within the label, standard texts use Ref, Ref1, and so on.
Standard annotation texts
Section titled “Standard annotation texts”The EDF+ standard-text page defines annotation strings that plus software can recognize automatically. Cardiac entries include:
Sinus Tachycardia;WC tachycardia;NC tachycardia;Bradycardia;Asystole;Atrial fibrillation.
Recording starts and Recording ends are instantaneous boundary
annotations. Other standard-text entries in the table, including the
cardiac entries above, carry a Duration.
An annotation can target a channel by appending @@ and the exact
unpadded standard channel label:
Atrial fibrillation@@ECG IIStrict validation checklist
Section titled “Strict validation checklist”A strict validator checks the following before interpreting samples:
- the first eight bytes identify EDF or BDF;
- all header bytes except the BDF
0xFFversion byte are printable US-ASCII for a plus file; header_bytes == 256 * (signal_count + 1);- every fixed-width band is present;
signal_count,record_count, and everysamples_per_recordare valid integers;record_durationis valid for the selected dialect;- the
reservedprefix matches the version family and is exactly a supported+Cor+Dtag for plus files; - ordinary digital extrema are ordered and fit the selected 16-bit or 24-bit sample width;
- physical extrema differ;
- record size uses the selected 2-byte or 3-byte sample width and respects the dialect limit;
- an EDF+ file contains
EDF Annotationsand a BDF+ file containsBDF Annotations; - annotation-channel digital extrema and blank fields match the dialect;
- every record begins its first annotations channel with a valid time-keeping TAL;
- no TAL crosses a record boundary;
- every TAL and UTF-8 annotation obeys the control-byte rules;
- the body contains the declared number of complete records;
+Consets are contiguous and+Donsets remain in temporal order.