nimbus-bci
Nimbus Personalizer — Bayesian personalization head for frozen neural EEG embeddings.
Plug any frozen trunk that emits encode(X) → Z, adapt online with a Nimbus head, ship apps on BrainState — without owning or retraining the encoder.
0.6 product shape: the Personalizer surface — cheap online adaptation (~8–10× cheaper than batch refit, ~22–131× cheaper than trunk retraining at matched n), portable profiles, and paradigm recipes (MI · P300 · Riemannian).
Also ships sklearn-compatible heads for classical feature pipelines (CSP, Riemann, …): Bayesian LDA / QDA / Softmax, plus NimbusSTS (EKF latent state + point-estimated emissions). Those heads power Personalizer and can be used alone.
Docs · Personalizer · API reference · PyPI · Contact
Install
pip install nimbus-bci
# optional: pip install nimbus-bci[softmax] # JAX Softmax head
# optional: pip install nimbus-bci[riemann] # pyRiemann pipelines
# optional: pip install nimbus-bci[mne] # MNE helpers
# optional: pip install nimbus-bci[train] # torch trunk-arm trainers (LoRA / FT)
# optional: pip install nimbus-bci[viz] # matplotlib plotting helpers
# optional: pip install nimbus-bci[all] # everything above
From source: pip install -e ".[all]" after cloning.
Upgrading from 0.5? See Migration notes in CHANGELOG.md (ships in the
sdist; also linked from docs.nimbusbci.com).
5-minute quickstart
Run the example (no external data needed):
python examples/quickstart.py
Or follow along:
import numpy as np
from nimbus_bci import Personalizer, wrap
# 1. Wrap any frozen trunk (EEGNet, REVE, ...) — here a random projection.
rng = np.random.default_rng(42)
proj = rng.standard_normal((6, 16))
enc = wrap(lambda X: X @ proj, model_id="toy", embedding_dim=16)
# 2. Fit a Bayesian head on ~30 calibration trials.
# for_deployment = strict gating + LDA + minimal params (the common case).
# For research/experimentation: Personalizer.for_research(enc, classes, ...).
# For classical features (no encoder): Personalizer.for_features(classes).
# To PIN the accept rate for your trunk (default-gate accept rates span
# 7-78% across trunks), fit + calibrate the gate in one call:
# adapter.fit_calibrated(X_cal, y_cal, X_val, y_val, target_accept=0.7)
adapter = Personalizer.for_deployment(enc, ["left_hand", "right_hand"],
paradigm="motor_imagery")
adapter.fit(X_cal, y_cal)
# 3. Predict → BrainState with trial rejection.
states = adapter.predict(X_test) # list[BrainState]
accepted = [s for s in states if not s.rejected] # confident trials
# s.intent, s.confidence, s.uncertainty, s.rejected, s.rejection_reason
# 4. Adapt online (exact conjugate update — no retraining).
adapter.partial_fit(X_new, y_new)
# 5. Save / load.
adapter.save("profile"); loaded = Personalizer.load("profile", encoder=enc)
The three regimes
# A. Classical features (CSP log-variance, tangent space, hand-crafted) —
# no encoder, features go straight to the Bayesian head.
p = Personalizer.for_features(["left", "right"]).fit(X_csp, y)
# B. Frozen deep trunk (EEGNet, foundation model) — embeddings → head,
# strict trial gating out of the box.
p = Personalizer.for_deployment(enc, ["left", "right"]).fit(X_cal, y_cal)
states = p.predict(X_test) # BrainState per trial, rejected flagged
# C. Riemannian geometry & P300 (OAS / xDAWN tangent space) —
# weak-trunk / raw epochs; for_riemann defaults to label-free geodesic
# tracking (tracking_alpha=0.05). Opt out with tracking_alpha=0.0.
p = Personalizer.for_riemann(["left", "right"]).fit(X_cal, y_cal)
# Or for P300 spellers (tracking opt-in; recommend α=0.05 when enabling):
# Personalizer.for_p300(["NonTarget", "Target"], tracking_alpha=0.05)
p.adapt(epoch) # label-free reference update (0 labels needed!)
# D. Streaming adaptation loop — predict, optionally partial_fit on new
# labels; the conjugate head update is exact and cheap (no retraining).
# Reference: examples/middleware_streaming_adaptation.py
for trial in stream:
state = p.predict(trial) # BrainState
if label_available(state):
p.partial_fit(trial, label) # ~1/30-1/131 the wall cost of retraining
Regime A/B/C are the shipped surface. A governed session runtime (drift gates, attribution, label budgets, quarantine) with subconscious error-potential self-supervision is in research and will ship separately.
The full parameter surface (user=, preset=, head choice) via direct
construction — anything that maps inputs to embeddings (n, d) plugs in;
Nimbus does not own DL architectures:
adapter = Personalizer(
encoder=enc, head="lda", user="subject_001",
classes=["left", "right"], preset="strict",
)
Full walkthrough with copy-paste synthetic data: Quickstart.
Optional shortcuts for common external trunks: wrap_eegnet, and
from nimbus_bci.middleware.adapters import wrap_braindecode
(see encoder contract).
Examples in this repo: middleware_personalizer.py, middleware_streaming_adaptation.py, middleware_geometry_gateway.py, middleware_mi_session.py, middleware_braindecode.py, middleware_reve.py, middleware_recommend_adapt.py.
Bench EEGNet demo (repo-only, needs nimbusbench[dl]): nimbusbench/scripts/middleware_eegnet.py.
When to adapt (thin helper)
Optional mean-shift check before spending labels on partial_fit. You choose the threshold tau.
dec = adapter.recommend_adapt(X_stream, tau=your_tau) # stay vs stream update
if dec.should_adapt:
adapter.partial_fit(X_lab, y_lab)
Trial rejection (BrainState.rejected / need_more_data) is a different gate — accept/reject the intent for the app.
Details: BrainState · recipe: examples/middleware_recommend_adapt.py.
A governed adaptation session — drift gates, label budgets, quarantine, and rollback — is under research and will ship as a separate release once its evidence matures.
Classical heads (CSP / features)
Same Bayesian heads without an encoder — inputs are already features:
from nimbus_bci import NimbusLDA
clf = NimbusLDA()
clf.fit(X_train, y_train)
proba = clf.predict_proba(X_test)
clf.partial_fit(X_new, y_new)
Also: streaming (StreamingSession), active learning (CalibrationSession), MNE helpers, optional Riemann pipelines. See docs.nimbusbci.com and examples/e2e_mne_csp_nimbus.py.
| Head | Role |
|---|---|
NimbusLDA / NimbusQDA |
Conjugate Bayesian LDA/QDA |
NimbusSoftmax |
Polya–Gamma VI (optional JAX) |
NimbusSTS |
EKF latent-state / drift (EKF on z; point W/H/b) |
Evidence
Public Personalizer story (heads, cost vs fine-tune, multi-trunk / REVE):
Evidence · Overview.
License
Two-track proprietary license — see the LICENSE.txt shipped with the package
(and on PyPI). Non-commercial use is
free under the Non-Commercial terms; commercial use requires a paid license.
Contact: hello@nimbusbci.com.
Contributing & security
Licensees with source access: follow the repository CONTRIBUTING.md and
SECURITY.md. Report vulnerabilities privately to
hello@nimbusbci.com — do not open a public issue.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 nimbus_bci-0.6.0.tar.gz.
File metadata
- Download URL: nimbus_bci-0.6.0.tar.gz
- Upload date:
- Size: 1.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98a6e6dad8d660ef59199f444691f9c8fd08f58f7cb679ae6cc40be7216a278f
|
|
| MD5 |
606d944ba199ee332bc8b8ac154399c8
|
|
| BLAKE2b-256 |
106768667ce29fb6ed5fa53210af090dd4e2496d0b70235a8c38de877e2be3fe
|
File details
Details for the file nimbus_bci-0.6.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 820.8 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91700f13d8dc68ff52959c23d4e9b65ac6c0f1349150972d99075d198e9316ba
|
|
| MD5 |
33b20788702b94ef37ad0ed740108de2
|
|
| BLAKE2b-256 |
9129cd7280d326402741f1bae55c85e9ded8d2196300d38c3267875aacc27e15
|
File details
Details for the file nimbus_bci-0.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af6c7fed2f8e6d464ce1c7e4686772a0b3e73c6f26d5f9dd88e9b53dde49012f
|
|
| MD5 |
b2f2ef5dbc708fd22754befcc63cc876
|
|
| BLAKE2b-256 |
3e0b89a86167b227b2ae0cad9dcacb9c7e09762cad6cdc926ed7b130e7823abd
|
File details
Details for the file nimbus_bci-0.6.0-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 897.3 kB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28e8bc7a264832cfc94116e84eb990bf0a4890c37f73fbd2067897a12c89ad86
|
|
| MD5 |
268b992f5e038790a06b2572afdbab4a
|
|
| BLAKE2b-256 |
265eb0093eaabcf51463fc261a762bc1565f71fb1c13d878bb8794c80326914b
|
File details
Details for the file nimbus_bci-0.6.0-cp313-cp313-macosx_10_13_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp313-cp313-macosx_10_13_x86_64.whl
- Upload date:
- Size: 905.9 kB
- Tags: CPython 3.13, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84a866789e81dd9e7b6c499c5be4837bc5cea8ef812355c5b2ad2b5f8cc5d1e9
|
|
| MD5 |
5071c0b6702a5cc89898386e0135a310
|
|
| BLAKE2b-256 |
4f43fb98c285dc05699a0381b82506bba29c51f235279fc488bc19d24bedcdc5
|
File details
Details for the file nimbus_bci-0.6.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 824.8 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13c8af32b3b4d8b854c5b66d86720c4cb33a03ae1ca967df6c3997d1b95fcd73
|
|
| MD5 |
ce90566b9f349c020e7a97870cd7fd60
|
|
| BLAKE2b-256 |
2f15ae28542520f8c03a8e15195777f0d0c82faebe134d1e55c812959db862c1
|
File details
Details for the file nimbus_bci-0.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
60f4380b43954ebfa336caa5a1af60f89e9d2762c0566af4b53537c3761f334c
|
|
| MD5 |
af771c6faac9d0f51e6110e762d8c50a
|
|
| BLAKE2b-256 |
8571d44e70622a210e09ec72ff4b6e0b117e16f008bec1e8ae560d8c158976d5
|
File details
Details for the file nimbus_bci-0.6.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 901.9 kB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0fa15fdb6a926b6e3e4b45fb35f08a2ca9b370f469d4f04ed7583c56df310d9
|
|
| MD5 |
2c3bb91ac7b957efe8b372b1481e4eb1
|
|
| BLAKE2b-256 |
0002a6f9090934f4f5b5b8a6b7c8bce44e4ae908fe8485791de2eb6552431aee
|
File details
Details for the file nimbus_bci-0.6.0-cp312-cp312-macosx_10_13_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp312-cp312-macosx_10_13_x86_64.whl
- Upload date:
- Size: 909.1 kB
- Tags: CPython 3.12, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b96b4961e782c7124c09feb563c742fe5560bca5f673cfbbb938dba36c911b0
|
|
| MD5 |
5e4ba4e8ff35bcf66e0a14d1c5bc1bc5
|
|
| BLAKE2b-256 |
df39b9cd2b0955ce76bacf41f633cf88e1a16bfb313c29cbe028cd9ab2c800fe
|
File details
Details for the file nimbus_bci-0.6.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 845.1 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81ccb434a54225c67dde8a08fac1200abeec33c52f5da37c8598e2b44e92c40c
|
|
| MD5 |
fbd7f593312ea9d0c6c3592ad3dbc189
|
|
| BLAKE2b-256 |
b01cfd17c940f8aedad71e3a43adde9951c510d56b92b51b83b3757770e869ca
|
File details
Details for the file nimbus_bci-0.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b77c4d20d1513d477b784aec82f1603c3171b6d541c9c4d32c7e74a4a84994f
|
|
| MD5 |
45c123e43332d81ba4b3d181425e2575
|
|
| BLAKE2b-256 |
1ffea5ac7262d1173923823032f59395eb85cf52db395502e47267c4c1c3f78c
|
File details
Details for the file nimbus_bci-0.6.0-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 901.2 kB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
272f8f424d06bf5fb15fa2ff94da880411add6d4c60e5f33dc4c7aedfc3aebad
|
|
| MD5 |
a9c0636dac5afaa1ae7aae0cdaf6920e
|
|
| BLAKE2b-256 |
60c87ce8460c564a67157a192c10caabb3bfc0bafe0039016a7f198ddbedecd1
|
File details
Details for the file nimbus_bci-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl.
File metadata
- Download URL: nimbus_bci-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl
- Upload date:
- Size: 927.6 kB
- Tags: CPython 3.11, macOS 10.9+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0192a5f61643fefa1b7580a79c7b7e1033d07a94901f16db9b7acd06f5bf5ee2
|
|
| MD5 |
e50a83e7c292f893a58ac505e5c7c167
|
|
| BLAKE2b-256 |
26110145939a33505de7fb255857c7d465fd5bbb78269cc828a1bea5359c067f
|