Project A: The SSVEP speller
Boxes flicker at different rates; the back of your head flickers with whichever one you look at. A decoder reads the frequency out of the EEG and types the letter. Works in an afternoon, and it is the BCI that actually works.
You are skimming: the title, the first figure, and the short version. Switch to Read in the header for the full page, or Deep to open every deep dive.
Stare at a square flashing ten times a second and your visual cortex oscillates at ten hertz, strongly enough that a single electrode at the back of the head shows a clean peak in the spectrum within two seconds. Put four squares on the screen at four different rates, decide which rate the EEG contains, and you have a four-way selector. Arrange letters behind the squares and you have a speller. The steady-state visual evoked potentialSteady-state visual evoked potential (SSVEP)When you stare at something flickering at a fixed rate, visual cortex oscillates at that rate, and the frequency can be read straight out of the EEG spectrum. Glossary entry is the most reliable non-invasive BCI paradigm, it needs no training, and it works for nearly everyone with working eyes.
- Click different boxes and watch how long the decoder takes to follow. That lag is the window length.
- Lower the SSVEP strength until the decoder starts making mistakes. Real people vary this much.
- Note that the decoder’s score for the true frequency includes its second harmonic. Real SSVEP has harmonics too.
Your monitor refreshes at 60 Hz. Which set of flicker frequencies can it display exactly?
Only frequencies that divide 60 evenly, because the screen can only change on a refresh. 10 Hz is on for three frames and off for three. 8.57 Hz (60/7) is on for three or four frames alternately, which still works. 9 Hz cannot be shown steadily on a 60 Hz screen and the actual stimulus will smear across nearby frequencies. This is the first practical constraint every SSVEP designer meets.
The signal
The response sits at the flicker frequency and its harmonics, over occipital electrodes (Oz strongest, O1 and O2 next). Amplitude is a few microvolts, which is small, but it is a pure tone, and pure tones are what spectra find best. Two to four seconds of data is enough to decide among four to eight frequencies for most people.
The decoder
Canonical correlation analysisCanonical correlation analysis (CCA)Finding the combination of channels that correlates best with reference sinusoids at each candidate frequency; the standard SSVEP decoder. Glossary entry is the standard. For each candidate frequency, build reference signals: sine and cosine at f, at 2f, and at 3f. Find the combination of EEG channels that correlates most with the combination of those references. The frequency with the highest correlation wins. With one channel it reduces to fitting the references by least squares and comparing the fit, which is what the simulator does. With several occipital channels the multichannel version is meaningfully better.
import numpy as np
from sklearn.cross_decomposition import CCA
def refs(f, fs, n, harmonics=3):
t = np.arange(n) / fs
return np.column_stack([g(2*np.pi*h*f*t) for h in range(1, harmonics+1) for g in (np.sin, np.cos)])
def decode(X, freqs, fs): # X: samples × channels, a 2–4 s window
scores = []
for f in freqs:
cca = CCA(n_components=1).fit(X, refs(f, fs, len(X)))
u, v = cca.transform(X, refs(f, fs, len(X)))
scores.append(np.corrcoef(u[:, 0], v[:, 0])[0, 1])
return freqs[int(np.argmax(scores))], scores
The stimulus
PsychoPy, full screen, black background, four to eight white squares each toggling on a fixed frame schedule, with a letter or word under each. Push an LSL marker whenever the layout changes. Frame-locked toggling is the whole trick; do it inside the flip loop, never with timers.
The speller
A four-target selector spells slowly. The classic layout is a tree: four squares each holding a group of letters; look at a group to select it, then the letters in that group spread across the four squares, then select the letter. Two selections per character, about eight seconds each with a comfortable window: a character every fifteen to twenty seconds. Slow, and it works on the first try for most people, which no other paradigm can say.
Measure and report two numbers: accuracy (fraction of selections correct) and information transfer rateBrain-computer interface (BCI)A system that turns measured brain activity into control of something outside the body, from a cursor to a wheelchair to a speech synthesizer. Glossary entry in bits per minute, which combines accuracy, number of targets, and speed into one figure that lets you compare against the literature. The classification explainer has the formula.
- Set up the LSL pipeline from Phase 2: EEG stream, marker stream, LabRecorder.
- Write the PsychoPy stimulus with four frequencies from the divisors of your refresh rate (6, 7.5, 10, 12 Hz is a good set). Verify the flicker rates with a photodiode on a spare channel; the spectrum of the photodiode channel should show a sharp line at each frequency.
- Record yourself looking at each square for ten seconds in turn. Plot the Oz spectrum for each. The peak should move.
- Implement the CCA decoder and run it offline on the recording with two-second windows. Report accuracy per window.
- Close the loop: decode live, highlight the winning square. Tune the window length for the best speed-accuracy trade for you.
- Build the two-level letter tree. Spell your name. Time it. Compute accuracy and ITR.
- Test on two friends (with the photosensitivity screening and under your lab’s protocol). Note how much the SSVEP amplitude varies between people.