bci_mcp.core.device ¶
Device abstraction shared by every EEG backend.
Chunk
dataclass
¶
Source code in src/bci_mcp/core/device.py
21 22 23 24 | |
Device ¶
Bases: ABC
A streaming EEG source. Subclasses run their own acquisition internally.
Source code in src/bci_mcp/core/device.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | |
read
abstractmethod
¶
read()
Non-blocking pull of newly available samples, or None if none/not streaming.
Source code in src/bci_mcp/core/device.py
38 39 40 | |
DeviceInfo
dataclass
¶
Source code in src/bci_mcp/core/device.py
10 11 12 13 14 15 16 17 18 | |
bci_mcp.core.registry ¶
URI-based device registry: create_device('synthetic://?focus=0.8').
Device ¶
Bases: ABC
A streaming EEG source. Subclasses run their own acquisition internally.
Source code in src/bci_mcp/core/device.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | |
read
abstractmethod
¶
read()
Non-blocking pull of newly available samples, or None if none/not streaming.
Source code in src/bci_mcp/core/device.py
38 39 40 | |
create_device ¶
create_device(uri)
Source code in src/bci_mcp/core/registry.py
17 18 19 20 21 22 23 24 25 | |
discover ¶
discover()
Best-effort device discovery: always-available schemes + scanned serial ports.
Source code in src/bci_mcp/core/registry.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
list_schemes ¶
list_schemes()
Source code in src/bci_mcp/core/registry.py
28 29 | |
register ¶
register(scheme, factory)
Source code in src/bci_mcp/core/registry.py
13 14 | |
bci_mcp.pipeline ¶
Pipeline: ties a Device/Stream to the DSP chain and emits BrainState.
BrainState
dataclass
¶
Source code in src/bci_mcp/dsp/state.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
Calibration
dataclass
¶
Source code in src/bci_mcp/dsp/calibration.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
Device ¶
Bases: ABC
A streaming EEG source. Subclasses run their own acquisition internally.
Source code in src/bci_mcp/core/device.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | |
read
abstractmethod
¶
read()
Non-blocking pull of newly available samples, or None if none/not streaming.
Source code in src/bci_mcp/core/device.py
38 39 40 | |
Pipeline ¶
Source code in src/bci_mcp/pipeline.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
Stream ¶
Source code in src/bci_mcp/core/stream.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | |
create_device ¶
create_device(uri)
Source code in src/bci_mcp/core/registry.py
17 18 19 20 21 22 23 24 25 | |
bci_mcp.dsp.bands ¶
Band power via Welch PSD.
Band power is the integral of the Welch power spectral density over each band
(scipy welch + trapezoid). This is the standard EEG band-power estimator; by
Parseval it equals the variance (RMS²) of the band-filtered signal up to scaling,
so the choice of "PSD vs RMS" is a unit convention, not a correctness question.
Two practical details handled here:
- Welch averaging.
npersegtargets ~1 s segments with 50% overlap, so a longer analysis window is averaged over several segments (lower-variance PSD) instead of returning a single noisy periodogram. - Narrow-band guard.
trapezoidover a single frequency bin returns 0. At coarse resolution a narrow band (e.g. gamma at a low sample rate) can capture just one bin, which would silently zero that band's power; we fall back to rectangular integration in that case.
BANDS
module-attribute
¶
BANDS = {'delta': (1.0, 4.0), 'theta': (4.0, 8.0), 'alpha': (8.0, 13.0), 'beta': (13.0, 30.0), 'gamma': (30.0, 45.0)}
band_powers ¶
band_powers(data, fs, nperseg=None)
Mean absolute power per band, averaged over channels (µV²).
Source code in src/bci_mcp/dsp/bands.py
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
relative_band_powers ¶
relative_band_powers(bp)
Source code in src/bci_mcp/dsp/bands.py
63 64 65 | |
bci_mcp.dsp.metrics ¶
Cognitive metrics derived from band powers.
These are heuristic band-power ratios, not validated clinical measurements.
Each one is a recognizable simplification of an index from the literature; the
METRIC_INFO table below records the exact formula, the work it draws on, and
an honest caveat for every metric. Downstream consumers (CLI, dashboard,
MCP/LLM) should treat the values as proxies, weight them by the per-reading
confidence the pipeline attaches, and never present them as ground-truth
cognitive states.
Design notes¶
focususes the genuine Pope, Bogart & Bartolome (1995) engagement indexβ / (α + θ)— the best-validated of these ratios.engagementis a distinct arousal ratioβ / α(not the Pope index), so the two are not duplicates.- Delta and gamma are intentionally excluded from every metric: on consumer hardware over short windows, 30-45 Hz "gamma" is dominated by EMG and <1-4 Hz delta by drift/ocular artifact, so building user-facing metrics on them adds noise, not signal. They are still reported as raw band powers.
- The metrics are chosen so no two are collinear on the same band in the same
direction — in particular
meditationfalls with theta whilefatiguerises with it, so a drowsy reading cannot score high on both (a relative- theta "meditation" metric would have confounded the two).
References¶
- Pope, Bogart & Bartolome (1995), Biological Psychology — engagement index
β / (α + θ). - Lubar (1991); Monastra et al. (1999), Neuropsychology — theta/beta ratio (TBR) for attention/ADHD; diagnostic validity later contested (Arns et al. 2013).
- Eoh, Chung & Kim (2005), Int. J. Industrial Ergonomics —
(θ + α) / βas a driver mental-fatigue index. - Berger (1929); NeuroSky eSense — alpha as the canonical relaxed-wakefulness rhythm underlying consumer calm/meditation meters.
DEFAULT_SCALING
module-attribute
¶
DEFAULT_SCALING = {'focus': (1.0, 1.0), 'calm': (0.5, 0.2), 'attention': (1.0, 1.0), 'engagement': (1.0, 1.0), 'fatigue': (1.0, 1.0), 'meditation': (0.5, 0.2)}
METRIC_INFO
module-attribute
¶
METRIC_INFO = {'focus': {'formula': 'beta / (alpha + theta)', 'basis': 'Pope et al. (1995) EEG engagement/concentration index — the best-validated of these ratios.', 'caveat': "A proxy for task engagement/concentration, not a direct measurement of 'focus'."}, 'calm': {'formula': 'alpha / (alpha + beta)', 'basis': 'Alpha-up / beta-down is a long-standing relaxation correlate.', 'caveat': "Resting alpha also tracks drowsiness and eyes-closed state, so high 'calm' is not necessarily relaxed attention."}, 'attention': {'formula': 'beta / theta (inverse of the theta/beta ratio, TBR)', 'basis': 'TBR (Lubar 1991; Monastra 1999) is the classic inattention marker.', 'caveat': "TBR's diagnostic validity is contested (Arns et al. 2013) and it is a between-subjects trait marker, not a moment-to-moment readout."}, 'engagement': {'formula': 'beta / alpha', 'basis': 'Beta/alpha arousal–activation ratio.', 'caveat': "An arousal proxy, distinct from the Pope engagement index (that formula is used by 'focus')."}, 'fatigue': {'formula': '(theta + alpha) / beta', 'basis': 'Eoh et al. (2005) driver mental-fatigue / drowsiness index.', 'caveat': 'Slow-wave dominance is ambiguous; corroborate with low engagement before concluding fatigue.'}, 'meditation': {'formula': 'alpha / (alpha + beta + theta)', 'basis': 'Relative alpha as a relaxed-wakefulness proxy (Berger rhythm; NeuroSky eSense convention).', 'caveat': 'NOT a validated meditation classifier. Deliberately falls with theta so it does not collapse into the drowsiness signal the way a relative-theta metric would.'}}
METRIC_NAMES
module-attribute
¶
METRIC_NAMES = ('focus', 'calm', 'attention', 'engagement', 'fatigue', 'meditation')
raw_metrics ¶
raw_metrics(bp)
Unscaled metric ratios. Calibration maps these into 0..1 later.
See the module docstring and METRIC_INFO for the basis and caveats of
each metric. Only theta/alpha/beta are used; delta and gamma are excluded
on purpose (drift- and EMG-dominated on consumer hardware).
Source code in src/bci_mcp/dsp/metrics.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | |
bci_mcp.dsp.state ¶
The unified brain-state snapshot shared by CLI, dashboard, and MCP.
BrainState
dataclass
¶
Source code in src/bci_mcp/dsp/state.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |