Metadata-Version: 2.4
Name: neurostream-edge
Version: 0.1.0
Summary: A modular runtime for continuous biosignal processing and real-time inference.
Author: Tarun Chilkur
License: MIT
Project-URL: Documentation, https://github.com/tarunc997/NeuroStream-Edge
Project-URL: Repository, https://github.com/tarunc997/NeuroStream-Edge
Project-URL: Issues, https://github.com/tarunc997/NeuroStream-Edge/issues
Keywords: biosignal,streaming,real-time,inference,eeg,ecg,emg,ppg,edge
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Provides-Extra: onnx
Requires-Dist: onnxruntime>=1.14; extra == "onnx"
Provides-Extra: torch
Requires-Dist: torch>=2.0; extra == "torch"
Provides-Extra: brainflow
Requires-Dist: brainflow>=5.0; extra == "brainflow"
Provides-Extra: lsl
Requires-Dist: pylsl>=1.16; extra == "lsl"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Dynamic: license-file

# NeuroStream-Edge

> **A modular, interface-driven runtime for continuous biosignal processing and real-time inference.**

[![Status](https://img.shields.io/badge/status-alpha-orange)](#status)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/badge/PyPI-neurostream--edge-blue.svg)](https://pypi.org/project/neurostream-edge/)
[![Tests](https://img.shields.io/badge/tests-95%20passing-brightgreen)](#testing)

---

## Overview

NeuroStream-Edge is an open-source runtime for building real-time biosignal
processing pipelines. It focuses on the **infrastructure between a continuous
sensor stream and machine learning inference** — providing modular components
for streaming, buffering, window generation, runtime orchestration, storage,
and performance analysis.

The runtime is designed to support multiple biosignal modalities — **EEG, ECG,
EMG, and PPG** — while remaining independent of any specific downstream task or
machine-learning architecture.

---

## Highlights

- **Interface-driven architecture** — every layer exposes an abstract base class.
  The runtime depends only on interfaces, never on concrete implementations.
- **Streaming-first, fixed-memory execution** — pre-allocated ring buffers with
  O(1) writes and circular overwrite semantics. No growth, no GC pressure in the
  hot path.
- **Model-agnostic & signal-agnostic** — bring your own ONNX / TorchScript model
  or implement the `InferenceEngine` interface.
- **Minimal core dependencies** — the runtime requires only **NumPy**. Every
  heavy backend (ONNX, PyTorch, BrainFlow, LSL) is an optional extra with a
  clear `ImportError` and lazy import.
- **Observable by design** — a decoupled Observer-based event system feeds a
  logger, profiler, and metrics collector without coupling into the execution path.
- **Online runtime and offline pipeline are intentionally separated** — reflecting
  the different engineering requirements of low-latency inference and large-scale
  dataset processing.

---

## Status

**Alpha.** All eight core modules are implemented and covered by 95 passing tests
(~78% line coverage). The runtime is functional end-to-end with a reference
simulated pipeline, but is not yet benchmarked against external baselines and the
public API is still stabilising. See the [Roadmap](#roadmap) for what is planned.

| Module | Interface | Role | Status |
|--------|-----------|------|--------|
| `acquisition` | `SignalSource` | Continuous sample streams from sensors or simulators | ✅ |
| `streaming` | `Buffer` | Fixed-capacity, overwrite-on-full buffers | ✅ |
| `windowing` | `WindowGenerator` | Overlapping inference-ready windows | ✅ |
| `runtime` | — | Pipeline orchestration + event system | ✅ |
| `models` | `InferenceEngine` | Model-agnostic prediction backends | ✅ |
| `storage` | `StorageBackend` | Offline dataset recording / playback | ✅ |
| `observability` | `Observer` | Decoupled logging, profiling, metrics | ✅ |
| `benchmarking` | — | Throughput & latency characterisation | ✅ |

---

## Installation

### From PyPI

```bash
pip install neurostream-edge
```

### From source

```bash
git clone https://github.com/tarunc997/NeuroStream-Edge.git
cd NeuroStream-Edge
pip install -e .
```

### Optional extras

Heavy backends are never installed automatically — install only what you need:

```bash
pip install "neurostream-edge[onnx]"      # ONNX Runtime
pip install "neurostream-edge[torch]"     # TorchScript
pip install "neurostream-edge[brainflow]" # BrainFlow hardware adapters
pip install "neurostream-edge[lsl]"       # Lab Streaming Layer
pip install "neurostream-edge[dev]"       # pytest, pytest-cov
```

Extras can be combined, e.g. `pip install "neurostream-edge[onnx,dev]"`.

---

## Quick start

A minimal online pipeline: **SimulatedSignalSource → RingBuffer → SlidingWindowGenerator → DummyInferenceEngine**.

```python
import time
import neurostream as ns

# 1. Build components (dependency injection)
source  = ns.SimulatedSignalSource(sample_rate=250.0, n_channels=8, seed=42)
buffer  = ns.RingBuffer(capacity=2500, n_channels=8)           # 10 s @ 250 Hz
window  = ns.SlidingWindowGenerator(buffer, window_size=250,   # 1 s window
                                    stride=50)                 # 0.2 s stride
engine  = ns.DummyInferenceEngine(n_outputs=3)

# 2. Optional observability
bus = ns.EventBus()
metrics  = ns.Metrics()
profiler = ns.Profiler()
bus.subscribe("*", metrics)
bus.subscribe("*", profiler)

# 3. Wire everything into the runtime
runtime = ns.Runtime(source=source, buffer=buffer, window=window,
                     inference=engine, event_bus=bus, read_chunk=10)

# 4. Run
runtime.start()
runtime.run_for(2.0)   # run for 2 seconds
runtime.stop()

print(f"Predictions: {len(runtime.predictions)}")
print(f"Throughput : { {k: f'{v:.1f}/s' for k, v in metrics.throughput().items()} }")
```

More examples live in [`examples/`](examples):

- [`online_pipeline.py`](examples/online_pipeline.py) — full online inference pipeline
- [`offline_recording.py`](examples/offline_recording.py) — record a stream to disk and replay it
- [`benchmark_buffers.py`](examples/benchmark_buffers.py) — compare buffer backends

---

## Architecture

The online inference runtime and offline data pipeline are intentionally
separated, reflecting the different engineering requirements of low-latency
inference and large-scale dataset processing.

### Online runtime

```text
Continuous Signal
        │
        ▼
Acquisition Layer
        │
        ▼
Streaming Layer
 (Ring Buffers)
        │
        ▼
Windowing Layer
        │
        ▼
Inference Runtime
        │
        ▼
Model Interface
        │
        ▼
Prediction
```

### Pipeline context

```text
                Runtime (orchestrator)
                        │
       ┌────────────────┼────────────────┐
       ▼                ▼                ▼
 Acquisition       Streaming        Windowing
 (SignalSource)     (Buffer)     (WindowGenerator)
       │                │                │
       └────────────────┼────────────────┘
                        ▼
                 Models (InferenceEngine)
                        │
                  Storage (offline)

   Observability (Logger · Profiler · Metrics) ← Runtime events
   Benchmarking  (per-component measurement)
```

### Design principles

- **Streaming-first** — designed around continuous signals, not static datasets.
- **Interface-driven** — the runtime depends only on abstractions; components are
  interchangeable (Strategy pattern).
- **Composition over inheritance** — no per-modality `EEGRuntime` / `ECGRuntime`
  classes; one runtime serves every signal type.
- **Fixed-memory execution** — storage is allocated once and never grows.
- **Storage-independent & model-agnostic** — backends are pluggable.

> **Allocation note:** the streaming write path is O(1) and allocation-free for
> contiguous writes. Read paths (`read()`, `latest()`) allocate copies to avoid
> exposing internal buffers.

---

## Repository structure

```text
docs/                # architectural & per-module reference
examples/            # runnable scripts
neurostream/
├── acquisition/     # signal sources & adapters
├── streaming/       # fixed-memory buffers
├── windowing/       # sliding-window generation
├── runtime/         # pipeline orchestration & events
├── models/          # inference engines & factory
├── storage/         # dataset backends
├── observability/   # logger, profiler, metrics
└── benchmarking/    # benchmarks & latency profiling
tests/               # 95 tests
```

---

## Documentation

Detailed per-module guides cover each layer's purpose, its abstract interface,
the concrete implementations and their trade-offs, and runnable usage examples.

| Module | Guide |
|--------|-------|
| Acquisition | [`docs/modules/acquisition.md`](docs/modules/acquisition.md) |
| Streaming | [`docs/modules/streaming.md`](docs/modules/streaming.md) |
| Windowing | [`docs/modules/windowing.md`](docs/modules/windowing.md) |
| Models | [`docs/modules/models.md`](docs/modules/models.md) |
| Storage | [`docs/modules/storage.md`](docs/modules/storage.md) |
| Runtime | [`docs/modules/runtime.md`](docs/modules/runtime.md) |
| Observability | [`docs/modules/observability.md`](docs/modules/observability.md) |
| Benchmarking | [`docs/modules/benchmarking.md`](docs/modules/benchmarking.md) |

Start at [`docs/index.md`](docs/index.md) for the architecture overview.

---

## Testing

The suite uses **real concurrency** — actual background threads, real timing,
real predictions — rather than mocks, so integration behaviour is exercised
directly.

```bash
pip install "neurostream-edge[dev]"
pytest
```

With a coverage report:

```bash
pytest --cov=neurostream --cov-report=term-missing
```

---

## Scope

NeuroStream-Edge is **infrastructure, not an end-user application.** It is not
tied to a specific machine-learning task such as seizure detection, sleep
staging, emotion recognition, or motor imagery. Instead, it provides the runtime
required to support continuous biosignal inference across multiple research and
deployment scenarios.

---

## Roadmap

- [ ] End-to-end reference pipeline on a public dataset (e.g. TUH EEG, BCI Comp IV)
- [ ] Benchmark against a naive baseline using the built-in `benchmarking/` layer
- [ ] Convenience `quickstart()` constructor for low-friction onboarding
- [ ] Config-driven pipelines + `neurostream run` CLI (YAML → wired runtime)
- [ ] Plugin entry points (`[project.entry-points]`) for third-party engines/sources
- [ ] Explicit backpressure / drop policies (`block` / `drop-newest` / `drop-oldest`)
- [ ] Source & storage factories to match the existing `InferenceFactory`
- [ ] Async / queued EventBus option to fully decouple observers from the tick
- [ ] `CITATION.cff` and first tagged release

---

## Contributing

Contributions are welcome. The project follows an interface-driven architecture —
every layer exposes an abstract base class, and the runtime depends only on
interfaces. Before adding new functionality, open an issue to discuss scope.

When contributing, please:

1. Keep the runtime free of concrete-component dependencies (depend on interfaces).
2. Add or update tests for any behavioural change.
3. Run `pytest` and ensure the full suite passes before submitting a PR.
4. Follow the existing numpy-style docstring conventions.

---

## License

[MIT License](LICENSE) © Tarun Chilkur
