Metadata-Version: 2.4
Name: nimbus-bci
Version: 0.4.2
Summary: Nimbus BCI: Bayesian classifiers for brain-computer interfaces
Author-email: "Nimbus BCI Inc." <hello@nimbusbci.com>
License: NIMBUS BCI PYTHON SDK — SOFTWARE LICENSE AGREEMENT
        
        Copyright (c) 2024–2026 Nimbus BCI Inc. All rights reserved.
        
        ================================================================================
        1. OVERVIEW
        ================================================================================
        
        This Software License Agreement ("Agreement") governs use of the Nimbus BCI
        Python SDK, including source code, compiled extensions, documentation, and
        benchmark tooling (collectively, the "Software").
        
        The Software is **proprietary**. Nimbus BCI Inc. ("Nimbus BCI") retains all
        rights not expressly granted herein. Nothing in this Agreement transfers any
        ownership of intellectual property to you.
        
        This Agreement grants rights under **two tracks** that operate in parallel:
        
          - **Section 3 — Non-Commercial License (No-Cost, Self-Executing).**
            Available to anyone meeting the eligibility criteria, with no
            registration, email, or license key required. Use, modification, and
            non-commercial distribution are permitted for Non-Commercial Use.
            Attribution is requested as a community norm (see Section 4) but is
            not a condition of this license.
        
          - **Section 5 — Commercial Licenses (Paid).**
            Required for any use that is not a Non-Commercial Use. Contact
            hello@nimbusbci.com to obtain a commercial license appropriate to your
            use case.
        
        If you do not qualify under Section 3 and have not executed a separate
        written commercial license with Nimbus BCI under Section 5, you have no
        right to use the Software.
        
        ================================================================================
        2. DEFINITIONS
        ================================================================================
        
          - **"Non-Commercial Use"** means use of the Software solely for:
              (a) research, scholarship, or teaching conducted at, or under the
                  auspices of, an accredited academic institution, government
                  research laboratory, or recognized non-profit research
                  organization; OR
              (b) personal learning, hobby, or scientific curiosity, where the
                  Software is not used, directly or indirectly, in or for the
                  benefit of a commercial product, service, or business activity.
        
            "Non-Commercial Use" does **not** include any activity that is funded
            by, performed under contract for, or intended to produce revenue for a
            commercial entity, including sponsored research with for-profit
            sponsors, internal R&D inside a for-profit company, or product
            development of any kind.
        
          - **"Commercial Use"** means any use of the Software that is not a
            Non-Commercial Use, including without limitation: use inside a
            for-profit company; use in a paid product, service, or SaaS offering;
            internal business operations; sponsored or fee-for-service research;
            consulting; and inclusion in or bundling with a commercial product.
        
          - **"Academic Publication"** means a peer-reviewed paper, preprint
            (e.g., arXiv, bioRxiv), conference proceedings article, thesis, or
            similar scholarly work made publicly available.
        
          - **"Attribution"** means citing the Software in accordance with
            Section 4.
        
        ================================================================================
        3. NON-COMMERCIAL LICENSE (NO-COST, SELF-EXECUTING)
        ================================================================================
        
        Subject to the terms of this Agreement, Nimbus BCI grants you a
        worldwide, no-cost, non-exclusive, non-transferable, revocable license
        to:
        
          (a) install, copy, run, and modify the Software, and to make
              derivative works of it, for Non-Commercial Use;
        
          (b) reproduce, distribute, and publicly post the Software, in whole
              or in part, and your derivative works, **solely for Non-Commercial
              Use and solely at no charge**, provided that each copy or
              substantial portion of the Software:
                (i)   retains this LICENSE.txt file unchanged;
                (ii)  includes all copyright, patent, trademark, and
                      attribution notices present in the Software; and
                (iii) if it is a derivative work, prominently states that it is
                      a derivative of the Nimbus BCI Python SDK and links to
                      https://nimbusbci.com.
        
          Nothing in this Section 3 authorizes distribution for a fee, or any
          use or distribution that is a Commercial Use.
        
        This license is **self-executing**: no email, registration, license key,
        or proof of affiliation is required to exercise it. Attribution in the
        form of a citation is requested in Section 4 as a community norm, not a
        legal condition.
        
          Non-commercial patent grant. To the extent that any Nimbus BCI-owned
          patent claims are necessarily infringed by making, using, modifying,
          or distributing the Software as permitted under this Section 3 solely
          for Non-Commercial Use, Nimbus BCI grants you a non-exclusive,
          worldwide, royalty-free, non-transferable, non-sublicensable patent
          license to do so. This patent license does not cover (i) any
          modification of the Software that is not permitted under this Section
          3, (ii) any use that is a Commercial Use, or (iii) any combination of
          the Software with other software or hardware where the combination
          itself necessarily infringes a Nimbus BCI patent claim that the
          Software alone would not. If you institute patent litigation against
          Nimbus BCI (or a cross-claim or counterclaim in a lawsuit) alleging
          that the Software, a Nimbus BCI patent, or both directly or
          indirectly infringes any patent, then any patent licenses granted to
          you under this Section 3 for the Software terminate automatically as
          of the date the litigation is filed.
        
        ================================================================================
        4. ATTRIBUTION AND CITATION (COMMUNITY NORM, NOT A LICENSE CONDITION)
        ================================================================================
        
        Attribution is **not** a contractual condition of the Non-Commercial
        License in Section 3. You do not lose your license by omitting a
        citation. However, Nimbus BCI is a small team and the SDK is provided
        at no cost for non-commercial use; **citation is how that work is
        recognized and is therefore strongly requested**, as follows:
        
          (a) **Citation in Academic Publications.** If you write an Academic
              Publication that uses the Software, reports results produced with
              the Software, or is based on methods implemented in the Software,
              please cite it. Use the canonical citation in `CITATION.cff` at
              the root of this repository (or, if no `CITATION.cff` is present,
              cite the Software as: "Nimbus BCI Python SDK, Nimbus BCI Inc.,
              https://nimbusbci.com, version <version you used>").
        
          (b) **Notice in derivative artifacts.** If you publicly distribute a
              derivative work (e.g., a fork, a notebook collection, a dataset
              produced with the Software), please prominently state "Built with
              the Nimbus BCI Python SDK" and link to https://nimbusbci.com.
              (This is required for distributions under Section 3(b)(ii) above;
              it is requested, not required, for distributions you make under a
              separate written commercial license.)
        
          (c) **Retention of notices.** You must retain all copyright, patent,
              trademark, and attribution notices present in the Software. This
              is a condition of the license (Section 3(b)(ii)) and survives
              independent of this Section 4.
        
        ================================================================================
        5. COMMERCIAL LICENSES (PAID, SEPARATE AGREEMENT)
        ================================================================================
        
        Any Commercial Use of the Software requires a separate written commercial
        license agreement with Nimbus BCI. The commercial tiers below describe
        typical offerings; exact terms, fees, and scope are set in the applicable
        commercial agreement you sign.
        
          TIER              TYPICAL USE CASE
          --------------------------------------------------------------------------
          Startup           Companies with less than US $1M annual revenue;
                            single product; standard email support.
          Commercial        Full production rights for commercial applications;
                            unlimited products within the licensed organization;
                            priority technical support.
          Enterprise        Unlimited deployments across the organization; SLA
                            guarantees; on-premise options; custom feature
                            development; training and onboarding.
          OEM / Embedded    Medical devices and embedded systems; FDA regulatory
                            documentation package; white-label and redistribution
                            rights; extended warranty; design review support.
        
        To obtain a commercial license: hello@nimbusbci.com or
        https://nimbusbci.com/dashboard.
        
        ================================================================================
        6. THINGS YOU MAY NOT DO
        ================================================================================
        
        You may NOT:
        
          1. Use the Software for any Commercial Use without an active
             commercial license agreement under Section 5.
        
          2. Sublicense, rent, lease, sell, resell, or otherwise distribute the
             Software for a fee, in whole or in part. (Distributing the Software
             or your derivative works at no charge for Non-Commercial Use is
             permitted under Section 3; everything else requires a commercial
             license.)
        
          3. Remove, alter, or obscure any copyright, patent, trademark, or
             attribution notices on or in the Software.
        
          4. Institute patent litigation against Nimbus BCI alleging that the
             Software or a Nimbus BCI patent infringes any patent (doing so
             automatically terminates the patent license granted in Section 3,
             as described there).
        
          5. Use the Software in any manner that violates applicable laws or
             regulations, including applicable export-control laws.
        
          6. Use the Software for any life-critical, safety-critical, or
             medical-diagnostic purpose without appropriate regulatory
             clearances and a valid OEM/Embedded License.
        
          7. Share, publish, or expose any API keys, license keys, or
             authentication credentials issued by Nimbus BCI.
        
        ================================================================================
        7. INTELLECTUAL PROPERTY
        ================================================================================
        
        The Software, including all algorithms, methods, designs, and
        implementations, is and remains the exclusive property of Nimbus BCI Inc.
        This Agreement does not transfer any ownership rights to you.
        
        The Software contains proprietary Bayesian inference algorithms
        including, but not limited to:
          - Bayesian Linear Discriminant Analysis (LDA) with conjugate
            Normal-Inverse-Wishart priors and multivariate Student's-t posterior
            predictive;
          - Bayesian Quadratic Discriminant Analysis (QDA);
          - Polya-Gamma Variational Inference for Bayesian Softmax regression;
          - Structural Time Series (STS) classification via Extended Kalman
            Filter with persistent latent state;
          - Bayesian Active Learning by Disagreement (BALD) on the conjugate and
            variational posteriors;
          - Real-time streaming inference, online `partial_fit` updates, and
            label-free calibration-stopping methods.
        
        These algorithms constitute valuable trade secrets and copyrighted works
        of Nimbus BCI Inc.
        
        ================================================================================
        8. CONFIDENTIALITY
        ================================================================================
        
        To the extent the Software is distributed in source form (e.g., for
        reproducibility or internal use), you acknowledge that the source code
        contains confidential and proprietary information. You agree to:
        
          1. Maintain the confidentiality of any non-public source code to the
             extent permitted under Section 3;
          2. Use at least the same degree of care to protect the Software as you
             use to protect your own confidential information;
          3. Not publicly disclose source code in a manner inconsistent with
             Section 3.
        
        For the avoidance of doubt: public posting, reproduction, or
        distribution of the Software (verbatim or as modified) that is
        expressly authorized under Section 3 is **not** a breach of this
        Section 8. The Software's source-available distribution model is a
        feature, not a bug — Section 8 protects genuinely non-public materials
        (e.g., unreleased source shared under NDA), not the Software itself.
        
        ================================================================================
        9. DATA PRIVACY
        ================================================================================
        
        The Software processes EEG and neurophysiological data locally on your
        systems. Nimbus BCI does not collect, store, or have access to your
        research data or subject data.
        
        The Software may transmit to Nimbus BCI servers (only when a license
        key is configured): license key validation requests, aggregated usage
        metrics (e.g., inference counts), and software version/platform
        information for compatibility checks.
        
        ================================================================================
        10. WARRANTY DISCLAIMER
        ================================================================================
        
        THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS
        OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
        
        NIMBUS BCI DOES NOT WARRANT THAT:
          - The Software will meet your specific requirements;
          - The Software will be uninterrupted, timely, secure, or error-free;
          - Any results obtained from the Software will be accurate or reliable;
          - Any errors in the Software will be corrected.
        
        ================================================================================
        11. MEDICAL DEVICE DISCLAIMER
        ================================================================================
        
        IMPORTANT: THE SOFTWARE IS NOT A MEDICAL DEVICE.
        
        The Software has NOT been cleared or approved by the U.S. Food and Drug
        Administration (FDA), the European Medicines Agency (EMA), or any other
        regulatory body for use as a medical device.
        
        The Software is intended for RESEARCH AND DEVELOPMENT PURPOSES ONLY and
        must NOT be used for:
          - Clinical diagnosis or treatment of patients;
          - Medical decision-making or patient care;
          - Any application where failure could result in death or personal
            injury.
        
        Use of the Software for medical or clinical purposes requires
        appropriate regulatory clearances (510(k), CE Mark, etc.), a valid
        OEM/Embedded License with regulatory support, and independent
        validation and verification.
        
        ================================================================================
        12. LIMITATION OF LIABILITY
        ================================================================================
        
        TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW:
        
        IN NO EVENT SHALL NIMBUS BCI INC., ITS AFFILIATES, OFFICERS, DIRECTORS,
        EMPLOYEES, OR AGENTS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
        CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING BUT NOT LIMITED TO:
          - Loss of profits, revenue, or business opportunities;
          - Loss of data or research results;
          - Business interruption;
          - Cost of substitute goods or services;
        
        WHETHER ARISING FROM CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY, OR ANY
        OTHER LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
        
        NIMBUS BCI'S TOTAL AGGREGATE LIABILITY SHALL NOT EXCEED:
        
          - **For Non-Commercial Use (Section 3):** One Hundred U.S. Dollars
            (US $100), consistent with the no-cost nature of that grant and
            with the long-standing convention for free-of-charge software.
        
          - **For Commercial Use (Section 5):** The total amount paid by you
            to Nimbus BCI for the Software in the twelve (12) months preceding
            the event giving rise to the claim, or such higher figure as is
            set out in the written commercial agreement executed between you
            and Nimbus BCI. If your commercial agreement specifies a different
            cap, that cap controls and supersedes this Section.
        
        The foregoing caps apply even if a remedy fails of its essential
        purpose.
        
        ================================================================================
        13. TERM AND TERMINATION
        ================================================================================
        
        This license is effective until terminated. Nimbus BCI may terminate
        your license under this Agreement (whether the Non-Commercial License in
        Section 3 or a commercial license under Section 5) immediately if you
        breach any material term of this Agreement and, where the breach is
        curable, fail to cure it within thirty (30) days of written notice.
        Termination of the patent license under Section 3 occurs automatically
        upon the events specified in Section 3.
        
        Upon termination:
          1. You must cease all use of the Software;
          2. You must destroy all copies of the Software in your possession or
             control, except that you may retain verbatim copies strictly to
             support the reproducibility of an Academic Publication already
             published, and except for archival copies you are required to keep
             under applicable law; and
          3. You must certify in writing, if requested, that you have complied.
        
        Termination does not affect the rights of any downstream recipient who
        received the Software (or a permitted derivative work) directly from
        you under Section 3 before the termination event, so long as that
        recipient remains in compliance with this Agreement. (This is the
        reciprocal of the "non-exclusive" nature of the grant: your breach ends
        your rights going forward, but does not retroactively unwind
        permissible distributions you already made.)
        
        Sections 7 (Intellectual Property), 8 (Confidentiality), 10 (Warranty
        Disclaimer), 11 (Medical Device Disclaimer), 12 (Limitation of
        Liability), and 14 (Governing Law) survive termination.
        
        ================================================================================
        14. GOVERNING LAW AND JURISDICTION
        ================================================================================
        
        This Agreement is governed by and construed in accordance with the laws
        of the State of Delaware, United States, without regard to its conflict
        of laws principles.
        
        Any disputes arising under this Agreement shall be resolved exclusively
        in the state or federal courts located in Delaware. You consent to the
        personal jurisdiction of such courts.
        
        ================================================================================
        15. EXPORT COMPLIANCE
        ================================================================================
        
        The Software may be subject to U.S. export control laws and regulations.
        You agree to comply with all applicable export laws and not to export or
        re-export the Software to any prohibited countries, entities, or persons.
        
        ================================================================================
        16. ENTIRE AGREEMENT; AMENDMENT; NO RETROACTIVE REDUCTION
        ================================================================================
        
        This Agreement is the entire agreement between you and Nimbus BCI
        regarding the Software and supersedes all prior agreements and
        communications regarding the Software.
        
        Nimbus BCI may amend this Agreement for future releases of the Software.
        The version of the Agreement that ships with the copy of the Software
        you obtained governs your use, unless you obtain a separate written
        commercial license that supersedes it.
        
        **No retroactive reduction.** Nimbus BCI will not, in any future version
        of this Agreement, reduce the Non-Commercial Use rights granted under
        this Section 3 for any copy of the Software that you obtained under
        this version (v2.1). Specifically:
          - The right to install, copy, run, modify, and make derivative works
            of the Software for Non-Commercial Use;
          - The right to reproduce and distribute the Software and your
            non-commercial derivative works at no charge, under the conditions
            of Section 3;
          - The non-commercial patent license described in Section 3;
        
        shall remain available to you for that copy of the Software under the
        terms of this version (v2.1), even if a later version of this
        Agreement is more restrictive. This is a promise to the community on
        which the Software's adoption depends, and it survives any amendment.
        
        Nothing in this Section prevents Nimbus BCI from changing the license
        terms of *future* releases of the Software.
        
        ================================================================================
        17. CONTACT
        ================================================================================
        
        Nimbus BCI Inc.
        588 El Camino Real
        Santa Clara, CA 95050
        United States
        
        Email:          hello@nimbusbci.com
        Website:        https://nimbusbci.com
        Documentation:  https://docs.nimbusbci.com
        
        ================================================================================
        
        By installing, copying, or otherwise using the Software, you acknowledge
        that you have read this Agreement, understand it, and agree to be bound
        by its terms.
        
        ================================================================================
        Last Updated: June 2026
        Version: 2.1
        
        © 2024–2026 Nimbus BCI Inc. All rights reserved.
        
Project-URL: Homepage, https://nimbusbci.com
Project-URL: Documentation, https://docs.nimbusbci.com
Project-URL: Repository, https://github.com/nimbusbci/nimbuspysdk
Project-URL: Issues, https://github.com/nimbusbci/nimbuspysdk/issues
Keywords: bci,eeg,machine-learning,bayesian,classification,sklearn
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: numpy>=1.26
Requires-Dist: scikit-learn>=1.4
Requires-Dist: scipy>=1.17.1
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: python-dateutil>=2.9.0; extra == "dev"
Requires-Dist: Cython>=3.0; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: viz
Requires-Dist: matplotlib>=3.8; extra == "viz"
Provides-Extra: mne
Requires-Dist: mne>=1.6; extra == "mne"
Provides-Extra: softmax
Requires-Dist: jax>=0.4.25; extra == "softmax"
Provides-Extra: all
Requires-Dist: matplotlib>=3.8; extra == "all"
Requires-Dist: mne>=1.6; extra == "all"
Requires-Dist: jax>=0.4.25; extra == "all"
Dynamic: license-file

# nimbus-bci

Bayesian BCI classifiers with **sklearn compatibility**, **streaming inference**, **low-cost online updates** (`partial_fit` vs full refit), **measured** scoring time via `predict_batch` · `latency_ms`, **active-learning calibration loops**, and **rich diagnostics**.

[PyPI](https://pypi.org/project/nimbus-bci/)
[Python](https://pypi.org/project/nimbus-bci/)
[License](LICENSE.txt)

**Documentation in this repo:** [Why Nimbus? (vs sklearn / pyRiemann)](docs/why_nimbus.md) · **[NimbusBench — main conclusions](docs/benchmarks.md#main-conclusions)** · [Latency (NimbusBench + in-SDK scope)](docs/latency_and_performance.md) · [Trust, calibration, and rejection](docs/trust_and_calibration.md) · [Active-learning calibration loops](docs/active_learning.md) · [Notebooks index](notebooks/README.md). Hosted docs: [docs.nimbusbci.com](https://docs.nimbusbci.com).

## Features

- **Four sklearn-compatible classifiers**: three static Bayesian decoders — **LDA**, **QDA**, **Softmax** (Polya–Gamma) — plus **NimbusSTS** for latent-state / non-stationary settings (EKF-style updates, experimental)
- **sklearn-compatible API**: Works with pipelines, cross-validation, and GridSearchCV
- **Streaming inference**: Real-time chunk-by-chunk processing; per-call `predict_batch` → `BatchResult.latency_ms`
- **Online update cost**: Conjugate / variational `partial_fit` on Nimbus heads — measured vs batch refit in NimbusBench ([main conclusions](docs/benchmarks.md#main-conclusions), [latency scope](docs/latency_and_performance.md))
- **Active learning**: `suggest_next_trial` (BALD on LDA/QDA/Softmax), `should_query` streaming gate, and label-free `calibration_sufficient` stopping — cut cued calibration time without manual heuristics
- **Rich diagnostics**: Entropy, Mahalanobis distance, calibration metrics (ECE/MCE)
- **Online learning**: Update models with new data without retraining
- **BCI-specific utilities**: ITR calculation, temporal aggregation, quality assessment
- **MNE-Python integration**: Convert between MNE Epochs and Nimbus data formats

## Installation

```bash
pip install nimbus-bci
```

To use the optional JAX-based softmax model:

```bash
pip install nimbus-bci[softmax]
```

**From source:**

```bash
git clone https://github.com/nimbusbci/nimbuspysdk.git
cd nimbuspysdk
pip install -e ".[all]"
```

## Quick Start

### sklearn-Compatible API (Recommended)

```python
from nimbus_bci import NimbusLDA, NimbusQDA, NimbusSoftmax, NimbusSTS
import numpy as np

# Create and fit classifier
clf = NimbusLDA()
clf.fit(X_train, y_train)

# Predict
predictions = clf.predict(X_test)
probabilities = clf.predict_proba(X_test)

# Online learning
clf.partial_fit(X_new, y_new)
```

### Works with sklearn Pipelines

```python
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score, GridSearchCV

# Simple pipeline
pipe = make_pipeline(StandardScaler(), NimbusLDA())
pipe.fit(X_train, y_train)

# Cross-validation
scores = cross_val_score(NimbusLDA(), X, y, cv=5)
print(f"Accuracy: {scores.mean():.2%} (+/- {scores.std():.2%})")

# Hyperparameter tuning
param_grid = {'mu_scale': [1.0, 3.0, 5.0], 'class_prior_alpha': [0.5, 1.0]}
grid = GridSearchCV(NimbusLDA(), param_grid, cv=5)
grid.fit(X, y)
print(f"Best params: {grid.best_params_}")
```

### Streaming Inference (Real-Time BCI)

```python
from nimbus_bci import NimbusLDA, StreamingSession
from nimbus_bci.data import BCIMetadata

# Setup
metadata = BCIMetadata(
    sampling_rate=250.0,
    paradigm="motor_imagery",
    feature_type="csp",
    n_features=16,
    n_classes=4,
    chunk_size=125,  # 500ms chunks
    temporal_aggregation="logvar",
)

# Train model
clf = NimbusLDA()
clf.fit(X_train, y_train)

# Create streaming session
session = StreamingSession(clf.model_, metadata)

# Process chunks in real-time
for chunk in eeg_stream:
    result = session.process_chunk(chunk)
    print(f"Chunk prediction: {result.prediction} ({result.confidence:.2%})")

# Finalize trial with aggregation
final = session.finalize_trial(method="weighted_vote")
print(f"Final: class {final.prediction} (entropy: {final.entropy:.2f} bits)")
```

For **NimbusSTS** specifically (stateful latent dynamics), use `StreamingSessionSTS`
so the latent state can be propagated and updated with delayed feedback:

```python
from nimbus_bci import NimbusSTS
from nimbus_bci.inference import StreamingSessionSTS
from nimbus_bci.data import BCIMetadata

metadata = BCIMetadata(
    sampling_rate=250.0,
    paradigm="motor_imagery",
    feature_type="csp",
    n_features=16,
    n_classes=2,
    chunk_size=125,
    temporal_aggregation="mean",
)

clf = NimbusSTS().fit(X_train, y_train)
session = StreamingSessionSTS(clf, metadata)

result = session.process_chunk(chunk)  # propagates state by default
session.provide_feedback(label=0)      # when label arrives later
```

### Active Learning (Calibration Loop)

Cut cued-calibration time by labeling only the trials the model is genuinely uncertain about, and stop automatically when the posterior settles:

```python
from nimbus_bci import NimbusLDA
from nimbus_bci.active_learning import (
    suggest_next_trial,
    calibration_sufficient,
)

clf = NimbusLDA().fit(X_seed, y_seed)   # small initial cued batch
prev = clf.get_model()

for _ in range(max_rounds):
    # Rank the unlabeled pool by BALD informativeness, label the top 4.
    ranked = suggest_next_trial(
        clf, X_pool, strategy="bald", n=4, num_posterior_samples=64,
    )
    X_new, y_new = collect_labels_for(ranked.indices)   # cue + record
    clf.partial_fit(X_new, y_new)

    # Label-free stopping: when predict_proba over the pool stops moving,
    # more cues will not change predictions much.
    status = calibration_sufficient(
        clf, X_pool,
        criterion="posterior_stability",
        previous=prev, threshold=0.02,
    )
    if status.is_sufficient:
        break
    prev = clf.get_model()
```

Strategies (`entropy`, `margin`, `least_confidence`, `bald`) and stopping criteria (`posterior_stability`, `expected_info_gain`) are all model-agnostic. STS gets `posterior_stability` for free; BALD-based features on STS are deferred to v1.1. Full recipe in [docs/active_learning.md](docs/active_learning.md).

### Batch Inference with Diagnostics

```python
from nimbus_bci import predict_batch
from nimbus_bci.data import BCIData, BCIMetadata

# Create BCI data container
metadata = BCIMetadata(
    sampling_rate=250.0,
    paradigm="motor_imagery",
    feature_type="csp",
    n_features=16,
    n_classes=4,
)
data = BCIData(features, metadata, labels)

# Run batch inference with full diagnostics
result = predict_batch(model, data)

print(f"Mean entropy: {result.mean_entropy:.2f} bits")
print(f"Balance: {result.balance:.2%}")
if result.calibration is not None:
    print(f"ECE: {result.calibration.ece:.3f}")
print(f"Latency: {result.latency_ms:.1f}ms")
```

`latency_ms` is the SDK’s measured wall time for this `predict_batch` call (not your full acquisition→feature pipeline). Online **update** cost vs batch refit is in NimbusBench ([main conclusions](docs/benchmarks.md#main-conclusions), [Latency & performance](docs/latency_and_performance.md)).

### MNE-Python Integration

```python
import mne
from nimbus_bci import NimbusLDA
from nimbus_bci.compat import from_mne_epochs, extract_csp_features

# Load and preprocess with MNE
raw = mne.io.read_raw_gdf("motor_imagery.gdf")
events = mne.find_events(raw)
epochs = mne.Epochs(raw, events, tmin=0, tmax=4, baseline=None, preload=True)
epochs.filter(8, 30)  # Mu + Beta bands

# Extract CSP features
csp_features, csp = extract_csp_features(epochs, n_components=8)

# Train Nimbus classifier
clf = NimbusLDA()
clf.fit(csp_features, epochs.events[:, 2])
```

## Available Classifiers


| Classifier      | Description                                                            | Best For                                                          |
| --------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `NimbusLDA`     | Bayesian LDA with shared covariance                                    | Fast, when classes have similar shapes                            |
| `NimbusQDA`     | Bayesian QDA with class-specific covariances                           | Complex class distributions                                       |
| `NimbusSoftmax` | Bayesian logistic regression (Polya-Gamma VI)                          | Non-Gaussian decision boundaries                                  |
| `NimbusSTS`     | Structural time series classifier (latent state + EKF-style inference) | Non-stationary settings, drifting class boundaries (experimental) |


## Choosing the Right Classifier

### Quick Decision Guide

**Is your data stationary (distributions don't change over time)?**

- **Yes** → Use static models (LDA/QDA/Softmax)
- **No** → Use `NimbusSTS` for temporal adaptation

**For stationary data:**

- **Classes have similar covariance?** → `NimbusLDA` (fastest)
- **Classes have different shapes?** → `NimbusQDA`
- **Non-Gaussian boundaries?** → `NimbusSoftmax`

**For non-stationary data:**

- **Gradual drift (fatigue, electrode shift)?** → `NimbusSTS`
- **Multi-day sessions with state transfer?** → `NimbusSTS`
- **Delayed feedback paradigms?** → `NimbusSTS`

### Detailed Comparison


| Scenario                                              | Recommended Model                                | Why?                                                              |
| ----------------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------- |
| **Stable offline datasets**                           | `NimbusLDA`                                      | Fastest, closed-form solution                                     |
| **P300 spelling (stable)**                            | `NimbusLDA` or `NimbusQDA`                       | Event-related, stationary                                         |
| **SSVEP**                                             | `NimbusLDA`                                      | Highly stationary frequency response                              |
| **Motor Imagery (short sessions)**                    | `NimbusLDA` or `NimbusQDA`                       | Stationary within session                                         |
| **Motor Imagery (long sessions, fatigue)**            | `NimbusSTS`                                      | Tracks drift due to fatigue                                       |
| **Multi-day experiments**                             | `NimbusSTS`                                      | State transfer across sessions                                    |
| **Electrode repositioning**                           | `NimbusSTS`                                      | Adapts to impedance changes                                       |
| **Closed-loop with delayed feedback**                 | `NimbusSTS`                                      | Explicit state propagation                                        |
| **Asynchronous BCI (idle vs active)**                 | `NimbusSTS`                                      | Models engagement state                                           |
| **Neurofeedback training**                            | `NimbusSTS`                                      | Tracks learning-induced changes                                   |
| **Long calibration sessions, want to cut label cost** | Any head + `suggest_next_trial(strategy="bald")` | Pool-based BALD on the conjugate posterior; LDA/QDA/Softmax in v1 |
| **Don't know when to stop calibrating**               | Any head + `calibration_sufficient`              | Label-free `posterior_stability` works for STS too                |


### NimbusSTS Example (Temporal Adaptation)

```python
from nimbus_bci import NimbusSTS

# Train on calibration data
clf = NimbusSTS(transition_cov=0.05, num_steps=50)
clf.fit(X_calibration, y_calibration)

# Online session with delayed feedback
for x_trial, y_feedback in online_trials:
    # 1. Propagate state forward (no label needed)
    clf.propagate_state()
    
    # 2. Make prediction
    prediction = clf.predict(x_trial)
    
    # ... user performs action, feedback arrives later ...
    
    # 3. Update with true label
    clf.partial_fit(x_trial, y_feedback)

# Multi-day state transfer
z_day1, P_day1 = clf.get_latent_state()

# Day 2: Initialize with Day 1 state (increased uncertainty)
clf_day2 = NimbusSTS()
clf_day2.fit(X_day2_calib, y_day2_calib)
clf_day2.set_latent_state(z_day1 * 0.5, P_day1 * 2.0)
```

## Label Conventions (Important)

Nimbus supports common EEG/BCI labeling patterns:

- **BCIData labels**: can be any **non-negative integer codes** (e.g., MNE event IDs like 769/770),
as long as the number of unique labels does not exceed `BCIMetadata.n_classes`.
- **sklearn estimators** (`NimbusLDA`, `NimbusQDA`, `NimbusSoftmax`, `NimbusSTS`):
  - `fit()` learns `classes_` from your provided labels.
  - `predict()` returns labels in the **original label space** (elements of `classes_`).
- **Model-snapshot inference** (`NimbusModel` + `predict_batch` / `StreamingSession`):
  - predictions are returned in the model’s **label_base** convention (`label_base` is stored in `model.params`).
  - use `nimbus_bci.data.labels_to_zero_indexed(...)` for metrics/aggregation that require 0-indexed labels.

## NimbusSTS Sequence Semantics (Important)

`NimbusSTS` has a latent state. For correctness and sklearn compatibility:

- `NimbusSTS.predict_proba(X)` treats rows as **conditionally independent** by default.
- For **time-ordered** evaluation, propagate explicitly:
  - call `clf.propagate_state()` between trials/chunks, or
  - use the functional API `nimbus_sts_predict_proba(model, X, evolve_state=True)` when `X` rows are ordered in time.

## Metrics & Diagnostics

```python
from nimbus_bci import (
    compute_entropy,            # Prediction uncertainty
    compute_calibration_metrics,  # ECE, MCE
    calculate_itr,              # Information Transfer Rate
    assess_trial_quality,       # Quality checks
)

# Entropy (uncertainty)
entropy = compute_entropy(posterior)  # bits

# Calibration
calib = compute_calibration_metrics(predictions, confidences, labels)
print(f"ECE: {calib.ece:.3f}, MCE: {calib.mce:.3f}")

# ITR
itr = calculate_itr(accuracy=0.85, n_classes=4, trial_duration=4.0)
print(f"ITR: {itr:.1f} bits/min")
```

## Normalization

Critical for cross-session BCI performance:

```python
from nimbus_bci import estimate_normalization_params, apply_normalization

# Estimate from training data
params = estimate_normalization_params(X_train, method="zscore")

# Apply to all data
X_train_norm = apply_normalization(X_train, params)
X_test_norm = apply_normalization(X_test, params)  # Same params!
```

## Benchmarks

Reproducible **MOABB** runs live in the separately installable `[nimbusbench/](nimbusbench/README.md)` package (install, CLI, checked-in CSVs, `benchmark_summary.md`).

**Read in order:** [Main conclusions](docs/benchmarks.md#main-conclusions) (what to take away) → [Pinned headline table](docs/benchmarks.md#executive-summary-one-pager) (numbers + CSV paths) → [Limitations](docs/benchmarks.md#limitations). Statistics: [benchmark_preregistration.md](docs/benchmark_preregistration.md). **What each model track may claim:** [benchmark_claims.md](docs/benchmark_claims.md).

### At a glance (IV-2b / Lee2019 unless noted)

- **S3:** `partial_fit` matches Nimbus batch refit in eval accuracy; mean **head-only** update time **~8–10×** lower than sklearn batch refit on the same stream (see table + [latency](docs/latency_and_performance.md) for E2E scope).
- **S4:** Report **effective ITR** together with **accept rate** and **accuracy on accepted** (LOFO / non-oracle).
- **S5:** Lee2019 — positive mean lift for `partial_fit` vs **static** on accuracy and effective ITR; Physionet is **supporting**; report heterogeneity where summaries include it.
- **S1 / S2:** Preregistered small-label and tail metrics only—not a universal “beats sklearn” claim.

Regenerate numbers with `python -m nimbusbench summarize --input …` next to the CSVs; do not copy stale figures from prose.

**Quick demo (no MOABB download):** [notebooks/s3_update_latency_head_vs_sklearn.ipynb](notebooks/s3_update_latency_head_vs_sklearn.ipynb) - same-accuracy **partial_fit** vs Nimbus refit + **~8–10×** head update vs sklearn refit from the checked-in S3 CSV.

## Project Structure

```
nimbus_bci/
├── models/              # Classifiers
│   ├── nimbus_lda/     # LDA (shared covariance)
│   ├── nimbus_qda/     # QDA (class-specific covariances)
│   └── nimbus_softmax/ # Softmax (Polya-Gamma)
├── data/               # Data contracts (BCIData, BCIMetadata)
├── inference/          # Batch and streaming inference
├── metrics/            # Diagnostics, calibration, ITR
├── utils/              # Normalization, aggregation
└── compat/             # sklearn/MNE compatibility
```

## Functional API (Backward Compatible)

The original functional API is still available:

```python
from nimbus_bci import (
    nimbus_lda_fit, nimbus_lda_predict, nimbus_lda_update,
    nimbus_qda_fit, nimbus_qda_predict,
    nimbus_softmax_fit, nimbus_softmax_predict,
    nimbus_save, nimbus_load,
)

# Fit model
model = nimbus_lda_fit(X, y, n_classes=4, label_base=0, ...)

# Predict
probs = nimbus_lda_predict_proba(model, X_test)

# Update (online learning)
model = nimbus_lda_update(model, X_new, y_new)

# Save/load
nimbus_save(model, "model.npz")
model = nimbus_load("model.npz")

# Legacy trusted artifacts that contain object-serialized params
# require explicit opt-in:
legacy_model = nimbus_load("legacy-model.npz", trusted=True)
```

## Testing

```bash
pip install -e ".[dev]"
pytest -v
```

## Requirements

**Core** (installed with `pip install nimbus-bci`):

- Python ≥ 3.11
- NumPy ≥ 1.26
- scikit-learn ≥ 1.4
- SciPy ≥ 1.17.1

**Optional extras:**

- **JAX** ≥ 0.4.25 — required for `NimbusSoftmax` and the softmax functional API (`pip install nimbus-bci[softmax]`)
- **MNE** ≥ 1.6 — EEG integration (`pip install nimbus-bci[mne]`)
- **matplotlib** ≥ 3.8 — visualization (`pip install nimbus-bci[viz]`)
- `all` installs all optional extras above (`pip install nimbus-bci[all]`)

## License

This Software is **proprietary** — Nimbus BCI Inc. retains all rights — and is licensed under **two tracks**:

1. **No-cost Non-Commercial License (self-executing, no registration required).**
   Anyone may install, use, modify, and redistribute the Software (and their own derivative works) for **non-commercial** research, scholarship, teaching, or personal learning — including at universities, government labs, and non-profit research organizations. Modifications and non-commercial distribution (e.g., forks, public reproducibility archives) are permitted, provided derivative works keep this LICENSE.txt and link back to nimbusbci.com. A non-commercial patent grant is included.
   **Citation is strongly requested** (it's how a small team sustains no-cost academic access) but is **not a legal condition** — you don't lose your license by forgetting a BibTeX entry. See [`CITATION.cff`](CITATION.cff).

2. **Paid Commercial License.**
   Any use inside a for-profit company, in a paid product or service, for sponsored/fee-for-service research, or for internal business operations requires a separate written commercial license. Tiers below.

| Tier             | Use Case                                                  |
| ---------------- | --------------------------------------------------------- |
| **Startup**      | Companies < $1M revenue                                   |
| **Commercial**   | Full production rights                                    |
| **Enterprise**   | Unlimited deployments + SLA                               |
| **OEM/Embedded** | Medical devices, FDA support, white-label redistribution  |

Full terms: [`LICENSE.txt`](LICENSE.txt). If you are unsure which track applies to your use case, contact [hello@nimbusbci.com](mailto:hello@nimbusbci.com).

### How to cite

If you use the Nimbus BCI Python SDK in your research, please cite it (see [`CITATION.cff`](CITATION.cff)):

```bibtex
@software{nimbus_bci_pysdk,
  author       = {{Nimbus BCI Inc.}},
  title        = {Nimbus BCI Python SDK: Bayesian classifiers for brain-computer interfaces},
  year         = {2026},
  version      = {0.4.2},
  url          = {https://nimbusbci.com},
  note         = {Replace the version above with the version you installed.}
}
```

### Request a commercial license

1. Email **[hello@nimbusbci.com](mailto:hello@nimbusbci.com)** with your use case
2. Receive a license agreement and API key (if applicable)
3. Install and start building

**Website:** [https://nimbusbci.com](https://nimbusbci.com)

---

© 2024-2026 [Nimbus BCI Inc.](https://nimbusbci.com) — The AI Engine for Brain-Computer Interfaces.

**License:** Proprietary with a no-cost Non-Commercial License for academic and non-commercial use (citation requested, not required). See [License](#license) below and [`LICENSE.txt`](LICENSE.txt).
