Downloads · 30 days
0
Twu31/EEG_SSVEP_Drone
EEG_SSVEP_Drone is a machine learning model from Twu31. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
Mirror of github.com/twu3202/EEGSSVEPDrone. Data also at Twu31/cap32-ssvep.
Downloads · 30 days
0
Access
Public
Updated Aug 20, 2026
Repo size
6.3 MB
Likes
0
Public
Click a slice to open those files.
.npz3.7 MB · 49%
From the Hugging Face model README
Mirror of github.com/twu3202/EEG_SSVEP_Drone. Data also at Twu31/cap32-ssvep.
Steering a DJI Tello with SSVEP (steady-state visually evoked potentials) recorded on a low-cost 32-channel dry-electrode cap (TI ADS1299, 250 Hz, WiFi/UDP). The aim was a continuous control loop — a command every 300–400 ms — rather than one command every five seconds.
Companion project: EEG_MI (motor imagery on the same cap; this repo reuses its acquisition/protocol layer rather than forking it).
Decoding is barely above chance, and this repo is mostly the record of finding out why.
| Session | Targets | Best decoder | Accuracy | Chance | 95 % CI |
|---|---|---|---|---|---|
ssvep_20260725_150031 | 12 | FBCCA, 2.4 s | 0.150 | 0.083 | [0.10, 0.22] |
ssvep_20260725_171821 | 4 | TRCA-CCA, 1.8 s | 0.450 | 0.250 | [0.33, 0.58] |
Above chance, statistically — and nowhere near usable for flying anything. The interesting part is the diagnosis.
Errors piled up at 8 Hz regardless of the true target. The obvious suspect is the alpha rhythm, and this subject's IAF is exactly 10.00 Hz — but that turned out to be the second effect, not the cause.
CCA/FBCCA's score ρ is a variance ratio, so argmax over candidate frequencies is really
comparing absolute power at each. Under a S(f) ∝ f^-α aperiodic background the noise
floor itself goes as ρ_noise(f) ∝ f^(-α/2) — monotonically decreasing, so the lowest
candidate frequency wins by default. Measured slope: −0.95 to −1.11, against an
independently fitted α = 1.79–2.34 whose prediction matches to within 0.06. The 8 Hz noise
floor sits 1.7–1.9× higher than 15.7 Hz.
Alpha is real and does sit on top of it — in the one confound-free session the excess over the power law peaks at exactly 10.0 Hz, matching the independently measured IAF — but that excess is only +19.7 % against the +71 % from the 1/f floor.
Full derivation and the measurements: docs/lowfreq_bias_report.pdf (中文).
Holm correction is applied throughout, which is why several early effects disappeared.
Four calibration sessions, published with the code in calib/ and mirrored to
huggingface.co/datasets/Twu31/cap32-ssvep.
import numpy as np
d = np.load("calib/ssvep_20260725_171821.npz", allow_pickle=True)
d["X"] # (60, 10, 500) float32 µV — trials × channels × samples
d["y"] # (60,) int32 — target index
d["freqs"] # (4,) Hz; d["phases"] (4,) rad; d["names"] (4,) target names
d["ch_names"] # ('P7','P3','PZ','P4','P8','PO3','PO4','O1','OZ','O2')
⚠ These files contain 10 posterior channels, not all 32. Channel selection was applied at
record time, so these sessions cannot be re-analysed with a different montage.
meta_json.channels_full lists the full 32-channel montage the cap was wearing.
src/ssvep/ stimulus, decoders (CCA / FBCCA / eTRCA / TDCA / TRCA-CCA),
calibration, quality checks, the 1/f bias diagnostic, benchmarks
src/control/ Tello SDK driver, safety layer, latency test, MuJoCo simulator
src/acquisition/ SsvepStream — timing-exact capture with gap reconstruction
(imports EEG_MI's protocol layer; does not fork it)
glasses/ Rokid AR-glasses on-device SSVEP probe (Android/Kotlin)
calib/ four calibration sessions: .npz signals + .json paradigm sidecars
docs/ the 1/f bias report; Tello control-stack notes
results/ benchmarks, bias diagnostics, duration frontiers, simulator captures
At 12 Hz one cycle is 83 ms, so a 4 ms epoch-boundary error is 14° of phase. eTRCA and TDCA are phase-locking decoders and collapse to chance when that drifts — which is exactly what happened before the phase-aware templates fix. The acquisition layer reconstructs dropped UDP frames rather than skipping them, for the same reason: skipping compresses the time axis.
Related: the cap's sample clock was later measured against an external generator at +3235 ppm — small for band power, but a 0.4 % clock error rotates a 12 Hz tone by a full cycle in ~2 s. See the crosstalk report in EEG_MI.
pip install -r requirements.txt
python src/ssvep/benchmark.py --demo # decoders on synthetic SSVEP, no hardware
python src/ssvep/stimulus.py --targets 4 # frame-accurate flicker stimulus
python src/ssvep/bias_diag.py calib/ssvep_20260725_150031.npz # the 1/f diagnostic
python src/control/sim_mujoco.py # Tello simulator, no drone needed
Live capture needs the cap on its ESPBCI access point and the Tello on its own — one WiFi
adapter cannot hold both, which is the first architectural problem in this project. Options
are written up in docs/tello_control_stack.md.
MIT for the code. The recordings are CC BY 4.0.
Recordings are from a single consenting adult subject (the author). No clinical or identifying information is included.