Replay PhysioNet EEG motor imagery as a simulated 4-command brain-computer interface.
Project description
NeuralSim
Replay real PhysioNet EEG motor-imagery recordings as a simulated brain-computer interface (BCI) and watch them get decoded into 4 commands in your terminal, in real time.
LEFT <-- RIGHT --> SELECT [OK] IDLE ...
NeuralSim is a small, readable teaching/prototyping library. It loads recorded brain signals with MNE-Python, streams them as if they were arriving live from a headset, and classifies each window with a transparent NumPy decoder.
What it actually does
- Loads the PhysioNet EEG Motor Movement/Imagery dataset via
mne.datasets.eegbci(downloads on first use, then caches). - Replays recorded trials through a real-time streamer (
BCIStream) that paces output to mimic live acquisition. - Decodes each trial into one of four commands:
LEFT,RIGHT,SELECT,IDLE. - Demo: a terminal app shows each incoming signal window, the true label, the decoded command, a confidence bar, and a running accuracy.
Honest caveats (read these)
- This is a simulator and learning tool, not a production BCI. It replays recorded data; it does not read a live brain.
- The default decoder is a deliberately simple NumPy band-power nearest-centroid classifier. On real EEG it lands roughly in the 50-70% range for 4 classes (chance is 25%). That is normal for a lightweight motor-imagery decoder and far below clinical systems.
- For meaningfully better accuracy, install the
sklearnextra and switch toCSPDecoder(Common Spatial Patterns + LDA), the standard baseline for this dataset. - The
SELECTcommand is mapped from "imagine both fists" trials (runs 6/10/14). It is the weakest-separated class.
Install
pip install -e . # core: MNE + NumPy
pip install -e ".[sklearn]" # + scikit-learn for the CSP+LDA decoder
Python 3.9+.
Quickstart
Run the live demo. First run downloads ~50 MB from PhysioNet:
neuralsim-demo --subject 1 --speed 8
No network or just want to see it run instantly? Use the synthetic stand-in:
neuralsim-demo --synthetic --speed 8
Use the stronger decoder (needs the sklearn extra):
neuralsim-demo --subject 1 --csp
CLI flags: --subject (1-109), --synthetic, --speed (1 = real time), --train-frac, --csp, --seed.
Sample output
NeuralSim :: PhysioNet EEG motor-imagery -> simulated BCI
120 trials | 64 ch @ 160 Hz | 480 samples/trial | LEFT=30, RIGHT=30, SELECT=30, IDLE=30
Decoder: NumPy band-power nearest-centroid | trained on 84 trials, streaming 36 live
----------------------------------------------------------------
t= 1 | signal in [64ch x 480] | true LEFT -> pred <-- LEFT OK conf #########--- 74% | acc 100%
t= 2 | signal in [64ch x 480] | true RIGHT -> pred ... IDLE XX conf ######------ 52% | acc 50%
...
Use it as a library
from neuralsim import load_eegbci, make_synthetic, BandPowerDecoder, BCIStream
# Real data (downloads on first call). Or: ds = make_synthetic()
ds = load_eegbci(subject=1)
print(ds.summary())
# Train a decoder
dec = BandPowerDecoder(ch_indices=ds.motor_indices, sfreq=ds.sfreq)
dec.fit(ds.signals, ds.commands)
# Stream trials in "real time" and classify them
for idx, signal, true_cmd in BCIStream(ds.signals, ds.commands, ds.sfreq, speed=8):
pred, confidence, scores = dec.predict_one(signal)
print(true_cmd, "->", pred, f"({confidence:.0%})")
Command mapping
PhysioNet annotations (T0/T1/T2) mean different things per run. NeuralSim maps them like this:
| Command | Source runs | Annotation | Meaning |
|---|---|---|---|
LEFT |
4, 8, 12 | T1 | Imagine left fist |
RIGHT |
4, 8, 12 | T2 | Imagine right fist |
SELECT |
6, 10, 14 | T1 | Imagine both fists |
IDLE |
4, 8, 12 | T0 | Rest |
How it works
PhysioNet EDF -> MNE load + standardize + 7-30 Hz filter -> epoch into trials
| |
| relabel to commands
v v
BCIStream (paced replay) ----per trial----> BandPowerDecoder / CSPDecoder
|
LEFT / RIGHT / SELECT / IDLE
- Features (default): log power in the mu (8-12 Hz) and beta (13-30 Hz) bands over motor-cortex channels (C3/Cz/C4 and neighbours), via FFT. Pure NumPy.
- Classifier (default): z-score features, then nearest class centroid; softmax over negative distance gives a confidence.
- Classifier (optional):
CSPDecoder= MNECSP+ scikit-learnLDA.
Package layout
neuralsim/
├── neuralsim/
│ ├── __init__.py public API
│ ├── commands.py Command enum + label mapping
│ ├── data.py PhysioNet loader (MNE) + synthetic generator
│ ├── decoder.py band-power decoder (NumPy) + CSP decoder (optional)
│ ├── stream.py real-time replay
│ └── demo.py terminal demo + CLI
├── tests/test_smoke.py
├── setup.py
├── pyproject.toml
├── requirements.txt
└── README.md
Run tests with pip install -e ".[dev]" && pytest.
Dependencies
- MNE-Python (EEG loading and processing)
- NumPy
- scikit-learn (optional, only for
CSPDecoder)
License
MIT. The PhysioNet EEGBCI dataset has its own terms; see the PhysioNet EEG Motor Movement/Imagery Dataset.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file neuralsim-0.3.0.tar.gz.
File metadata
- Download URL: neuralsim-0.3.0.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
562ce5ab6e3418c00a6d93fe2f03d1de5a635af169e890d84ef071a0179ec233
|
|
| MD5 |
ecd8ead92f691d28a57e4f3b7a4755ac
|
|
| BLAKE2b-256 |
f9d4558b0a7809d88a64ab845c0b66a203b036d3809cf2a97e142fdfd7178273
|
File details
Details for the file neuralsim-0.3.0-py3-none-any.whl.
File metadata
- Download URL: neuralsim-0.3.0-py3-none-any.whl
- Upload date:
- Size: 20.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5861f83294189f181cbf2e79afecaac731c7691de9f49bd4e8e93f8263dc0d63
|
|
| MD5 |
760b30ca8a9f4df513f945410d321191
|
|
| BLAKE2b-256 |
4927cf1d994fc3ec814a6b82ece02d728d5a0ed4d3919f241a59cb03ae722d6e
|