Skip to content

zh1peng/EEGflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EEGflow

EEGflow is a MATLAB toolbox for EEG preprocessing and analysis built on a state + pipeline design. Prep and analysis are decoupled so you can compose workflows from small, testable steps.

This README focuses on preprocessing. It is written to be friendly to humans and LLMs.


Documentation

  • Preprocessing (+prep): docs/prep.md
  • Resting-state features (+rest): docs/rest.md
  • ERP analysis (+analysis): docs/erp.md
  • Time-frequency analysis (+analysis): docs/tf.md

Prep design logic (quick mental model)

  • State is the payload: every step is state = prep.<op>(state, args, meta).
  • Steps are middleware: each op reads/writes state and appends history.
  • Registry maps op -> function: the pipeline resolves step names using a registry.
  • Job JSON is the spec: list of steps with op and args.
  • setup_io fills I/O and logging: it injects filename/filepath, LogFile, LogPath.

Job JSON (LLM-friendly schema)

Top level:

  • steps (required): array of step objects
  • Options (optional): e.g., { "validate_only": false }

Each step object:

  • id string
  • name string
  • op string (must match a prep op name)
  • args object (parameters; can be empty)

Minimal example:

{
  "steps": [
    { "id":"S001", "name":"Load", "op":"load_set",
      "args": { "filename":"", "filepath":"" } },
    { "id":"S002", "name":"Filter", "op":"filter",
      "args": { "LowCutoff":0.5, "HighCutoff":30 } },
    { "id":"S003", "name":"BadChannels", "op":"remove_bad_channels",
      "args": { "Action":"remove" } },
    { "id":"S004", "name":"Save", "op":"save_set",
      "args": { "filename":"", "filepath":"" } }
  ],
  "Options": { "validate_only": false }
}

What setup_io injects (you can omit these in JSON):

  • filename/filepath for load_set/load_mff and save_set
  • LogFile for most steps
  • LogPath for ops that write plots/files: remove_bad_channels, remove_bad_ICs

Prep ops reference (purpose + args)

