read_EDF¶
High-performance EDF / EDF+ reader for MATLAB, with a compiled MEX backend and a pure-MATLAB fallback.
Handles the things that break off-the-shelf EDF readers in practice: malformed record counts in clinical files, EDF+ TAL annotations, A-B rereferencing at load time, de-identification, and large polysomnography recordings where a naive loop is slow.
Part of the Prerau Lab preraulab_utilities meta-repository. Can also be used standalone.
Quick start¶
[header, signal_header, signal_cell, annotations] = read_EDF('sleep.edf');
header— struct with main-header metadata (patient ID, record duration, start date/time, etc.)signal_header— struct array, one per channel (label, transducer, physical range, sample rate)signal_cell— cell array of channel vectors in physical units (scaled from digital)annotations— struct array of EDF+ events (onset, text)
Features¶
Feature |
What it does |
|---|---|
Full header parsing |
256-byte main header + 16-field-per-signal header per EDF spec |
MEX acceleration |
Compiled C reader; pure MATLAB fallback if MEX isn’t available or is disabled |
Channel subsetting |
Load only specific channels by name |
A-B rereferencing |
|
Epoch subsetting |
Load only a |
EDF+ annotations |
Parse TAL (Time-Annotation List) format |
Header repair |
Correct invalid |
De-identification |
Strip PHI fields and save a |
Digital → physical scaling |
|
Usage¶
Basic¶
% Load all channels
[header, sig_hdr, signals, annot] = read_EDF('psg.edf');
% Load specific channels (names are matched case-insensitively)
[~, ~, signals] = read_EDF('psg.edf', 'Channels', {'EEG C3-A2', 'EEG O2-A1', 'EOG Left-Right'});
A-B rereferencing¶
% Rereference on load — EDF file contains both EEG C3 and EEG A2 separately
[~, ~, s] = read_EDF('psg.edf', 'Channels', {'EEG C3-A2'});
The reader parses 'C3-A2', loads both channels, subtracts, and returns a single rereferenced signal.
Load a specific time window¶
% Load epochs 30 to 60 (0-indexed, in units of the EDF record duration)
[~, ~, signals] = read_EDF('psg.edf', 'Epochs', [30 60]);
Repair a broken file¶
Clinical EDFs sometimes have invalid num_data_records — the field says one number but the file actually contains a different amount of data. Passing 'RepairHeader', true recomputes the correct value and writes it to a <filename>_fixed.edf file:
[~, ~, ~] = read_EDF('broken.edf', 'RepairHeader', true);
% Writes broken_fixed.edf
De-identify¶
[~, ~, ~] = read_EDF('patient.edf', 'deidentify', true);
% Writes patient_deidentified.edf with PHI fields blanked
Force pure-MATLAB path (disable MEX)¶
[~, ~, s] = read_EDF('f.edf', 'forceMATLAB', true);
Inspect the header in a GUI¶
[header, sig_hdr] = read_EDF('f.edf');
[ht, st] = header_gui(header, sig_hdr);
% Opens a UIFIGURE with two tables — main header + per-signal headers
Name-value pairs¶
Name |
Type |
Default |
Description |
|---|---|---|---|
|
cell array of char |
|
Which channels to load; supports A-B rereferencing syntax |
|
1x2 double |
|
|
|
logical |
|
Print progress messages |
|
logical |
|
Fix invalid |
|
logical |
|
Disable MEX, use pure MATLAB reader |
|
logical |
|
Verbose MEX diagnostics |
|
logical |
|
Blank PHI fields, write |
Files¶
File |
Role |
|---|---|
|
Main entry point — dispatches to MEX or pure-MATLAB, handles rereferencing, annotations |
|
C source for the MEX accelerator |
|
Pre-built MEX binary for Apple Silicon |
|
Pre-built MEX binary for Linux x86_64 |
|
Optional UI for inspecting header + signal-header tables |
No pre-built Windows MEX is shipped; MATLAB will transparently fall back to read_EDF.m (pure MATLAB), or you can build your own:
mex read_EDF_mex.c
Install¶
addpath('/path/to/read_EDF');
When used as part of preraulab_utilities, the top-level path setup handles this automatically.
Dependencies¶
MATLAB R2020a or later
No required toolboxes for the core
read_EDF.mheader_gui.mrequiresuifigure(available in R2016a+ but most polished in R2020a+)A C compiler configured for MEX (
mex -setup C) if you need to rebuild the MEX on a new platform
Implementation notes¶
Why MEX?¶
EDF files store samples as int16 and require per-channel digital-to-physical conversion. The naive MATLAB loop is memory-bound and slow on large files. The MEX version:
Reads file regions in one
freadper recordDoes the int16 → double conversion in tight C loops
Handles annotation channels separately (they’re not numeric data)
Uses less peak memory because it doesn’t build MATLAB arrays until the end
Typical speedup for a full-night PSG file: 5-20× over the pure-MATLAB path, depending on channel count.
Pure-MATLAB fallback¶
Kicks in when the MEX binary isn’t available for your platform (Windows unless you build it) or when 'forceMATLAB', true is passed. Produces bit-identical output; just slower.
License¶
BSD 3-Clause. See LICENSE.