Skip to content

Electrode-impedance check (Run mode)

Before a session (and optionally before each block) the operator checks per-electrode impedance on the OpenBCI Cyton, lowers it to their satisfaction, and the readings are saved into the recording. This closes one of the pilot's back-fill gaps: impedances are captured in-app and travel with the data, never pulled from a side spreadsheet afterwards (DESIGN_PRINCIPLES #1).

Operator SOP

  1. Cap/gel the participant as usual. With the board powered on and connected, lock the protocol on Set up Session (Load protocol… / Resolve / 🔒 Lock all live there — #147), then switch to Run Session and launch the check:
  2. GUI: expand the collapsible QA check pane (it also expands automatically when you press Start selected run) and click Start / Re-check. (Before #126 this lived on its own QA check tab; it is the same widget, just folded into Run Session so the whole session runs from one place.)
  3. or headless one-shot: python -m ssvep.runtime.openbci --serial-port COM5 --impedance. (The OpenBCI GUI must be closed — it locks the serial port.)
  4. The montage graphic shows one circle per electrode at its 2-D position, labelled the way the selected carrier labels its channels — 10-10 site names on the default Occipital 10-10 montage, Cyton wire colours on the free electrode array — coloured by impedance on a luminance-balanced gradient (the printed number is the actual kΩ; n/a = a channel that could not be measured). The scale auto-sizes to at least 100 kΩ and expands to cover the worst channel, so gel montages read on a 0–100 scale while dry electrodes — which run to many hundreds of kΩ — aren't all pinned to the top colour. It updates live as you adjust electrodes.
  5. Set Label to when the reading is taken (pre-session, then pre-block-3, …) and click Done. The current values are captured as a snapshot immediately; switching the drive off is asked for at the same moment, but see Stopping is not instant below — the status line stays honest about which of those two has actually happened.
  6. Repeat before later blocks as needed — each Done appends another snapshot.

During the check the channels are not recording EEG (the board is injecting the drive tone), so this is always a distinct step before/between recording, not concurrent with it.

Stopping is not instant — the status line (and Start session) say so

On the Cyton, turning the drive off is 8 sequential synchronous serial round-trips (openbci._drive_all_channels) followed by releasing the board session — real hardware I/O that has been observed to take 5–10 seconds, not the sub-second teardown Done otherwise looks like. Until that finishes:

  • The impedance status line reads "stopping… (releasing the amplifier — this can take several seconds)" — not "captured" or "ready" — and only flips to the real "captured '
  • Start session stays disabled the whole time. Clicking it anyway (e.g. from a stale UI state) is also refused directly, with "An impedance check is running — click Done to stop it before recording."

Both of those track the actual worker thread, not a fixed wait: an earlier version (#119) reported "stopped" unconditionally after a bounded synchronous wait, even when that wait timed out and the Cyton was still mid-teardown — so Start session could look clickable for several seconds after Done, then refuse anyway with "impedance still running" when clicked. If you see the "stopping…" status linger, that delay is real board teardown time, not a hang — wait for it; there is nothing to retry.

How it works

The Cyton has no continuous impedance stream. We use the ADS1299 lead-off detection: enable a 6 nA / 31.2 Hz drive on each channel (BrainFlow config_board("z<ch>01Z")), read back the amplitude of that tone, and convert with the OpenBCI formula

Z = √2 · V_rms / I_drive − R_series      # I_drive = 6 nA, R_series = 2200 Ω

Pure core (testable, no hardware): ssvep.runtime.impedance. Live board read (hardware-gated): ssvep.runtime.openbci.stream_impedance / measure_impedance_once. UI: ssvep.ui.run.

⚠ Known limitation — Cyton/ADS1299 only (Unicorn reports bogus ~0 kΩ)

This method is specific to the Cyton's ADS1299 lead-off drive. Boards without that path report invalid numbers:

  • g.tec Unicorn — observed 2026-07-14: impedance shows ≈ 0 kΩ on every channel regardless of real contact (with dry Unicorn electrodes and obviously poor signal quality, i.e. the true impedances are much higher). The Unicorn exposes no lead-off drive via BrainFlow, so the Cyton formula is meaningless for it. Do not trust Unicorn impedance readings — needs a Unicorn-specific method or an explicit "impedance unsupported on this board" state. Not yet fixed.
  • actiCHamp — has its own impedance mode (ssvep.runtime.actichamp.impedances_kohm), but that read layout is not yet verified on hardware (see docs/ACTICHAMP.md).

Where it's saved

Each session sidecar (*_eeg.session.json) gains an impedance list — one entry per snapshot with its label, timestamp, drive parameters, and per-channel kΩ. The latest snapshot is also mirrored into that recording's manifest montage (acquisition.montage[].impedance_kohm), so analysis can read impedance by lookup with zero heuristics. The versioned design-time run manifest in run-manifests/ is never modified — impedance is acquisition-time data.

Thresholds — deliberately not set yet

There is no pass/fail cut-off and the colour scale is a plain gradient, not a good/bad split. What impedance actually predicts good vs. poor SSVEP classification (and how that differs for gold-cup + paste vs. the dry-electrode prototype) is to be determined empirically against decoding performance. Until then the tool records the numbers and shows the range; it does not judge them.

First dry-headset bring-up (2026-07-03, self-test on sub-000) read 170–1030 kΩ across the occipital montage and still decoded 9-class SSVEP at 25.9 % @ 4 s (chance 11.1 %, p≈0.025) — weak but above chance, i.e. a lot of headroom between "measurable" and "good" for the dry prototype.

Impedance checking is routine EEG practice, and the 6 nA drive is far below any safety concern — but whether it needs its own sign-off is a question for your ethics board, not this doc. It is the hardware itself that most often needs it, tracked per deployment in docs/REB_AMENDMENTS.md.