cortipy is the pure-Python implementation of the EEG Analysis Tool that used to live
inside MATLAB. It bundles the measurement pipeline, acquisition modules, device
adapters, evaluators, and a Streamlit UI so the stack can be installed as a standard
Python package.
cortipy/
├── core/ # MeasurementPipeline, ModuleContext, params helpers
├── devices/ # UNICORN, ActiCHamp (Win), LSL, offline + dummy adapters
├── modules/ # Alpha, VEP, SSVEP, BERA, ASSR, P300, BCI acquisition loops
├── evaluation/ # Module-specific analysis and plotting code
├── shared/ # FFT, filters, plotting, report helpers, etc.
└── ui/ # Config loaders, Streamlit UI, session runner, save helpers
- CortiPy is for research and educational use only; it is not a medical device and must not be used for diagnosis or patient care.
- Follow institutional approvals and local regulations before any clinical evaluation; validate device interoperability and trigger/latency behavior in your lab.
- Do not store or share identifiable participant data in repositories or issue trackers. Anonymize runs and keep PHI on secured systems; use synthetic/anonymized data for examples.
- Questions or incident reports: joh1391@thi.de, Rahul.Mondal@thi.de, Laurens.Kreilinger@thi.de.
| Platform | pip | conda | Notes |
|---|---|---|---|
| Windows 10/11 | ✅ pip install -e .[ui,bids,sbids] |
✅ conda env create -f environment.yml |
ActiCHamp binaries supported only on Windows; Streamlit UI works. |
| macOS (Apple/Intel) | ✅ | ✅ | UNICORN supported; ActiCHamp not supported (Windows-only SDK). |
| Linux (Ubuntu 22.04+) | ✅ | ✅ | UNICORN supported; ActiCHamp not supported (Windows-only SDK). |
| Device | Windows | macOS | Linux | Notes |
|---|---|---|---|---|
| UNICORN | ✅ | ✅ | ✅ | Uses virtual COM/Bluetooth serial; verify port name (e.g., COM7, /dev/tty.Unicorn-DevB). |
| ActiCHamp | ✅ | ❌ | ❌ | Windows-only due to vendor SDK binaries shipped in cortipy/devices/actichamp. |
| LSL streams | ✅ | ✅ | ✅ | Any LabStreamingLayer EEG source. |
| Dummy/Sim | ✅ | ✅ | ✅ | For UI/tests without hardware. |
| Offline replay | ✅ | ✅ | ✅ | Replays .npz/.mat/BIDS data. |
- Issue/PR templates live in
.github/ISSUE_TEMPLATEand.github/pull_request_template.md; please avoid sharing PHI in tickets. - Response target: within 5 business days for new issues and vulnerability reports (use the contacts above).
- For clinical/academic collaborations, reach out via Rahul.Mondal@thi.de or Laurens.Kreilinger@thi.de.
- CI/CD hardening: lint/type/coverage gates, release automation to PyPI.
- Streamlit UX: impedance/latency display, clearer device status, structured logging.
- Docs: quickstart, device setup, BIDS/SBIDS workflows, troubleshooting.
- Data governance: anonymization guidance, SBOM/dependency provenance for clinical reviews.
- Packaging: signed wheels/sdists, unified versioning and changelog.
- Experiment 1 – Streaming & numerical validation (
experiments/experiment1/run_experiment1.py):PYTHONPATH=. python ...with no flags. Checks bitwise identity of BIN exports, runs a synthetic sine pipeline surrogate, and renders CortiPy plots for ABR/ASSR/Oddball/VEP/SSVEP/Sine10Hz to compare against EEGLAB references. Outputs live underexperiments/experiment1/results/(JSON + PNG/PDFs). Hardware/EEGLAB numeric correlations are documented as manual placeholders. - Experiment 2 – File format storage & latency (
experiments/experiment2/run_experiment2.py): measures export size and read/write latency across BIDS/SBIDS containers and formats (parquet/edf/zarr/hdf5) using synthetic 1 h datasets (19/64/256 ch). Default: run all datasets, containers, and formats; results saved toexperiments/experiment2/results/experiment2_results.jsonwith plots. Key flags:--datasetslabels,--containersbids|sbids,--formatsparquet|edf|zarr|hdf5,--runsN,--keep-artifacts,--no-purge,--plot-scope all|synthetic|bin,--plots-only,--results-json PATH. - Experiment 3 – Streaming access benchmark (
experiments/experiment3/run_experiment3.py): times streaming-style reads (open handle, single channel, random windows) for the same synthetic datasets exported to BIDS/SBIDS formats. Default: all datasets, containers, formats; results toexperiments/experiment3/results/experiment3_results.jsonwith plots. Key flags:--datasets,--containers,--formats,--runs,--window-s(window duration),--channel-idx(0-based),--keep-artifacts,--no-purge,--plots-only,--results-json PATH.
- Quickstart, API reference, and workflows will live in a docs site (MkDocs/Sphinx). For now, see the README and in-code docstrings.
- Release notes are maintained in
CHANGELOG.md.
Install in editable mode with optional UI extras:
python -m venv .venv
source .venv/bin/activate # PowerShell: .venv\Scripts\Activate.ps1
pip install --upgrade pip
pip install -e . # core toolkit
pip install -e .[ui] # adds Streamlit dependencies
# Add `[bids]` to enable the BIDS loader/exporter extras (EDF/BDF, Parquet, HDF5, Zarr)
pip install -e .[bids]
pip install -e .[ui,bids] # UI plus BIDS extrasFor conda users, an environment spec is provided. It pins the same runtime
dependencies and installs cortipy from the local checkout via pip:
conda env create -f environment.yml
conda activate cortipyfrom cortipy import MeasurementPipeline
from cortipy.core.pipeline import PipelineHooks
params = {
"Method": "Alpha",
"Device": "ActiCHamp",
"Parameters": {
"fs": 250,
"RecordingTime": 60,
"NumberEEGChannels": 8,
"ReferenceChannel": 1,
"TriggerChannel": 9,
"Trigger": "Fixed",
"TriggerTime": 10,
},
"Channels": [{"Position": f"Ch{i+1}"} for i in range(8)],
}
hooks = PipelineHooks(params_provider=lambda prev: params if prev is None else None)
MeasurementPipeline(hooks=hooks).run()cortipy.ui.run_from_configloads JSON/TOML configs (compatible with the legacy MATLABParamsstructure) and executes the pipeline once.cortipy.ui.SessionOptions+SaveManagerreproduce MATLAB’ssaveDatamainbehaviour, including timestamped run folders containingparams.json+data.npz.apps/streamlit_app.pyprovides a Streamlit interface for configuring params, naming electrodes, selecting devices, and launching/monitoring measurements with live previews. Saved runs appear in the sidebar so you can browse and reload them.
pip install -e .[ui] # once per environment
streamlit run apps/streamlit_app.pyOpen http://localhost:8501 (default Streamlit port) and configure a run:
- Pick a method and device, fill in participant metadata, and assign electrodes before starting.
- Set the sidebar “Save directory” (defaults to
./cortipy_runs); each run gets its own timestamped folder. - Use “Simulate run” to exercise the UI without hardware, or “Use imported data” to replay
.npzexports offline. - The “Preview” tab shows the assembled params and lets you download
params.jsonfor later scripting. - Finished runs appear under “Saved sessions” so you can reload params and browse results.
- App logs live in
streamlit_app.lognext to the repo; keep it handy when debugging device connections.
- UNICORN: Provide the virtual COM port (for example
"COM7"on Windows or"/dev/tty.Unicorn-DevB"on macOS) viaParams["Parameters"]["UNICORNPort"](aliasesUNICORNAddress/UnicornPortare accepted). Optional extras:UNICORNDeviceNamefor logging andUnicornTimeout(seconds). The adapter returns 16-column packets[EEG(8), accel(3), gyro(3), battery, counter]. - ActiCHamp: Windows-only because the vendor SDK uses Win32 shared memory and DLLs.
Binaries ship in
cortipy/devices/actichamp; override withParams["ActiChampPath"]if needed. Supplyfs,NumberEEGChannels, and optionalNumberAUXChannels; triggers follow EEG/AUX data. - LSL / Dummy / Offline: Use
Device="LSL"for any LabStreamingLayer EEG stream,"Dummy"(or"Sim") for synthetic data, or"Offline"to replay.npz/.matfiles. All are selectable from the Streamlit UI for testing without hardware.
cortipy.shared.BIDSLoadercan read/write BIDS datasets. Supported inputs include EDF/BDF, BrainVision (.vhdr/.eeg), EEGLAB (.set), FIF, Parquet, HDF5, and Zarr.cortipy.shared.ExperimentBinLoaderreads/writes the.bin+params.jsonpairs used inexperiments/datasets/D2_software_curated_signalsandexperiments/datasets/D4_sereega_evoked_potentials, returning aBIDSLoadResultso you can analyse or re-export them.- Extra dependencies for non-default formats:
pyedflib(EDF/BDF export),pyarroworfastparquet(Parquet),h5py(HDF5),zarr(Zarr),pybv(BrainVision export), andeeglabio(EEGLAB export). - Install them via
pip install -e .[bids](or combine with[ui]) to enable all BIDS I/O features.
from cortipy.shared import BIDSLoader, ExperimentBinLoader
bin_loader = ExperimentBinLoader("experiments/datasets/D4_sereega_evoked_potentials")
result = bin_loader.read_bin("Oddball") # loads params.json + Oddball_scalpdata.bin
# Convert to BIDS
BIDSLoader("exports/oddball_bids").to_bids(result.raw, subject="01", task="oddball", overwrite=True)
# Convert any Raw/numpy data back into the bin layout
bin_loader.write_bin(result.raw, "exports/oddball_bin", params=result.metadata["params"], overwrite=True)The tests/regression fixtures mirror deterministic MATLAB exports. Run pytest for
Python-only checks or tests/run_parity_tests.m inside MATLAB to generate fresh dummy
data and compare the legacy stack vs. the Python port. Continuous integration should
exercise at least the regression scripts before cutting releases.