mne_rt.RTStream#
- class mne_rt.RTStream(subject_id: str, session: str, subjects_dir: str, montage: str | None, data_type: str = 'eeg', mri: bool = False, subject_fs_id: str = 'fsaverage', subjects_fs_dir: str | None = None, bandpass_freq: tuple | None = None, notch_freq: float | list | None = None, artifact_correction: bool | str = False, save_nf_signal: bool = True, config_file: str | None = None, verbose: bool | str | None = None)[source]#
Bases:
ModalityMixinReal-time Real-time M/EEG session controller.
Orchestrates LSL streaming, optional artifact rejection, parallel feature extraction, and real-time visualisation for a complete neurofeedback session. Inherits all feature-extraction methods from
ModalityMixin.- Parameters:
- subject_id
str Unique subject identifier (non-empty string). Used as the BIDS subject label (e.g.
"sub01"→ foldersub-sub01/).- session
str BIDS session label (e.g.
"01","pre","week1"). Used to name output files and directories following the BIDS conventionsub-<ID>_ses-<session>_task-<task>.- subjects_dir
str Root directory that holds one sub-folder per subject.
- montage
str|None EEG montage — a MNE built-in name (e.g.
"easycap-M1"), a path to a.bvctCapTrak file, orNonefor MEG.- data_type{“eeg”, “meg”}, default “eeg”
Recording modality. Controls channel selection and forward model.
- mribool, default
False If
True, individual MRI anatomy is used for source localisation instead of thefsaveragetemplate.- subject_fs_id
str, default “fsaverage” FreeSurfer subject identifier. Use
"fsaverage"for template- based source localisation.- subjects_fs_dir
str|None, defaultNone FreeSurfer subjects directory. Required when
subject_fs_id != "fsaverage"or whenshow_brain_activationis requested.- bandpass_freq
tuple(float,float) |None, defaultNone Online band-pass filter applied to the LSL stream before feature extraction, as
(l_freq, h_freq)in Hz.Nonedisables band-pass filtering. Example:(1.0, 40.0)for a standard EEG band-pass.- notch_freq
float|list[float] |None, defaultNone One or more frequencies (Hz) to suppress with an IIR notch filter.
Nonedisables notch filtering. Example:50or[50, 100]for 50 Hz power-line interference and its harmonic.- artifact_correction{
False, “lms”, “orica”, “gedai”, “asr”, “maxwell”}, defaultFalse Real-time artifact correction strategy applied sample-by-sample inside the acquisition loop.
False— no correction"lms"— adaptive LMS regression on a frontal reference channel; fast and lightweight (EEG only). (AdaptiveLMSFilter)"orica"— online recursive ICA; blind source separation with continuous weight updates. (ORICA)"gedai"— generalised eigendecomposition artefact isolation; callfit_gedai()afterrecord_baseline(). (GEDAIDenoiser)"asr"— Artifact Subspace Reconstruction; callfit_asr()afterrecord_baseline(). (ASRDenoiser)"maxwell"— Signal Space Separation / tSSS for MEG; callfit_maxwell()beforerecord_main()(MEG only). (RTMaxwellFilter)
- save_nf_signalbool, default
True Save extracted feature time-series as JSON.
- config_file
str|None, defaultNone Path to a YAML configuration file.
Noneuses the bundled default (config_methods.yml).- verbosebool |
str|None, defaultNone Verbosity level. Mirrors MNE’s convention:
True/"INFO"→ informational,False/"WARNING"→ warnings only,"DEBUG"→ all messages.
- subject_id
- Raises:
ValueErrorIf any constructor argument fails validation.
See also
ant.modalities.ModalityMixinAll supported NF feature methods.
mne_rt.viz.NFPlotScrolling real-time NF signal display.
mne_rt.viz.RawPlotScrolling raw M/EEG channel viewer (bad-channel / bad-segment marking).
mne_rt.viz.EpochPlotScrolling raw viewer with trigger/epoch overlays.
mne_rt.viz.BrainPlot3D brain activation display.
Notes
Typical workflow:
nf = RTStream("sub01", session="01", subjects_dir="/data/subjects", montage="easycap-M1") nf.connect_to_lsl() nf.record_baseline(baseline_duration=120) nf.record_main(duration=600, modality=["sensor_power", "erd_ers"])
The main main loop runs M/EEG acquisition in a background daemon thread and drives all visualisation windows (StreamViewer, signal plot, brain plot) from the Qt event loop on the main thread via a 33 ms pump timer, ensuring all three windows are truly parallel and non-blocking.
Added in version 1.0.0.
- __init__(subject_id: str, session: str, subjects_dir: str, montage: str | None, data_type: str = 'eeg', mri: bool = False, subject_fs_id: str = 'fsaverage', subjects_fs_dir: str | None = None, bandpass_freq: tuple | None = None, notch_freq: float | list | None = None, artifact_correction: bool | str = False, save_nf_signal: bool = True, config_file: str | None = None, verbose: bool | str | None = None) None[source]#
Methods
__init__(subject_id, session, subjects_dir, ...)compute_inv_operator([loose, depth, ...])Compute and save the inverse operator for source localisation.
connect_to_lsl([chunk_size, mock_lsl, ...])Connect to an LSL M/EEG stream.
create_report([overwrite, include_psd, ...])Generate an HTML MNE report for the session.
fit_asr([cutoff, window_len, ...])Fit an
ASRDenoiserfrom the recorded baseline.fit_gedai([band, shrinkage, use_leadfield, ...])Fit a
GEDAIDenoiserfrom the recorded baseline.fit_maxwell([int_order, ext_order, origin, ...])Prepare real-time Maxwell filtering (SSS / tSSS) for MEG data.
get_blink_template([max_iter, method, ...])Identify the eye-blink ICA component from baseline EEG.
load_nf_data(path)Load a saved NF data file produced by
save().open_stream_viewer([bufsize])Open the mne-lsl StreamViewer for raw M/EEG monitoring.
record_baseline(baseline_duration[, ...])Record a resting-state baseline segment.
record_main(duration[, modality, picks, ...])Stream M/EEG, extract neural features, and drive NF visualisation.
replay(fname[, modality, duration, winsize, ...])Replay a saved recording as a mock LSL session.
run_blocks(blocks[, rest_duration, verbose])Run multiple NF blocks separated by rest periods.
run_orica(n_channels[, learning_rate, ...])Initialise an Online Recursive ICA (ORICA) instance.
save([nf_data, acq_delay, artifact_delay, ...])Save session outputs and disconnect the LSL stream.
Attributes
Per-modality parameter overrides applied during the NF session.
- connect_to_lsl(chunk_size: int = 10, mock_lsl: bool = False, fname: str | None = None, n_repeat: int | float = inf, bufsize_baseline: int = 4, bufsize_main: int = 3, acquisition_delay: float = 0.001, timeout: float = 15.0, stream_name: str | None = None, stream_source_id: str | None = None, pick_types: str | None = None, verbose: bool | str | None = None) None[source]#
Connect to an LSL M/EEG stream.
- Parameters:
- chunk_size
int, default 10 Samples per chunk for mock streaming.
- mock_lslbool, default
False Stream a pre-recorded file instead of live hardware. Requires
fnameor uses the bundled sample file.- fname
str|None, defaultNone Path to any MNE-readable recording for mock streaming (.fif, .vhdr, .edf, .bdf, .set, …).
Noneuses the bundled sample recording.- n_repeat
int|float, defaultnp.inf How many times to loop the mock recording.
- bufsize_baseline
int, default 4 LSL buffer size in seconds for baseline sessions.
- bufsize_main
int, default 3 LSL buffer size in seconds for main sessions.
- acquisition_delay
float, default 0.001 Seconds between acquisition polling attempts.
- timeout
float, default 15.0 Maximum wait time in seconds for the LSL connection.
- stream_name
str|None, defaultNone Connect by stream name (e.g.
neuromag2lslfor MEG devices).- stream_source_id
str|None, defaultNone Connect by stream source ID.
- pick_types
str|None, defaultNone Channel type to keep (e.g.
"eeg","mag").Nonekeeps all available channels.- verbosebool |
str|None, defaultNone Override the instance-level verbosity for this call.
- chunk_size
- Raises:
RuntimeErrorIf no LSL stream matching the given criteria is found within
timeoutseconds.
Notes
All public methods of
mne_lsl.stream.StreamLSLare also exposed directly on theRTStreaminstance after connection.Examples
Connect to a live EEG amplifier:
nf.connect_to_lsl()
Simulate from any MNE-readable file:
nf.connect_to_lsl(mock_lsl=True, fname="path/to/data.fif") nf.connect_to_lsl(mock_lsl=True, fname="path/to/data.edf")
- record_baseline(baseline_duration: float, winsize: float = 3.0, verbose: bool | str | None = None) None[source]#
Record a resting-state baseline segment.
Collects
baseline_durationseconds of M/EEG, stores it asraw_baseline, saves it to disk, and computes the inverse operator (stored asinv).- Parameters:
Notes
Output files written under
<subjects_dir>/sub-<ID>/ses-<session>/:eeg/sub-<ID>_ses-<session>_task-baseline_eeg.fifinv/sub-<ID>_ses-<session>_task-baseline_inv.fifinv/sub-<ID>_ses-<session>_task-baseline_fwd.fifinv/sub-<ID>_ses-<session>_task-baseline_cov.fif
Examples
>>> nf.record_baseline(baseline_duration=120)
- record_main(duration: float, modality: str | list[str] = 'sensor_power', picks: str | list[str] | None = None, winsize: float = 1.0, estimate_delays: bool = False, modality_params: dict[str, Any] | None = None, show_raw_signal: bool = True, show_nf_signal: bool = True, time_window: float = 10.0, show_topo: bool = False, topo_bands: dict | None = None, show_brain_activation: bool = False, brain_surf: str = 'inflated', brain_mode: str = 'power', brain_freq_range: tuple[float, float] = (8.0, 13.0), zscore_normalize: bool = False, zscore_warmup: int = 10, zscore_alpha: float = 0.0, osc_sender: Any | None = None, lsl_sender: Any | None = None, protocol: Any | None = None, save_raw: bool = False, ref_channel: str = 'Fp1', signal_smoothing: float = 0.25, display_smoothing: float = 0.3, topo_display_smoothing: float = 1.0, brain_display_smoothing: float = 0.3, track_artifact_rate: bool = True, artifact_threshold_uv: float = 100.0, track_snr: bool = False, snr_frange: tuple | None = None, verbose: bool | str | None = None) None[source]#
Stream M/EEG, extract neural features, and drive NF visualisation.
This is the main closed-loop entry point. It:
Prepares each requested modality (calls
_<modality>_prep).Opens the selected visualisation windows (StreamViewer, signal plot, brain plot) on the main thread.
Starts a background daemon thread that continuously fetches data, runs artifact correction, and computes features in parallel via a thread pool.
Drives all windows from the Qt event loop via a 33 ms pump timer.
Saves raw data and feature time-series to disk when finished.
- Parameters:
- duration
float Total recording length in seconds.
- modality
str|listofstr, default “sensor_power” NF feature(s) to extract. Must match keys in
config_methods.yml. Multiple modalities are extracted in parallel. Available modalities:"sensor_power","band_ratio","erd_ers","laterality","laterality_erd_ers","hjorth","spectral_centroid","argmax_freq","individual_peak_power","entropy","instantaneous_phase","scp","peak_alpha_freq","sensor_connectivity","cfc_sensor","sensor_graph","connectivity_ratio","source_power","source_connectivity","source_graph".- picks
str|listofstr|None, defaultNone Channel selection passed to the LSL stream.
Noneuses all available channels. Must beNonefor source-space modalities.- winsize
float, default 1.0 Analysis window length in seconds.
- estimate_delaysbool, default
False Measure and save per-step timing (acquisition, artifact correction, feature extraction).
- modality_params
dict|None, defaultNone Per-modality parameter overrides. Keys are modality names; values are dicts of
{parameter: new_value}pairs that override the config-file defaults.- show_raw_signalbool, default
True Show the
RawPlotscrolling raw M/EEG viewer.- show_nf_signalbool, default
True Show the
NFPlotreal-time NF monitor.- time_window
float, default 10.0 Visible time range in seconds for the signal plot.
- show_topobool, default
False Show the
TopomapPlotreal-time scalp topomap display. Requires the montage to be set on the channel info.- topo_bands
dict|None, defaultNone Frequency bands to show in the topomap as
{label: (f_low, f_high)}.Noneuses the default δ/θ/α/β/γ bands.- show_brain_activationbool, default
False Show the
BrainPlot3D brain activation display (requiressubjects_fs_dirand a fitted inverse operator).- brain_surf{“inflated”, “pial”, “white”, “sphere”}, default “pial”
Cortical surface geometry for the brain display.
"pial"shows the true cortical folding;"inflated"unfolds gyri/sulci for easier label inspection.- brain_mode{“power”, “activation”}, default “power”
Source-space display mode.
"power"shows mean squared amplitude;"activation"shows mean amplitude.- brain_freq_range(
float,float), default (8.0, 13.0) Frequency band in Hz used to band-pass the data before computing source power for the brain display.
- zscore_normalizebool, default
False Apply online z-score normalisation to each NF feature value before storing and displaying it. During the first
zscore_warmupwindows the raw value is passed through unchanged; once warmup completes, each value is normalised asz = (x − μ) / σwhere μ and σ are estimated from the warmup windows. Ifzscore_alpha > 0the statistics are updated after every window with an exponential moving average so the normaliser slowly tracks drift.- zscore_warmup
int, default 10 Number of windows to collect before activating normalisation. The mean and standard deviation of these windows are used as the initial statistics.
- zscore_alpha
float, default 0.0 EMA forgetting factor for updating μ and σ each window.
0.0freezes statistics after warmup (recommended for most NF protocols). Values in [0.01, 0.1] add slow adaptation.- osc_sender
OSCSender|None, defaultNone If provided, each computed NF value is also broadcast over OSC to the configured host/port after every update cycle. See
OSCSender.- lsl_sender
LSLSender|None, defaultNone If provided, each computed NF value is pushed into an LSL stream outlet after every update cycle. Faster and more reliable than OSC for same-machine feedback delivery. See
LSLSender.- protocol
Protocolinstance|dict|None, defaultNone Real-time NF reward protocol evaluated on every analysis window. Pass a single Protocol instance (e.g.
ThresholdProtocol) to apply it to the first modality, or a{modality_name: protocol}dict to apply different protocols to different modalities. On each window the protocol’sevaluate(value)method is called and(crossed, magnitude)is recorded. Results are accessible viareward_dataafter the session.- save_rawbool, default
False Persist the raw pre-correction M/EEG acquired during the main session to
raw/<stem>-raw.fif. Off by default because FIF files can be large; enable when the raw continuous signal is needed for offline re-analysis or provenance.- signal_smoothing
float, default 0.25 Exponential moving average (EMA) factor applied to each NF feature value before it is stored and displayed. Controls the trade-off between signal smoothness and responsiveness:
1.0— no smoothing; raw per-window estimate passed through.0.5— moderate smoothing; each value is 50 % new + 50 % history.0.1— heavy smoothing; very slow response to rapid changes.
The EMA is applied after z-score normalisation (if enabled) and before protocol evaluation, so protocols see the smoothed value.
- display_smoothing
float, default 0.3 Additional EMA factor applied only inside the live signal plot. Does not affect stored
nf_dataor protocol evaluation. Lower values give a smoother, slower-reacting display curve;1.0disables this extra layer and shows the alreadysignal_smoothing-filtered values directly.- topo_display_smoothing
float, default 1.0 EMA factor for the
TopomapPlotband-power maps.1.0(default) disables smoothing so transient artifacts remain visible for operator monitoring. Lower values progressively smooth the spatial maps across consecutive windows.- brain_display_smoothing
float, default 0.3 EMA factor for the
BrainPlotper-vertex activation arrays. Blends consecutive frames so the cortical map transitions smoothly.1.0disables smoothing.- ref_channel
str, default “Fp1” Reference channel used for LMS artifact correction (
artifact_correction="lms"only). Ignored for all other correction methods.- track_artifact_ratebool, default
True If
True, count windows whose peak-to-peak amplitude exceedsartifact_threshold_uvand store the fraction asartifact_rateat the end of the session.- artifact_threshold_uv
float, default 100.0 Peak-to-peak amplitude threshold in µV used to classify a window as artifactual when
track_artifact_rate=True.- track_snrbool, default
False If
True, compute a per-window signal-to-noise ratio (band power insnr_frangedivided by broadband noise power, in dB) and store the resulting time-series assnr_data.- snr_frange
tuple(float,float) |None, defaultNone Frequency band
(f_low, f_high)in Hz used as the “signal” band whentrack_snr=True.Nonedefaults to the alpha band(8.0, 13.0).- verbosebool |
str|None, defaultNone Override the instance-level verbosity for this call.
- duration
- Raises:
NotImplementedErrorIf a requested
modalityis not implemented.ValueErrorIf a source-space modality is requested together with non-
Nonepicks.RuntimeErrorIf
show_brain_activation=Truebutsubjects_fs_diris not set, or ifartifact_correction="gedai"butfit_gedai()has not been called.
Notes
Output files written under
<subjects_dir>/sub-<ID>/ses-<session>/:beh/sub-<ID>_ses-<session>_task-neurofeedback_beh.json— NF feature time-series plus session metadatadelays/sub-<ID>_ses-<session>_task-neurofeedback_delays.json— per-step timing (only whenestimate_delays=True)eeg/sub-<ID>_ses-<session>_task-neurofeedback_eeg.fif— pre-correction M/EEG (only whensave_raw=True)
Examples
Single-modality alpha-power NF with brain activation:
nf.record_main( duration=300, modality="sensor_power", show_brain_activation=True, )
Multi-modality session with custom parameters:
nf.record_main( duration=600, modality=["sensor_power", "erd_ers", "laterality"], modality_params={"sensor_power": {"frange": [10, 12]}}, show_nf_signal=True, )
Added in version 1.0.0.
- replay(fname: str, modality: str | list[str] = 'sensor_power', duration: float | None = None, winsize: float = 1.0, verbose: bool | str | None = None, **record_main_kwargs) None[source]#
Replay a saved recording as a mock LSL session.
Loads a pre-recorded M/EEG file (any MNE-readable format), streams it via
PlayerLSLat its native sampling rate, and passes the live stream throughrecord_main()— exercising the full real-time pipeline (artifact correction, feature extraction, protocol evaluation) without live hardware.Useful for:
Offline parameter tuning (test different protocols on the same data).
Verifying pipeline latency and modality behaviour.
Reproducing a session with modified parameters.
- Parameters:
- fname
str Path to any MNE-readable recording (
.fif,.vhdr,.edf,.bdf,.set, …).- modality
str|listofstr, default “sensor_power” NF modality(ies) to extract.
- duration
float|None, defaultNone Duration of replay in seconds.
Noneinfers the full recording length from the file.- winsize
float, default 1.0 Analysis window length in seconds.
- verbosebool |
str|None, defaultNone Override instance verbosity for this call.
- **record_main_kwargs
Additional keyword arguments forwarded to
record_main()(e.g.protocol,modality_params,track_snr).
- fname
Examples
Replay a saved EEG file and run a ZScore protocol offline:
from mne_rt.protocols import ZScoreProtocol nf.replay( "sub-01/ses-01/eeg/sub-01_ses-01_task-neurofeedback_eeg.fif", modality="sensor_power", protocol=ZScoreProtocol(), show_nf_signal=False, show_raw_signal=False, ) print(f"Artifact rate: {nf.artifact_rate:.1%}")
Added in version 1.0.0.
- run_blocks(blocks: list[dict], rest_duration: float = 30.0, verbose: bool | str | None = None) list[dict][source]#
Run multiple NF blocks separated by rest periods.
Each block calls
record_main()with the parameters given in the corresponding dict. Blocks are separated byrest_durationseconds of silence (no acquisition, no feedback).- Parameters:
- blocks
listofdict Each dict is passed as keyword arguments to
record_main(). The key"rest"(optional) overridesrest_durationfor the pause after that block. All other keys must be validrecord_main()parameters.Minimal example:
blocks = [ {"duration": 120, "modality": "sensor_power"}, {"duration": 120, "modality": "sensor_power", "rest": 60}, {"duration": 120, "modality": "sensor_power"}, ]
- rest_duration
float, default 30.0 Default inter-block rest period in seconds.
- verbosebool |
str|None, defaultNone Override instance verbosity for this call.
- blocks
- Returns:
- all_nf_data
listofdict One dict per block, each matching
nf_datafrom that block’srecord_main()call. Also stored asblock_nf_data.
- all_nf_data
Notes
save()is called internally at the end of each block byrecord_main(). The returned list lets you inspect per-block feature time-series without re-loading JSON files.Examples
Three 2-minute NF runs separated by 30-second rests:
nf.connect_to_lsl(mock_lsl=True, fname="recording.fif") nf.record_baseline(baseline_duration=60) results = nf.run_blocks( blocks=[ {"duration": 120, "modality": "sensor_power", "show_nf_signal": False, "show_raw_signal": False}, {"duration": 120, "modality": "sensor_power", "show_nf_signal": False, "show_raw_signal": False}, {"duration": 120, "modality": "sensor_power", "show_nf_signal": False, "show_raw_signal": False}, ], rest_duration=30.0, ) for i, block_data in enumerate(results): vals = block_data["sensor_power"] print(f"Block {i+1}: {len(vals)} windows, mean={sum(vals)/len(vals):.4f}")
Added in version 1.0.0.
- property modality_params: dict#
Per-modality parameter overrides applied during the NF session.
A flat or nested dict that maps modality keys (e.g.
"sensor_power") to keyword arguments forwarded to the corresponding feature extractor.Noneis accepted on assignment and normalised to{}.Examples
>>> nf.modality_params = {"sensor_power": {"frange": [10, 12]}, ... "erd_ers": {"frange": [8, 13]}}
- get_blink_template(max_iter: int = 800, method: str = 'infomax', n_components: int | float | None = 0.95, fit_params: dict | None = None, random_state: int | None = 0, iclabel_threshold: float = 0.5) None[source]#
Identify the eye-blink ICA component from baseline EEG.
Sets
self.blink_template(ndarray) — the spatial template vector for the blink component, used by artifact correction during the main session.- Parameters:
- max_iter
int, default 800 Maximum number of ICA fitting iterations.
- method
str, default “infomax” ICA algorithm passed to
mne.preprocessing.ICA. Common choices:"infomax","fastica","picard".- n_components
int|float|None, default 0.95 Number of PCA components before ICA. A float in (0, 1) retains enough components to explain that fraction of variance.
Noneuses all channels. Falls back to5if the initial fit fails.- fit_params
dict|None, defaultNone Extra keyword arguments forwarded to the ICA solver.
Nonedefaults to{"extended": True}for infomax (recommended).- random_state
int|None, default 0 Seed for reproducible ICA solutions.
- iclabel_threshold
float, default 0.5 Minimum ICLabel probability for a component to be classified as
"eye blink". Lower values are more permissive; higher values require stronger confidence.
- max_iter
- run_orica(n_channels: int, learning_rate: float = 0.1, block_size: int = 256, online_whitening: bool = True, calibrate_pca: bool = False, forgetfac: float = 1.0, nonlinearity: str = 'tanh', random_state: int | None = None) None[source]#
Initialise an Online Recursive ICA (ORICA) instance.
ORICA is a streaming, adaptive ICA algorithm that updates its unmixing matrix incrementally as each new EEG block arrives — without ever storing the full recording. It is the preferred real-time alternative to offline ICA when the signal statistics change over time (non-stationarity).
- Parameters:
- n_channels
int Number of EEG/MEG channels. Must match the channel count of the data passed to each subsequent
partial_fit()orfit_transform()call.- learning_rate
float, default 0.1 Step size for the online natural-gradient update of the unmixing matrix W. Larger values adapt faster but may oscillate; values in [0.01, 0.2] are typically stable.
- block_size
int, default 256 Number of samples per update block. Smaller blocks give finer temporal resolution at the cost of noisier gradient estimates. Must be ≥
n_channels.- online_whiteningbool, default
True If
True, a recursive PCA whitening step is applied to each block before the ICA update, keeping the algorithm numerically stable as signal variance drifts.- calibrate_pcabool, default
False If
True, run a batch PCA on the first block to initialise the whitening matrix before switching to online updates. Recommended when starting cold with no prior covariance estimate.- forgetfac
float, default 1.0 Exponential forgetting factor for the online covariance estimate (1.0 = no forgetting; 0.99 → slowly decaying influence of older samples). Values < 1 help track gradual changes in the mixing matrix.
- nonlinearity
str, default “tanh” Score function used in the natural-gradient ICA update.
"tanh"works well for super-Gaussian sources (spikes, blinks);"logcosh"is a smooth approximation with similar properties.- random_state
int|None, defaultNone Seed for reproducible initialisation of the unmixing matrix W.
Noneuses a random seed.
- n_channels
See also
ant.tools.ORICAThe underlying ORICA implementation.
RTStream.get_blink_templateCompute a blink spatial template to guide component identification.
Notes
run_orica()is called automatically insiderecord_baseline()whenartifact_correction="orica"is set on theRTStreaminstance. Call it manually only if you need to tune the ORICA hyperparameters.
- fit_gedai(band: tuple[float, float] = (8.0, 13.0), shrinkage: float = 0.01, use_leadfield: bool = True, verbose: bool | str | None = None) None[source]#
Fit a
GEDAIDenoiserfrom the recorded baseline.Must be called after
record_baseline()and beforerecord_main()whenartifact_correction="gedai".- Parameters:
- band
tupleoffloat, default (8.0, 13.0) Target frequency band
(low_Hz, high_Hz)used when fitting in band-filter mode (use_leadfield=False). Ignored whenuse_leadfield=True.- shrinkage
float, default 0.01 Tikhonov regularisation strength applied to the reference covariance before solving the generalised eigenvalue problem. Larger values improve numerical stability at the cost of slightly less discriminative spatial filters.
- use_leadfieldbool, default
True If
Trueand a forward solution is available (i.e.,compute_inv_operator()has been called), fit in leadfield mode — the true GEDAI algorithm (Ros et al., 2025). The forward gain matrix \(\mathbf{L}\) is used as the reference covariance \(\mathbf{R} = \mathbf{L}\mathbf{L}^\top\), so components that best explain the theoretical brain-source model are kept and non-leadfield-aligned components (artifacts) are removed.If
False, or if no forward solution is available, falls back to band-filter mode: the GEP is solved between the band-filtered and broadband EEG covariances (Cohen, 2022).- verbosebool |
str|None, defaultNone Override the instance-level verbosity for this call.
- band
- Raises:
RuntimeErrorIf
record_baseline()has not been called yet.
See also
ant.tools.GEDAIDenoiserThe underlying GED denoiser class.
RTStream.compute_inv_operatorComputes the forward solution required for leadfield mode.
References
Ros, T., Férat, V., Huang, Y., et al. (2025). Return of the GEDAI: Unsupervised EEG Denoising based on Leadfield Filtering. bioRxiv. https://doi.org/10.1101/2025.10.04.680449
Examples
Leadfield mode (recommended — requires forward solution):
>>> nf.record_baseline(baseline_duration=120) >>> nf.compute_inv_operator() # builds the forward model >>> nf.fit_gedai(use_leadfield=True) >>> nf.record_main(duration=600, artifact_correction="gedai")
Band-filter mode (no MRI required):
>>> nf.record_baseline(baseline_duration=120) >>> nf.fit_gedai(band=(8, 13), use_leadfield=False) >>> nf.record_main(duration=600, artifact_correction="gedai")
- fit_asr(cutoff: float = 5.0, window_len: float = 1.0, max_dropout_fraction: float = 0.1, verbose: bool | str | None = None) None[source]#
Fit an
ASRDenoiserfrom the recorded baseline.Must be called after
record_baseline()and beforerecord_main()whenartifact_correction="asr".- Parameters:
- cutoff
float, default 5.0 Rejection threshold in standard deviations above the clean-data RMS per component. Lower values (e.g. 3) are more aggressive; higher values (e.g. 10) are more conservative. The Mullen et al. (2015) default is 5.0.
- window_len
float, default 1.0 Calibration window length in seconds. Shorter windows give more estimates but with higher variance. Recommend 0.5–1.0 s.
- max_dropout_fraction
float, default 0.1 Fraction of calibration windows with the highest total power to discard before estimating clean statistics.
0.1keeps the 90 % cleanest windows.- verbosebool |
str|None, defaultNone Override the instance-level verbosity for this call.
- cutoff
- Raises:
RuntimeErrorIf
record_baseline()has not been called yet.
See also
ant.tools.ASRDenoiserThe underlying ASR implementation.
RTStream.record_baselineRecords and stores the baseline segment.
References
Mullen, T. R., et al. (2015). Real-Time Neuroimaging and Cognitive Monitoring Using Wearable Dry EEG. IEEE Trans. Biomed. Eng., 62(11), 2553–2567.
Examples
>>> nf.record_baseline(baseline_duration=120) >>> nf.fit_asr(cutoff=5.0) >>> nf.record_main(duration=600, artifact_correction="asr")
- fit_maxwell(int_order: int = 8, ext_order: int = 3, origin: str | tuple = 'auto', st_duration: float | None = None, st_correlation: float = 0.98, st_update_interval: int = 1, calibration: str | None = None, cross_talk: str | None = None, coord_frame: str = 'head', regularize: str | None = 'in', mag_scale: float = 100.0, empty_room_raw: Any | None = None, verbose: bool | str | None = None) None[source]#
Prepare real-time Maxwell filtering (SSS / tSSS) for MEG data.
Computes the Signal Space Separation (SSS) projection operator once from sensor geometry. No baseline recording is required — the SSS basis is entirely geometric. Call this method at any point before
record_main()whenartifact_correction="maxwell".- Parameters:
- int_order
int, default 8 Internal spherical-harmonic expansion order.
8→ 80 internal moments (MNE default, adequate for all standard MEG systems).- ext_order
int, default 3 External expansion order (
3→ 16 external moments).- originarray_like
ofshape(3,) | “auto”, default “auto” SSS expansion origin in metres (head frame).
"auto"places it at the geometric centre of the sensor array.- st_duration
float|None, defaultNone Temporal SSS (tSSS) buffer duration in seconds.
None— spatial SSS only. The pre-computed projector is applied per chunk via a single matrix multiply.float— tSSS mode. A rolling buffer ofst_durationseconds feeds MNE’s full tSSS everyst_update_intervalchunks for temporal interference suppression. The spatial SSS projector is always applied first (zero-latency stage 1).
Typical values: 10 s for persistent shielding leakage, 1–4 s for moving subjects.
- st_correlation
float, default 0.98 Minimum inside-outside correlation for tSSS suppression.
- st_update_interval
int, default 1 Apply tSSS every N chunks. Increase to reduce CPU load when
winsizeis small.- calibration
str|None, defaultNone Path to the fine-calibration
.datfile. Strongly recommended for Elekta/MEGIN systems — it corrects sensor position and orientation errors.- cross_talk
str|None, defaultNone Path to the cross-talk
.fiffile. Compensates for flux leakage between adjacent sensors.- coord_frame{“head”, “meg”}, default “head”
Coordinate frame for the spherical-harmonic expansion.
- regularize{“in”,
None}, default “in” Internal-moment regularisation passed to MNE.
"in"(Tikhonov) is recommended for most datasets.- mag_scale
float, default 100.0 Magnetometer/gradiometer balance factor in the SSS decomposition.
- empty_room_raw
mne.io.Raw|None, defaultNone Empty-room recording (shielded room, no subject). When provided, the SSS operator is extracted via system identification so that noise-informed regularisation from the empty room is incorporated into the cached matrix. This improves suppression of spatially correlated sensor noise and is equivalent to passing
noise_covtomaxwell_filter().When
None, geometric regularisation only is used viacompute_maxwell_basis()(faster, adequate when shielding is good).- verbosebool |
str|None, defaultNone Override instance-level verbosity.
- int_order
- Raises:
RuntimeErrorIf no LSL stream has been connected yet (
connect_to_lsl()must be called first so thatself.rec_infois populated).ValueErrorIf this instance was initialised with
data_type="eeg"(Maxwell filtering is MEG-only).
Notes
See
RTMaxwellFilterfor the underlying filter class andfit_asr()for the EEG alternative (ASR).Unlike
fit_asr()andfit_gedai(), no baseline recording is needed. The SSS operator depends only on sensor positions, not on brain signal statistics. Simply call:nf.connect_to_lsl() nf.fit_maxwell() # operator ready in seconds nf.record_main(duration=600, artifact_correction="maxwell")
If a fine-calibration file is available, passing it via
calibrationtypically reduces the RMS noise floor by 10–20 % compared to the uncalibrated SSS.References
Taulu, S., Kajola, M., & Simola, J. (2004). Suppression of interference and artifacts by the Signal Space Separation Method. Brain Topogr., 16(4), 269–275.
Taulu, S., & Simola, J. (2006). Spatiotemporal signal space separation method for rejecting nearby interference in MEG measurements. Phys. Med. Biol., 51(7), 1759–1768.
Examples
SSS-only (fastest, no latency):
>>> nf.connect_to_lsl() >>> nf.fit_maxwell() >>> nf.record_main(duration=600, artifact_correction="maxwell")
tSSS with fine calibration and empty room:
>>> import mne >>> er_raw = mne.io.read_raw_fif("empty_room.fif", preload=True) >>> nf.connect_to_lsl() >>> nf.fit_maxwell( ... st_duration=10.0, ... calibration="sss_cal.dat", ... cross_talk="ct_sparse.fif", ... empty_room_raw=er_raw, ... ) >>> nf.record_main(duration=600, artifact_correction="maxwell")
- compute_inv_operator(loose: float = 0.2, depth: float = 0.8, noise_cov_method: str = 'ad_hoc', reg: float = 0.1) None[source]#
Compute and save the inverse operator for source localisation.
Wraps MNE’s forward-solution and inverse-operator pipeline. Results are saved to
<subjects_dir>/<subject_id>/inv/.- Parameters:
- loose
float, default 0.2 Orientation constraint for cortical source dipoles.
0= fixed (normal to surface),1= fully free,0.2= loose (recommended — allows slight tangential component while favouring surface-normal currents).- depth
float|None, default 0.8 Depth-weighting exponent to compensate for the MNE bias towards superficial sources.
Nonedisables depth weighting;0.8is the MNE default. Higher values suppress surface bias more aggressively.- noise_cov_method
str, default “ad_hoc” How to estimate the noise covariance used by the inverse operator.
"ad_hoc"(default) —mne.make_ad_hoc_cov()creates a diagonal covariance from standard sensor-noise floors (1 µV for EEG, 20 fT for MEG grads, 200 fT/cm for MEG mags). Recommended when no dedicated noise recording is available: the resting-state baseline contains brain signal, not pure noise, so fitting an empirical covariance on it conflates signal and noise."empirical"— sample covariance from the baseline raw."shrunk"— Ledoit-Wolf shrinkage; more stable when n_channels ≈ n_samples."diagonal_fixed"— diagonal regularisation.
- reg
float, default 0.1 Per-channel-type regularisation added to the noise covariance diagonal via
mne.cov.regularize(). Applied only whennoise_cov_method != "ad_hoc". Set to0to skip. Helps numerical stability when the baseline recording is short relative to the number of channels.
- loose
- Raises:
RuntimeErrorIf
record_baseline()has not been called yet.
See also
mne.make_inverse_operatorUnderlying MNE function.
mne.compute_raw_covarianceNoise covariance estimation.
- open_stream_viewer(bufsize: float = 0.2) None[source]#
Open the mne-lsl StreamViewer for raw M/EEG monitoring.
- Parameters:
- bufsize
float, default 0.2 Display window size (s).
- bufsize
- save(nf_data: bool = True, acq_delay: bool = True, artifact_delay: bool = True, method_delay: bool = True, raw_data: bool = False, bids_tsv: bool = False, format: str = 'json', delay_include_trace: bool = False) dict[str, Path][source]#
Save session outputs and disconnect the LSL stream.
All output files share the stem
sub-<ID>_ses-<session>set at the start ofrecord_main(), so multiple runs in a day never overwrite each other.- Parameters:
- nf_databool, default
True Save feature time-series as
beh/<stem>_task-neurofeedback_beh.json. The JSON contains a"meta"block (subject, modalities, sfreq, duration, artifact correction, artifact rate, SNR, start/end timestamps) and a"data"block with per-modality value lists. Whentrack_snr=Truewas passed torecord_main(), the per-window SNR series is included in"data"under the key"snr_db". Reward magnitudes delivered by the protocol are saved under"reward_<modality>"keys (one per modality).- acq_delaybool, default
True Include acquisition-loop timing in the delays file (only written when
estimate_delays=Truewas set inrecord_main()).- artifact_delaybool, default
True Include artifact-correction timing in the delays file.
- method_delaybool, default
True Include per-modality feature-extraction timing in the delays file.
- raw_databool, default
False Save the pre-correction M/EEG acquired during the main session as
eeg/<stem>_task-neurofeedback_eeg.fif.- bids_tsvbool, default
False Additionally write a BIDS-compliant tab-separated values file
beh/<stem>_task-neurofeedback_beh.tsvalongside the JSON. Columns are: one per modality,reward_<modality>per modality, andsnr_dbwhen available. Each row is one analysis window. This file passes a BIDS validator and can be loaded directly by EEGLAB, Fieldtrip, or any TSV reader.- format
str, default “json” Serialisation format for NF data and delays. Currently only
"json"is supported.- delay_include_tracebool, default
False Embed the full per-window delay trace (ms) in the delays JSON alongside the summary statistics. Can be large for long sessions.
- nf_databool, default
- Returns:
Notes
Disconnects the LSL stream as a side effect — the stream is not needed after the session ends.
- classmethod load_nf_data(path: str | Path) dict[source]#
Load a saved NF data file produced by
save().- Parameters:
- path
str|Path Path to a
*_nf.jsonfile.
- path
- Returns:
- payload
dict Dict with two keys:
"meta"— session metadata: subject ID, session type, modalities, sfreq, winsize, duration, n_windows, artifact correction, start/end timestamps."data"—{modality: [values, …]}per-modality lists.
- payload
Examples
>>> d = RTStream.load_nf_data("subjects/sub-sub01/ses-01/beh/sub-sub01_ses-01_task-neurofeedback_beh.json") >>> import numpy as np >>> alpha = np.array(d["data"]["sensor_power"]) >>> print(f"Mean alpha power: {alpha.mean():.3e}") >>> print(f"Session sfreq: {d['meta']['sfreq_hz']} Hz")
- create_report(overwrite: bool = True, include_psd: bool = True, include_nf_signal: bool = True, open_browser: bool = False) Path[source]#
Generate an HTML MNE report for the session.
Produces a self-contained HTML file containing baseline recording info, sensor layouts, optional PSD, feature time-series, and brain-label diagrams for source-space modalities.
- Parameters:
- overwritebool, default
True Overwrite an existing report file with the same name.
- include_psdbool, default
True If
True, add a baseline power-spectral-density plot (1–40 Hz) to the report.- include_nf_signalbool, default
True If
Trueandnf_datais populated (i.e.,record_main()has been run), add a time-series plot of the NF feature values for each modality.- open_browserbool, default
False If
True, open the saved report in the default web browser immediately after saving.
- overwritebool, default
- Returns:
- report_path
pathlib.Path Full path of the saved HTML report file.
- report_path
- Raises:
RuntimeErrorIf
record_baseline()has not been called yet.