Skip to main content

Crate exg

Crate exg 

Source
Expand description

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

exg is a zero-dependency* Rust library that implements the EEG preprocessing pipeline. Every DSP step is ported from MNE-Python and verified against MNE ground truth via safetensors test vectors (run cargo test).

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

§Pipeline overview

sample_raw.fif
  │
  ├─ fiff::open_raw()       native FIFF reader (no MNE)
  ├─ resample::resample()   FFT polyphase → target_sfreq (default 256 Hz)
  ├─ filter (FIR HP)        firwin + overlap-add → 0.5 Hz cutoff
  ├─ reference              per-timepoint channel mean removed
  ├─ normalize (z-score)    (data − μ) / σ  over all ch × t
  ├─ epoch                  non-overlapping 5 s windows
  ├─ baseline correct       per-epoch per-channel mean removed
  └─ ÷ data_norm            ÷ 10 → std ≈ 0.1
       │
       └─→ Vec<([C, 1280] f32, [C, 3] f32)>   (epochs, channel positions)

§Quick start

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

// 1. Read a .fif file — no Python required
let raw  = open_raw("data/sample1_raw.fif").unwrap();
let data = raw.read_all_data().unwrap();          // [C, T]  f64

// 2. Channel positions from the FIF file (metres)
let chan_pos: Array2<f32> = Array2::zeros((raw.info.n_chan, 3));

// 3. Run the full preprocessing pipeline
let cfg    = PipelineConfig::default();
let epochs = preprocess(
    data.mapv(|v| v as f32),
    chan_pos,
    raw.info.sfreq as f32,
    &cfg,
).unwrap();

for (i, (epoch_data, pos)) in epochs.iter().enumerate() {
    println!("Epoch {i}: shape {:?}", epoch_data.dim());
}

§Running individual steps

Each preprocessing step is also exposed as a standalone function:

use exg::resample::resample;
use exg::filter::{design_highpass, apply_fir_zero_phase};
use exg::reference::average_reference_inplace;
use exg::normalize::zscore_global_inplace;
use exg::epoch::epoch;
use ndarray::Array2;

let mut data: Array2<f32> = Array2::zeros((12, 3840)); // [C, T]

// Resample from 1024 Hz → 256 Hz
let data = resample(&data, 1024.0, 256.0).unwrap();

// Apply 0.5 Hz highpass FIR
let h = design_highpass(0.5, 256.0);
let mut data = data;
apply_fir_zero_phase(&mut data, &h).unwrap();

// Average reference
average_reference_inplace(&mut data);

// Global z-score
let (mean, std) = zscore_global_inplace(&mut data);

// Epoch into 5 s windows
let epochs = epoch(&data, 1280); // [E, C, 1280]

§Feature coverage

See the README for a full table of which MNE features are implemented and which are not yet ported.

Re-exports§

pub use config::PipelineConfig;
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_filter_length;
pub use filter::design_highpass;
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 normalize::zscore_global_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.
epoch
Fixed-length epoching.
fiff
FIFF file format reader.
filter
FIR filter design and application.
io
Safetensors I/O for the preprocessing pipeline.
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').

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.