affective computing · live

Reproducing the SEED protocol, on your own hardware.

A two-phase reproduction of the SJTU SEED emotion experiment (Zheng & Lu, 2015). Phase 1 — collection: stream EEG from an OpenBCI Cyton and cardiac data from an EmotiBit through a local bridge — optionally, on a local desktop or edge device NVIDIA Jetson Orin Nano — add webcam eye and hand tracking (WebGazer + MediaPipe), and let an LLM lab assistant run the SEED stimulus protocol and collect the data. Phase 2 — analysis & prediction: pre-train on SEED data and decode emotion from the recording with the models , right here — inference runs in this browser (onnxruntime-web) or through AWS Sagemaker endpoints. Source code is on GitHub.

Watch the walkthrough

A short video tour of this page — the study and models behind it, followed by a live run: sensors on, protocol paced by Pythia, data collected.

1 · Set up the live streams

webcam

Eye + hand tracking

WebGazer gaze + MediaPipe hand keypoints, fully local, logged alongside the EEG. Calibrate trains on nine dots; Validate measures accuracy in degrees of visual angle using the screen and viewing distances below.

off

hands: off

EmotiBit

Cardiac / ECG

EmotiBit over Wi-Fi via BrainFlow — auxiliary = cardiac (PPG), ancillary = EDA + temperature. Every sensor is graded live for signal quality.

bridge required · HR —

OpenBCI

EEG · Cyton

8-channel Cyton (or Daisy for 16), mapped by 10-20 name into the 62-channel SEED montage. Each channel is graded live on a rolling 10-second window — hover any tile for its numbers.

bridge required

2 · Run the SEED protocol

Collection phase, following SEED's session structure: each trial is a 5 s hint, an emotion-eliciting film clip, then self-assessment + rest — 15 trials in the full protocol. SEED's own clips are licensed, so the built-in library is cut from openly licensed and public-domain films into 15 four-minute clips, five per valence, with no in-session repeats — or switch stimuli to self-guided. All enabled streams record throughout, to local disk via the bridge or to S3.

Recording is gated on signal quality: a railed, flat, drifting or noisy channel holds the session until it is fixed or you accept it — accepting clears the hold for good, and the take is marked accepted rather than clean. While a session runs, a quality snapshot is written into the recording every 30 seconds, so an electrode that lifts during trial 7 costs you trial 7 rather than the whole session. Start the bridge with --lsl to mirror every stream and marker onto Lab Streaming Layer, so a LabRecorder can capture it all in one XDF.

Pythia · protocol

Pythia runs this session

Pythia checks the sensors, paces every trial, collects self-reports, and archives the synchronized recording. Start Session opens her automatically and asks you to share Entire Screen, recorded alongside the sensor streams.

With lab ticked (on by default) she watches signal quality and speaks up about anything outstanding, naming the electrode and the fix. Turn reminders off from a reminder or under ⚙ and she stays quiet for good; accepting the flagged quality below also retires its reminders.

Session controls — Pythia uses these same settings.

clip library: loading…

desktop capture: select Entire Screen when the session starts

bridge-saved sessions are training data: python -m eeg_lab.finetune continues the SEED checkpoint on them; --promote --export-web redeploys the personalized weights.

needs: EEG connected + local stimuli + desktop capture

3 · Analysis & prediction

Analysis phase: the decoders were chosen in a nine-arm model ablation on SJTU SEED — statistical representations (differential entropy + LDA, MiniRocket), two foundation models (NormWear2, LaBraM) across three transfer modes, and a from-scratch CNN+LSTM — all on the identical trial-grouped split (eeg_lab/seed_iv_inverted.ipynb; code deep-dive on the model page).

152,7301-second windows · 62 ch @ 200 Hz
9models across 5 families
3 classesemotion labels · chance = 33.3%
~9 hwall clock, cheapest arm first
90.3%best val accuracy — the from-scratch CNN
Validation accuracy — SEED emotion, fold 2
1 s windows · trial-grouped 5-fold split · early stopping on val accuracy for all arms
DE + shrinkage LDA 61.5%
MiniRocket + ridge 70.1%
NormWear2 · frozen probe 47.1%
NormWear2 · LoRA 58.2%
NormWear2 · progressive 50.7%
LaBraM · frozen probe 49.2%
LaBraM · LoRA 81.3%
LaBraM · progressive 66.0%
CNN+LSTM, from scratch chance 33.3%90.3% ★ best
Classical baselines NormWear2 — wearable FM, 187M params LaBraM — EEG-native FM, 5.8M params From scratch, 15.7M params

NormWear2 arms use a 17-channel montage with per-window z-normalization (its channel-fusion attention was pretrained on 2–6 channel inputs); all other arms see the full 62 channels. Caveat printed next to the numbers in the notebook, too.

Three things the chart says

upset

Scratch beats scale

The 15.7M-parameter CNN+LSTM trained from random init hit 90.3% — 9 points above the best foundation-model arm and 32 above the best that the 187M-parameter NormWear2 could manage. None of NormWear2's three transfer modes cleared the humble LDA baseline.

transfer

Specialized pretraining domains outperform general domains

LaBraM is 32× smaller than NormWear2 but was pretrained on ~2,500 h of scalp EEG at 200 Hz with 1 s patches — SEED's exact regime. Same harness, same loaders, same LoRA config: 81.3% vs 58.2%. What the encoder saw in pretraining matters more than how big it is.

fine-tuning

LoRA beat everything else

In both families LoRA outran progressive unfreezing (81.3 vs 66.0; 58.2 vs 50.7), and frozen linear probes came last — NormWear2's frozen probe landed below the statistical baseline. Thawing more blocks visibly plateaued: LaBraM went 63.6 → 66.0 → 65.9 as blocks unfroze.

Predict on your own signal

The winning arms are exported by eeg_lab.models and run here: emotion inference over 1-second windows, exactly like the notebook — resample to 200 Hz, map into the SEED montage, classify. Runs live while streaming and over each recorded stimulus segment after a session. Pick where it runs:

negative
neutral
positive

connect EEG (or the synthetic board) for a live read-out

Signal quality