Bench modeSteps, parts, and safety only. Big type for a phone at the bench.
Phase 3: Read intentProjectA weekend to a month$0 beyond the amplifierTier 2

Project B: The P300 speller

A grid of letters flashes row by row and column by column. The one you are counting produces a bump 300 milliseconds later. Average, classify, and the computer types it. The 1988 design that started the field, built in a weekend.

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.

Look at a six-by-six grid of letters and silently count the flashes of the one you want. Rows and columns flash in random order. Whenever your letter’s row or column flashes, your brain produces a : a positive bump over the top and back of the head about three hundred milliseconds later, because that flash was the rare, meaningful event you were waiting for. Average the responses to each row and each column, find the row and the column with the bump, and their intersection is your letter. Farwell and Donchin built this in 1988. It still works, and building it teaches averaging, classification, and honest evaluation in one project.

Averaging reveals the P300Simulated signal
This interactive needs JavaScript. If you are reading a printout, the caption describes what it shows.
Figure 1. The P300 rising out of noise as trials accumulate. This is the whole mechanism of the speller: the target row's flashes, averaged, have the bump; the other rows' do not.
Predict before you look

A single flash of the target row produces a 5 µV P300 in 20 µV of noise. How many flashes must you average before the P300 is twice the noise?

About 64. Noise shrinks as the square root of the number of trials: after N flashes the noise is 20/√N. For the 5 µV signal to be twice the noise, 20/√N = 2.5, so √N = 8 and N = 64. Real spellers get away with fewer, around 10 to 15 per row, because a classifier can use the whole waveform rather than one peak and because it only needs to rank the six rows, not measure any one cleanly. But the arithmetic is why P300 spellers are slower than SSVEP ones.

The stimulus

A 6×6 grid (26 letters plus digits and a few commands). Each “sequence” flashes all six rows and six columns once each, in random order: 12 flashes, each 100 ms on, 75 ms off, so a sequence takes about two seconds. Repeat 10 to 15 sequences per character. Push an LSL marker at each flash saying which row or column it was. The user counts flashes of their letter; the counting is what makes the P300 large.

The classifier

Epoch from 0 to 800 ms after each flash, at Pz, Cz, PO7, PO8, Oz and a few others. Downsample to about 20 Hz, so each epoch is 16 samples per channel, and concatenate channels into one feature vector. Train a classifier (or the stepwise version, SWLDA, which the original literature uses) on labelled epochs: target flashes versus non-target flashes, from a calibration run in which you spell a known word.

To select a character, apply the classifier to each flash’s epoch to get a score, sum the scores over all sequences for each row and each column, pick the row and column with the largest sums. Summing scores is the averaging, done after classification instead of before.

xDAWN spatial filtering before LDA, or a Riemannian classifier on the epoch covariances, improves things noticeably and is what current systems use. Start with LDA so you can see what the improvement is.

Evaluation

Accuracy per character as a function of the number of sequences; the curve rises and saturates. Information transfer rate at each point, so you can pick the number of sequences that maximizes bits per minute rather than accuracy. And the honest split: train on the calibration word, test on a different word spelled later in the session, then on a different day.

  1. Write the PsychoPy grid with row/column flashing and LSL markers.
  2. Record a calibration run: spell a ten-character word with 15 sequences per character. Epoch and average target versus non-target epochs at Pz. Confirm the P300 is visible in the average; if not, check timing with the photodiode and check that you are actually counting.
  3. Train LDA on the calibration epochs. Cross-validate by character (train on 8 characters, test on 2), not by epoch.
  4. Spell a test word. Plot accuracy and ITR against number of sequences.
  5. Add xDAWN or a Riemannian classifier and repeat. Note the improvement.
  6. Test on another person, on a different day. Report all numbers.
Recall
Why does the user count the target's flashes rather than just look at it?
The P300 is a response to a rare, task-relevant event. Actively counting makes the target flash task-relevant and the P300 larger and more reliable.
Recall
Why is the P300 speller slower than the SSVEP speller?
The P300 is a few microvolts in tens of microvolts of noise and must be averaged over many flashes (noise shrinks as √N), whereas SSVEP is a steady tone detectable in a couple of seconds.
Recall
What is the honest cross-validation split for a P300 speller?
By character (or by spelling run), never by epoch, so that flashes of the same character never appear in both training and test.