Notes:

  • Defaults shown are the code defaults (from each step's inputParser).
  • LogFile/LogPath are auto-injected by prep.setup_io.

I/O

  • load_set: load EEGLAB .set
    • args: filename (char, default ''), filepath (char, default ''), LogFile (auto)
  • load_mff: load EGI .mff
    • args: filename (char, default ''), filepath (char, default ''), LogFile (auto)
  • save_set: save EEGLAB .set
    • args: filename (char, default ''), filepath (char, default ''), LogFile (auto)

Basic signal ops

  • downsample: resample data
    • args: Rate (numeric, default 250), LogFile (auto)
  • filter: bandpass or high/low pass
    • args: LowCutoff (numeric, default -1), HighCutoff (numeric, default -1), LogFile (auto)
  • remove_powerline: remove line noise
    • args: Method ('cleanline'|'notch', default 'cleanline'), Freq (50), BW (2), NHarm (3), LogFile (auto)

Segmentation

  • crop_by_markers: keep data between start/end markers
    • args: StartMarker (char, default ''), EndMarker (char, default ''), PadSec (0), LogFile (auto)
  • segment_task: epoch around markers
    • args: Markers (cellstr, default {}), TimeWindow (ms, [start end], default []), LogFile (auto)
  • segment_rest: build rest blocks and fixed-length epochs
    • args: BlockLabel ("EC"), StartCode (10), EndCode ([]), BlockDurSec ([]), TrimStartSec (0), TrimEndSec (0), EpochLength (2000 ms), EpochOverlap (0.5), LogFile (auto)

Cleaning: bad channels and epochs

  • remove_bad_channels: detect bad channels (multiple detectors)
    • args:
      • ExcludeLabel ({})
      • Action ('remove'|'flag', default 'remove')
      • KnownBadLabel ({})
      • Kurtosis (false), Kurt_Threshold (5)
      • Probability (false), Prob_Threshold (5)
      • Spectrum (false), Spec_Threshold (5), Spec_FreqRange ([1 50])
      • NormOn ('on')
      • FASTER_MeanCorr (false), FASTER_Threshold (0.4), FASTER_RefChan ([]), FASTER_Bandpass ([])
      • FASTER_Variance (false), FASTER_VarThreshold (3)
      • FASTER_Hurst (false), FASTER_HurstThreshold (3)
      • CleanRaw_Flatline (false), Flatline_Sec (5)
      • CleanDrift_Band ([0.25 0.75]), CleanRaw_Noise (false)
      • CleanChan_Corr (0.8), CleanChan_Line (4), CleanChan_MaxBad (0.5), CleanChan_NSamp (50)
      • LogFile (auto), LogPath (auto)
  • remove_bad_epoch: detect bad epochs
    • args: Autorej (true), Autorej_MaxRej (2), FASTER (true), LogFile (auto)
  • remove_bad_ICs: ICA-based component rejection
    • args:
      • RunIdx (1)
      • LogPath (auto), LogFile (auto)
      • FilterICAOn (true), FilterICALocutoff (1)
      • ICAType ('runica')
      • ICLabelOn (true), ICLabelThreshold (default matrix)
      • FASTEROn (true)
      • EOGChanLabel ({})
      • DetectECG (true), ECG_Struct ([]), ECGCorrelationThreshold (0.8)

Channel selection/interp

  • remove_channels: drop channels by index or label
    • args: ChanIdx ([]), Chan2remove ({}), LogFile (auto)
  • select_channels: keep only selected channels
    • args: ChanIdx ([]), ChanLabels ({}), LogFile (auto)
  • interpolate: interpolate channels (uses EEG.badchan etc.)
    • args: LogFile (auto)
  • interpolate_bad_channels_epoch: interpolate per epoch
    • args: ExcludeLabel ({}), LogFile (auto)

Other steps

  • reref: average reference with exclusions
    • args: ExcludeLabel ({}), LogFile (auto)
  • correct_baseline: baseline correction
    • args: BaselineWindow ([start end] ms, default []), LogFile (auto)
  • edit_chantype: set channel types
    • args: EOGLabel ({}), ECGLabel ({}), OtherLabel ({}), LogFile (auto)
  • insert_relative_markers: create markers relative to an existing marker
    • args: ReferenceMarker (''), RefOccurrence ('first'), StartOffsetSec (0), DurationSec ([]), EndOffsetSec ([]), NewStartMarker ('clip_start'), NewEndMarker ('clip_end'), OverwriteExisting (true), LogFile (auto)

End-to-end prep usage (script style)

This matches test/prep_end_to_end.m:

repoRoot   = getenv('EEGFLOW_ROOT');
dataDir    = fullfile(repoRoot, 'test', 'data', 'raw');
outDir     = fullfile(repoRoot, 'test', 'out', 'prep_run');
configPath = fullfile(repoRoot, 'config_template', 'prep_config.json');

cfg = flow.load_cfg(configPath);

% Pick input file by regex (adjust pattern to your dataset)
[paths, names] = filesearch_regexp(dataDir, '^sub-.*\\.set$', 1);
if isempty(names), error('No .set files found.'); end

% Fill IO + logging fields
cfg = prep.setup_io(cfg, ...
    'InputPath', paths{1}, ...
    'InputFilename', names{1}, ...
    'OutputPath', outDir, ...
    'Suffix', '_cleaned');

% Build pipeline (prep registry used by default)
[pipe, state, cfg] = prep.build_pipeline(cfg);

% Run
[state_out, report] = pipe.run('stop_on_error', true);

Tip: use pipe.validate() to check arguments without running heavy ops.


Advanced: add your own prep step

  1. Write a step:
function state = my_step(state, args, meta)
state = log_step(state, meta, args.LogFile, '[my_step] running...');
% ... do work ...
state = state_update_history(state, 'my_step', args, 'success', struct());
end
  1. Register it:
reg = prep.register_new_op('my_step', @my_step);
[pipe, state, cfg] = prep.build_pipeline(cfg, 'Registry', reg);
  1. Add it to JSON:
{ "id":"S999", "name":"MyStep", "op":"my_step", "args": {} }

Notes:

  • register_new_op errors on duplicates unless AllowOverride = true.

Advanced: add your own analysis step

function state = my_analysis_step(state, args, meta)
state = state_update_history(state, 'my_analysis_step', args, 'success', struct());
end

reg = analysis.register_new_op('my_analysis_step', @my_analysis_step);

Structure

  • +prep: preprocessing steps and helpers
  • +analysis: analysis steps and helpers
  • config_template: job/config templates
  • utils: general utilities

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages