Skip to main content

Crate exg

Crate exg 

Source
Expand description

§exg — EEG/ECG/EMG preprocessing in pure Rust

Crate Docs

exg is a pure-Rust library for EEG preprocessing with 100% numerical parity against MNE-Python. Every DSP step is ported from MNE and verified against ground-truth test vectors (200+ tests).

No Python, no BLAS, no C libraries — pure Rust + RustFFT.

§Workspace

CrateDescription
exgCore DSP, file I/O, generic preprocessing pipeline
exg-lunaLUNA seizure-detection pipeline
exg-sourceSource localisation (eLORETA, MNE/dSPM/sLORETA)

§Features

CategoryCapabilities
File I/OFIF, EDF/EDF+, CSV readers; HDF5 (feature-gated); safetensors export
FiltersHighpass, lowpass, bandpass, notch — all MNE-parity _firwin_design
DSPFFT polyphase resampling, average reference, overlap-add convolution
NormalisationGlobal z-score, channel-wise z-score, per-epoch baseline correction
MontagesTCP bipolar (22-ch), Siena unipolar (29-ch), SEED-V unipolar (62-ch)
PipelinesGeneric preprocess(), LUNA-specific via exg-luna crate
Source localisationeLORETA, MNE/dSPM/sLORETA (via exg-source crate)

§Quick start — generic pipeline

use exg::{preprocess, PipelineConfig, fiff::open_raw};
use ndarray::Array2;

let raw  = open_raw("data/sample1_raw.fif").unwrap();
let data = raw.read_all_data().unwrap();
let chan_pos: Array2<f32> = Array2::zeros((raw.info.n_chan, 3));
let cfg  = PipelineConfig::default();           // 256 Hz · 0.5 Hz HP · 5 s epochs
let epochs = preprocess(data.mapv(|v| v as f32), chan_pos, raw.info.sfreq as f32, &cfg).unwrap();

§Quick start — LUNA seizure-detection pipeline

The LUNA pipeline lives in the separate exg-luna crate:

use exg::edf::open_raw_edf;
use exg_luna::{preprocess_luna, LunaPipelineConfig};

let raw = open_raw_edf("recording.edf").unwrap();
let data = raw.read_all_data().unwrap();
let ch_names = raw.channel_names();
let cfg = LunaPipelineConfig::default();        // 0.1–75 Hz BP · 60 Hz notch · TCP montage
let epochs = preprocess_luna(data, &ch_names, raw.header.sample_rate, &cfg).unwrap();

§Individual DSP steps

use exg::{resample::resample, filter::*, reference::*, normalize::*, epoch::*};
use ndarray::Array2;

let mut data: Array2<f32> = Array2::zeros((22, 7680));

// Resample 512 → 256 Hz
let mut data = resample(&data, 512.0, 256.0).unwrap();

// Bandpass 0.1–75 Hz
let h = design_bandpass(0.1, 75.0, 256.0);
apply_fir_zero_phase(&mut data, &h).unwrap();

// Notch 60 Hz
let h = design_notch(60.0, 256.0, None, None);
apply_fir_zero_phase(&mut data, &h).unwrap();

// Average reference → channel-wise z-score → epoch
average_reference_inplace(&mut data);
zscore_channelwise_inplace(&mut data);
let epochs = epoch(&data, 1280);                // [E, 22, 1280]

Re-exports§

