Skip to content

bdsp-core/neurobrowser

Repository files navigation

NeuroBrowser

Ultrafast EEG template matching under Dynamic Time Warping — a Python port of the algorithm at the core of NeuroBrowser.

J. Jing, J. Dauwels, T. Rakthanmanon, E. Keogh, S. S. Cash, M. B. Westover. Rapid annotation of interictal epileptiform discharges via template matching under Dynamic Time Warping. Journal of Neuroscience Methods 274 (2016) 179–190. doi:10.1016/j.jneumeth.2016.02.025

NeuroBrowser lets an expert mark one example of a waveform (e.g. an interictal epileptiform discharge / "spike") and then rapidly finds every similar waveform in a long EEG recording. The similarity measure is Dynamic Time Warping (DTW), made fast enough for interactive use by the UCR Suite / "Trillion" lower-bounding algorithm (Rakthanmanon et al., KDD 2012 — E. Keogh and T. Rakthanmanon are co-authors of the NeuroBrowser paper). In the original study this reduced expert annotation time by ~70% and yielded a database of 19,000+ spikes from 100 patients.

This repository reimplements that engine in pure Python (NumPy/SciPy) so it can be used without MATLAB, on any platform.

Reproduce

See REPRODUCE.md (what regenerates + one command) and DATA_SOURCE.md (data provenance). Verified 2026-07-06: Fig 2b separation, Fig 6/7 alignment, ~112x speed, 34/34 tests.

What's here

Module Purpose
neurobrowser/dtw.py Constrained (Sakoe–Chiba) DTW + z-normalized subsequence k-NN search with LB_Keogh early-abandoning (the "fast DTW").
neurobrowser/_ucrmodule.c C accelerator: the full UCR Suite cascade (online z-norm, LB_Kim, LB_Keogh, early-abandoning DTW). ~100× faster, identical results. Built automatically; pure-Python fallback if no compiler.
neurobrowser/preprocessing.py Band-pass filter, Teager NLEO energy operator, CAR montage.
neurobrowser/matching.py The template-matching pipeline (port of main_TMbyDTW.m).
neurobrowser/io.py Loaders for the .mat template bank and EEG event segments.
examples/demo_match.py Match one event and plot the DTW alignment + detected spike.
examples/reproduce_fig2b.py Reproduce the paper's spike-vs-background DTW-distance separation (Fig. 2b).
tests/ Correctness tests (banded DTW vs brute force; pruned search vs exhaustive).

Install

git clone git@github.com:bdsp-core/neurobrowser.git
cd neurobrowser
pip install -e ".[plot,dev]"

Requires Python ≥ 3.9, NumPy, SciPy (matplotlib for the figures).

Quickstart

import neurobrowser as nb

templates = nb.load_templates("data/Callbacks/Templates.mat")
event     = nb.load_event("data/Data/s117_SEG_10783.mat")

result = nb.match_event(event, templates)
print(result.template_index, result.distance, result.location)

Core search on your own signals:

import numpy as np, neurobrowser as nb

query = np.sin(np.linspace(0, 3*np.pi, 40))     # a template
data  = np.random.randn(2000)                    # a long recording (1 channel)
dist, loc = nb.ucr_knn_dtw(query, data, r=0.05, k=3)   # 3 best matches

Speed

The similarity search uses the UCR Suite cascade compiled in C. On a 20,000-sample signal with a 50-sample query it runs in ~3 ms vs ~385 ms for the pure-Python reference (~114×), returning bit-for-bit identical matches. Check which path is active and benchmark:

>>> from neurobrowser.dtw import HAVE_C; HAVE_C
True
python examples/benchmark.py        # naive DP vs Python vs C

The C accelerator builds automatically during pip install. If no C compiler is present the package still installs and transparently falls back to pure Python (backend="python").

Reproducing the paper

The headline ~70% time-savings is a human user-study result and is not computationally reproducible. The algorithmic claims are:

# 1) DTW cleanly matches a template to a spike and localizes it:
python examples/demo_match.py --data /path/to/bundle

# 2) DTW distance separates spikes from background EEG (Fig. 2b):
python examples/reproduce_fig2b.py --data /path/to/bundle

On the shipped demo bundle, (2) yields a clear separation (median DTW distance ≈ 1.8 at spikes vs ≈ 3.8 at background).

Relationship to the original MATLAB code

The original engine was a MATLAB MEX (UCR_KNN_DTW_Mex) wrapping a custom-modified UCR Suite in C. Only a compiled Windows binary survived, so this port re-derives the algorithm from the paper and the surviving MATLAB wrappers (UCR_KNN_DTW.m, main_TMbyDTW.m, energyop.m). By default the DTW local cost is squared-Euclidean to match the UCR Suite / MEX numerics; pass metric="abs" for the L1 form written in Eq. (2) of the paper. A MATLAB cross-validation harness lives under matlab/ (see its README).

Data & de-identification

The demo EEG segments are de-identified 10-second snippets. They are not committed here pending release approval; the dataset's canonical home is bdsp.io. See data/README.md.

License

BSD 3-Clause — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors