EEGLAB Format¶
EEGLAB is a MATLAB toolbox for processing EEG, MEG, and other electrophysiological data. biosigIO can import EEGLAB .set files to work with biosignal data stored in this format.
Format Description¶
EEGLAB .set files are MATLAB files that contain:
- Signal data in a matrix format
- Channel information (names, locations, types)
- Event markers
- Metadata about the recording
- Processing history
Structure¶
A typical EEGLAB .set file contains these fields:
| Field | Description |
|---|---|
data |
Signal data matrix (channels × time points) |
chanlocs |
Channel information (names, types, locations) |
srate |
Sampling rate in Hz |
xmin |
Time of first data point (seconds) |
xmax |
Time of last data point (seconds) |
times |
Time points vector |
event |
Event markers |
epoch |
Epoch information (if epoched) |
subject |
Subject identifier |
condition |
Condition name or description |
Importer Implementation¶
EEGLAB saves .set files in two MATLAB container formats, both read by
biosigio.importers.eeglab.EEGLABImporter under the same .set extension:
- Classic MATLAB v5/v7 (a zlib-compressed MAT container), via
scipy.io.loadmat. - MATLAB v7.3 (an HDF5 container -- MATLAB/EEGLAB switch to this
automatically once a variable exceeds ~2 GB, or on an explicit
-v7.3save), via h5py, an optional dependency (thehdf5extra:uv sync --extra hdf5).
The importer tells the two apart by sniffing the file's leading header text
(b"MATLAB 7.3 MAT-file" vs. the classic "MATLAB 5.0 MAT-file"), not by
extension -- both forms are .set.
Classic (v5/v7) path¶
- Loading the
.setfile usingscipy.io.loadmat - Normalizing the two EEGLAB save forms to a flat field map. Real EEGLAB saves a
dataset as a single MATLAB struct named
EEG, soloadmatreturns{'EEG': struct}with every field nested one level down; the legacy form writes the fields at the top level. biosigIO unwraps the nestedEEGstruct (and accepts the flat form) before reading any field, so a real-world.setloads correctly instead of silently importing as an empty recording - Extracting the EEG structure with signal data and metadata. When the matrix is
stored in a separate float32
.fdtfile (EEGLAB's default for large recordings, whereEEG.dataholds the.fdtfilename), the sibling.fdtnext to the.setis loaded and reshaped to(nbchan, pnts * trials) - Converting channel information to biosigIO's channel format
- Creating appropriate metadata dictionary
- Loading event markers into the recording's
eventstable (onset/duration in seconds)
MATLAB v7.3 (HDF5) path¶
- Opening the file with h5py and reading the top-level
EEGgroup's fields directly (nbchan,srate,pnts,trials,data, ...). Header scalars round-trip through HDF5 as 1x1 float arrays rather than true scalars, so they are flattened and coerced to int/float explicitly - Reading the signal matrix from
EEG.data. HDF5 stores the matrix TRANSPOSED relative to MATLAB --(n_samples, n_channels)instead of biosigIO's channel-major(n_channels, n_samples)-- so it is transposed back explicitly; getting this backwards would silently swap samples and channels. WhenEEG.dataholds a.fdtfilename (a char array) instead of the numeric matrix, the sibling.fdtis resolved the same way as the classic path - Resolving
chanlocs/eventstruct-array fields (labels, types, X/Y/Z, latency, ...), each stored as an array of HDF5 object references into a#refs#group rather than as flat values. Every field is dereferenced through#refs#, and char arrays are decoded from their Unicode code-point representation - Raising the same
NotContinuousRecordingErrorthe rest of biosigIO uses whenEEG.trials > 1(an epoched file), instead of silently flattening epochs into a fake continuous stream
Code Example¶
from biosigio import Recording
# Load data from EEGLAB .set file
rec = Recording.from_file('data.set', importer='eeglab')
# Print metadata
print(f"Subject: {rec.get_metadata('subject')}")
print(f"Condition: {rec.get_metadata('condition')}")
print(f"Sampling rate: {rec.get_metadata('srate')} Hz")
# Print channel information
print(f"Number of channels: {rec.get_n_channels()}")
channel_types = rec.get_channel_types()
print(f"Channel types: {channel_types}")
# Plot data
rec.plot_signals(time_range=(0, 5))
Channel Type Mapping¶
EEGLAB doesn't always explicitly designate channel types. biosigIO's EEGLAB importer uses the following rules to assign channel types:
- Channels with 'EMG' in the name are assigned type 'EMG'
- Channels with 'EEG' in the name are assigned type 'EEG'
- Channels with 'ACC' in the name are assigned type 'ACC'
- Other channels are assigned type 'OTHER'
Notes and Limitations¶
- Both EEGLAB save forms load: the standard single
EEGstruct (loadmatreturns{'EEG': struct}, which is what real EEGLAB writes) and the legacy flat layout. The importer normalizes them before reading, so a nested-struct file no longer imports as an empty recording - Both classic (v5/v7) and MATLAB v7.3 (HDF5)
.setfiles are supported; the v7.3 path requires the optionalhdf5extra (uv sync --extra hdf5) and raises a clear install-hint error if h5py is missing - Signal data stored inline in the
.setor in a separate float32.fdtfile is supported for both save forms; the sibling.fdtis resolved by the.setpath (so BIDS-renamed files load even thoughEEG.datakeeps the original.fdtname) - Event markers are loaded into the
eventstable (rec.events): EEGLAB event latency/duration (samples) are converted to onset/duration in seconds and the eventtypebecomes the description - Channel locations (if available) are preserved in the channel information
- An epoched MATLAB v7.3 file (
EEG.trials > 1) raisesNotContinuousRecordingErrorrather than being read as a fake continuous recording. The classic path's separate, pre-existing behavior for an epoched.fdtis unchanged here: it concatenates trials into one continuous series instead (seetest_eeglab_reads_epoched_fdt). The two paths therefore disagree on what an epoched file should become; that inconsistency predates this change and is tracked separately rather than resolved here. - Some EEGLAB-specific information may not be fully preserved in the conversion
- Time information is properly handled to maintain accurate timing in the imported data