Index
EDF and EDF+ recordings: their header, their annotations, and the rule that pseudonymises a header.
Every reader of an EDF header in the platform uses this package, so a recording is read the same way wherever it is read.
EDF_ANNOTATIONS_LABEL = 'EDF Annotations'
module-attribute
¶
The label EDF+ gives a signal that holds annotations rather than samples.
EDF_FIXED_HEADER_BYTES = 256
module-attribute
¶
The size of the fixed part of an EDF header, in bytes.
EDF_UNKNOWN_START_DATE = date(1985, 1, 1)
module-attribute
¶
EDF+'s marker for an unknown or removed start date, 01.01.85 in the header.
EDF_VARIABLE_HEADER_SIZE_PER_SIGNAL = 256
module-attribute
¶
The size of the header part each signal adds, in bytes.
NO_HEADER_DATE_YEAR = 1900
module-attribute
¶
The year the header parser gives a recording whose header carries no usable date.
PSEUDONYMOUS_PATIENT = 'X X X X'
module-attribute
¶
The local patient identification after the rule: every EDF+ subfield unknown.
REMOVED_START_DATE = '01.01.85'
module-attribute
¶
The start date field after the rule, when dates are removed.
NotAnEdfRecording
¶
Bases: ValueError
The file does not start with a whole EDF header.
get_validated_edf_headers(fixed_header, signal_headers)
¶
Validate a parsed header and return the recording it describes.
The fixed header is refused if its version is not 0, if it marks an
interrupted recording (EDF+D), or if its header size does not match
its number of signals. A signal is refused if its number of samples per
record is not a positive multiple of the record duration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fixed_header
|
dict[str, Any]
|
The fixed header, as :func: |
required |
signal_headers
|
list[dict[str, Any]]
|
The signal headers, as :func: |
required |
Returns:
| Type | Description |
|---|---|
RecordingHeader
|
The recording's length, start and channels. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the header is refused. |
header_sha256(data)
¶
Return the SHA-256 of the EDF header at the start of data.
The header is the fixed header and every signal header; any bytes after it are ignored.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
is_pseudonymised(fixed_header, *, keep_dates)
¶
Whether an EDF fixed header already follows the pseudonymisation rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fixed_header
|
bytes
|
The first 256 bytes of an EDF or EDF+ file. |
required |
keep_dates
|
bool
|
Whether the rule keeps the start date. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if applying the rule would change nothing. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_edf_annotations(readable, n_signals, n_records, record_duration_seconds, samples_per_record, annotation_signal_indices)
¶
Read the annotations of an EDF+ recording's data records.
Only the annotation signals are read: the reader seeks past every other
signal. Parsing stops once :data:MAX_ANNOTATION_DENSITY annotations per
second of recording have been read, and never before 100.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readable
|
SeekableReadable
|
The recording, positioned at the start of its data records. |
required |
n_signals
|
int
|
The number of signals, annotation signals included. |
required |
n_records
|
int
|
The number of data records. |
required |
record_duration_seconds
|
float
|
The duration of one data record. |
required |
samples_per_record
|
list[int]
|
Each signal's samples per data record. |
required |
annotation_signal_indices
|
list[int]
|
The indices of the annotation signals. |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[int, int, str, str | None]]
|
|
list[tuple[int, int, str, str | None]]
|
onset is at least 0 and at most :data: |
list[tuple[int, int, str, str | None]]
|
its duration capped at the same. |
list[tuple[int, int, str, str | None]]
|
|
list[tuple[int, int, str, str | None]]
|
matched, else None. |
parse_edf_fixed_header(header_bytes)
¶
Parse the 256-byte fixed part of an EDF header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header_bytes
|
bytes
|
The first 256 bytes of an EDF file. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
The fields by name, as :data: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_edf_signal_headers(header_bytes)
¶
Parse the per-signal part of an EDF header.
The part stores each field for every signal in turn: all labels, then all transducers, and so on.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header_bytes
|
bytes
|
The 256 bytes per signal that follow the fixed header. |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
One dictionary of fields per signal, as :data: |
list[dict[str, Any]]
|
reads them. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_edf_start_date(start_date)
¶
Parse the dd.mm.yy start date field of an EDF header.
The two-digit year is read as the most recent year that is not in the
future: 68 is 1968, not 2068. 01.01.85 therefore parses as
1985-01-01, which is also EDF+'s marker for an unknown date; the two are
spelled identically, so the parser cannot tell them apart and does not
try. :data:EDF_UNKNOWN_START_DATE lets a reader recognise it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
str
|
The field's text, e.g. |
required |
Returns:
| Type | Description |
|---|---|
date | None
|
The date, or None if the field is not a valid date. |
parse_edf_start_time(start_time)
¶
Parse the hh.mm.ss start time field of an EDF header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_time
|
str
|
The field's text, e.g. |
required |
Returns:
| Type | Description |
|---|---|
time | None
|
The time, or None if the field is not a valid time. |
pseudonymise_file_header(path, *, keep_dates)
¶
Apply the pseudonymisation rule to the header of an EDF file, in place.
Only the first 256 bytes are read, and they are written back only if the rule changes them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The EDF or EDF+ file. |
required |
keep_dates
|
bool
|
Keep the start date, or replace it with EDF+'s marker for an unknown date. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the header was changed. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file does not start with the fixed header of an EDF file. |
pseudonymise_header(fixed_header, *, keep_dates)
¶
Apply the pseudonymisation rule to an EDF fixed header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fixed_header
|
bytes
|
The first 256 bytes of an EDF or EDF+ file. |
required |
keep_dates
|
bool
|
Keep the start date, or replace it with EDF+'s marker for an unknown date. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
The rewritten 256 bytes. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
read_edf_raw_headers_from_readable(readable)
¶
Read and parse an EDF header from the start of a file or stream.
Reads the header only, leaving readable at the start of the data
records.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readable
|
Readable
|
The file or stream, positioned at its first byte. |
required |
Returns:
| Type | Description |
|---|---|
tuple[dict[str, Any], list[dict[str, Any]]]
|
The fixed header and the signal headers. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If either part cannot be parsed. |
read_edf_recording_header_from_readable(readable)
¶
Read, parse and validate an EDF header from the start of a file or stream.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readable
|
Readable
|
The file or stream, positioned at its first byte. |
required |
Returns:
| Type | Description |
|---|---|
RecordingHeader
|
The recording's length, start and channels. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the header cannot be parsed or is refused. |
read_recording(path, *, annotation_text)
¶
Read what an ingest reports about the EDF or EDF+ file at path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The file, as the container sees it: after the rule. |
required |
annotation_text
|
bool
|
Keep the text of annotations that match no label. |
required |
Annotations that are malformed, or outside the recording, are left out; only the header can make a file unreadable.
Raises:
| Type | Description |
|---|---|
NotAnEdfRecording
|
If the file does not start with a whole EDF header. |
validate_edf_recording(readable, full_file_size)
¶
Validate the start of an EDF recording against the size of the whole file.
The header must parse, must be valid, and must account for the whole file: its size plus two bytes per sample of every data record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readable
|
Readable
|
The start of the recording, at least its full header, positioned at its first byte. |
required |
full_file_size
|
int
|
The size of the whole file in bytes. |
required |
Returns:
| Type | Description |
|---|---|
RecordingHeader
|
The recording's length, start and channels. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file is too small, its header cannot be parsed or is refused, or its size does not match the header. |