pub use config::PipelineConfig;
pub use csv::read_eeg;
pub use edf::open_raw_edf;
pub use edf::RawEdf;
pub use edf::EdfHeader;
pub use edf::SignalHeader;
pub use edf::EdfAnnotation;
pub use epoch::epoch;
pub use epoch::epoch_and_baseline;
pub use fiff::open_raw;
pub use fiff::RawFif;
pub use fiff::BufferRecord;
pub use fiff::ChannelInfo;
pub use fiff::MeasInfo;
pub use fiff::read_meas_info;
pub use fiff::TagHeader;
pub use fiff::read_tag_header;
pub use fiff::read_i32;
pub use fiff::read_f32;
pub use fiff::read_f64;
pub use fiff::read_string;
pub use fiff::read_i32_array;
pub use fiff::read_f32_array;
pub use fiff::read_f64_array;
pub use fiff::read_raw_bytes;
pub use fiff::read_directory;
pub use fiff::Node;
pub use fiff::build_tree;
pub use fiff::read_tree;
pub use fiff::scan_directory;
pub use fiff::try_load_directory;
pub use filter::auto_trans_bandwidth;
pub use filter::auto_trans_bandwidth_lowpass;
pub use filter::auto_filter_length;
pub use filter::design_highpass;
pub use filter::design_lowpass;
pub use filter::design_bandpass;
pub use filter::design_notch;
pub use filter::firwin;
pub use filter::hamming;
pub use filter::apply_fir_zero_phase;
pub use filter::filter_1d;
pub use io::RawData;
pub use io::StWriter;
pub use io::write_batch;
pub use montage::make_bipolar;
pub use montage::normalize_channel_name;
pub use montage::pick_channels;
pub use montage::TCP_MONTAGE;
pub use montage::SIENA_CHANNELS;
pub use montage::SEED_V_CHANNELS;
pub use montage::BipolarDef;
pub use normalize::zscore_global_inplace;
pub use normalize::zscore_channelwise_inplace;
pub use normalize::baseline_correct_inplace;
pub use reference::average_reference_inplace;
pub use resample::resample;
pub use resample::resample_1d;
pub use resample::auto_npad;
pub use resample::rational_approx;
pub use resample::final_length;
pub use exg_source as source_localization;

Modules§

config
Pipeline configuration.
csv
CSV reader for EEG data.
edf
EDF/EDF+ file reader.
epoch
Fixed-length epoching.
fiff
FIFF file format reader.
filter
FIR filter design and application.
io
Safetensors I/O for the preprocessing pipeline.
montage
Bipolar montage conversion for EEG data.
normalize
Z-score normalisation and epoch baseline correction.
reference
Average reference: subtract the mean across channels at each time point.
resample
FFT-based rational resampler exactly matching MNE’s resample(..., method='fft').
xdf
XDF (Extensible Data Format) file writer.

Structs§

EloretaOptions
Options for the eLORETA iterative solver.
ForwardOperator
Forward operator (gain matrix + metadata).
InverseOperator
Prepared inverse operator, ready for application to data.
NoiseCov
Noise covariance matrix.
SourceEstimate
Source-space estimate produced by apply_inverse.
SphereModel
Parameters of a multi-shell spherical head model.

Enums§

InverseMethod
Choice of inverse method.
PickOri
How to handle source orientations in free-orientation inverse solutions.
Regularization
Regularisation strategy for covariance estimation.
SourceOrientation
Source orientation constraint.

Functions§

apply_inverse
Apply an inverse operator to sensor-space data.
apply_inverse_epochs
Apply inverse operator to each epoch in a batch.
apply_inverse_epochs_full
Apply inverse to epochs with full options.
apply_inverse_full
Apply inverse with full control over orientation picking and eLORETA options.
compute_covariance
Compute noise covariance from continuous data [n_channels, n_times].
compute_covariance_epochs
Compute noise covariance from epoched data [n_epochs, n_channels, n_times].
estimate_snr
Estimate SNR as a function of time.
get_cross_talk
Cross-talk function (CTF) for a given source index.
get_point_spread
Point-spread function (PSF) for a given source index.
grid_source_space
Generate a volume source space on a regular 3-D grid.
ico_n_vertices
Expected vertex count for a given icosahedron subdivision level.
ico_source_space
Generate a source space by subdividing an icosahedron.
make_inverse_operator
Build an inverse operator from a forward model and noise covariance.
make_resolution_matrix
Compute the resolution matrix R = K @ G.
make_sphere_forward
Compute a fixed-orientation EEG forward model using a spherical head.
make_sphere_forward_free
Compute a free-orientation EEG forward model using a spherical head.
peak_localisation_error
Compute peak localisation error for each source.
preprocess
Run the full EEG preprocessing pipeline on a single continuous recording.
relative_amplitude
Compute relative amplitude for each PSF.
spatial_spread
Compute spatial spread (half-max width) for each PSF.
zero_bad_channels
Zero-fill channels whose normalised name appears in bad.