MNE-RT: an open-source real-time neurofeedback/BCI framework
Hi all,
I’d like to introduce MNE-RT (link), an open-source Python package for real-time M/EEG signal processing, built on top of MNE-Python and MNE-LSL. It covers the entire closed-loop pipeline in a single, researcher-friendly API, aimed at neurofeedback, BCI, and real-time clinical/basic-science monitoring.
What it does:
- 21 real-time neural feature modalities in both sensor and source space
- Real-time single-trial decoding (CSP + any scikit-learn classifier)
- Adaptive feedback protocols: z-score, threshold, percentile, staircase, operant/RL-based, sham, multi-band, and cross-session transfer
- Online artifact-correction methods: ASR, adaptive LMS, GEDAI, ORICA, real-time Maxwell/SSS filtering for MEG
- Live visualization windows: Raw signal, NF feedback curves, epoch overlays, scalp topographies, 3D brain activity, TFR heatmaps, …
- External feedback output via OSC (Max/MSP, SuperCollider) and LSL outlets (PsychoPy, OpenViBE, BCI2000)
- BIDS-compatible session saving
- Full CLI
Use cases it’s built for: neurofeedback research, real-time BCI/motor-imagery decoding, and any closed-loop paradigm needing live feature extraction + adaptive feedback + artifact correction in one place.
Any feedback, issues, feature request, or contributions, especially from anyone doing real-time work who can stress-test it against their own hardware/paradigms are welcome!
Thanks!
Payam
Comments
Payam, wow.
This is a fantastic contribution to the BCI / neurofeedback / EEG community. I see you are the primary author. To expand your links:
Github:
https://github.com/mne-rt-org/mne-rt
Documentation:
https://mne-rt-org.github.io/mne-rt/
Modalities section:
https://mne-rt-org.github.io/mne-rt/modalities.html
Academic Paper link:
https://www.researchgate.net/publication/393419515_Advances_on_Real_Time_MEEG_Neural_Feature_Extraction
A couple preliminary questions. With the 3D source localization features, do you think that the 16 channels of OpenBCI Cyton + Daisy would provide 'usable' resolution for a simple neurofeedback protocol that say rewards a threshold of amplitude at a given Brodmann / voxel area? I realize most 3D neurofeedback (sLoreta etc.) is done with 19 channels. How about the case with only 8 channels (seems unlikely).
In a much simpler example neurofeedback program that say just rewards a threshold at a given scalp 10-20 location, what is the estimated delay time between the event at the EEG channel, and the triggered feedback? Just curious because in typical neurofeedback apps (BioEra, BrainBay, Bioexplorer, etc.) this usually a couple hundred milliseconds. Those apps are compiled code. Does the interpretive nature of Python, slow this down noticably?
Regards, William
Hi William,
Thank you so much for your interest.
Technically, MNE-RT will build a forward/inverse model and run source localisation methods (e.g. sLoreta) on 16 channels, there's no hard channel-count gate. But of course it comes with resolution limits: with 16 sensors, the leadfield's effective rank is around 16, so the number of independent spatial patterns you can actually resolve is small, and the PSF (localization blur) for any given source is typically several centimeters which is not good for deep/medial sources (e.g. cingulate, insula) than for superficial cortex. So a literal single-voxel or narrow single-Brodmann-area threshold isn't really meaningful at this density becasue neighboring gyri will smear into each other in the estimate.
That said, MNE-RT's NF modalities don't operate on raw voxels, they average activity within an anatomical label (atlas ROI, e.g. a Desikan-Killiany parcel), not a single dipole. That's actually the right granularity for low channel counts: a broad ROI (say, left vs. right sensorimotor cortex, or a whole frontal label) is far more robust to the blur than trying to isolate one small patch from its neighbors.
For 16 chs configuration, my recommendation would be well-separated ROIs rather than fine-grained Brodmann-level specificity, you'll get plausible, stable lateralization/regional contrasts, not precision imaging.
At 8 channels, I'd honestly steer away from 3D localization claims entirely, you're down to maybe 2–4 very broad distinguishable regions at best, which is more "spatial filter" than "source image. Sensor-space or a single coarse bilateral contrast would better choice there.
For a simple 10-20 montage amplitude/threshold reward, the dominant term isn't Python's interpreter, it's the acquisition window itself. MNE-RT processes windowed chunks with 50% overlap (default 1 s windows, so a new estimate every 0.5 s), and that window length is a free parameter: for a plain amplitude threshold (no need for frequency-resolved band power), you can shrink it to e.g. 0.25–0.5 s without hurting stability, since you're not FFT-resolution-limited the way you would be for narrow-band power. The actual per-window computation runs through NumPy/SciPy (vectorized C/Fortran under the hood), typically sub-millisecond to a few ms per window on ordinary hardware. On top of that there's a small display-refresh cost (the live plot updates at up to ~30 fps) and whatever latency your acquisition hardware/driver itself adds before samples even reach LSL. For Cyton+Daisy specifically, the Daisy's interleaved dual-board sampling scheme adds its own reconstruction delay, and that's outside any software's control. I guess with a short window and a simple amplitude criterion, you should land in the same "couple hundred ms", window length and hardware buffering dominate, not language choice. I haven't yet checked hardware-validated end-to-end latency numbers (it's an open item on my roadmap). Please feel free to open an issue add any feature request here.
Thanks again!
Payam
Payam,
Thanks for these great replies.
William