Tool: The Web Serial plotter
Plug an Arduino-class board into this page and see your signal live, with a spectrum, and record it to CSV. Or run the demo without hardware to learn the tool first.
On this page15 min to set up
Every hardware project on this site ends the same way: numbers stream out of a microcontroller over USB and you want to see them. This page is the plotter. It uses the browser’s Web Serial API, so nothing is installed; you plug in a board, click Connect, choose it, and the trace appears. It shows every channel, estimates the sample rate, shows a live spectrumSpectrum A plot of how much of a signal lives at each frequency. Related: Fast Fourier transform (FFT)Fast Fourier transform (FFT) The algorithm that breaks a stretch of signal into the sinusoids that would add up to it, giving amplitude and phase at each frequency. , Power spectral density (PSD)Power spectral density (PSD) The spectrum expressed as power per hertz, the standard way to quantify how strong alpha is. . Glossary entry of one channel, and records to a CSV file you can open in Python.
What the board has to send
One line per sample. Numbers separated by commas. A newline at the end. That is the whole protocol.
512,498
513,499
509,497
Two numbers per line means two channels. Eight means eight. The plotter does not care what the numbers mean; it plots them. Send raw ADCAnalog-to-digital converter (ADC) The chip that measures a voltage at regular instants and turns each into a number. Related: Sampling rateSampling rate How many measurements per second the ADC takes; EEG is usually 250 to 1000 per second. , QuantizationQuantization Rounding each sample to one of a finite set of levels; a 10-bit ADC has 1024 of them, a 24-bit one about 16 million. , Delta-sigma ADCDelta-sigma ADC A converter that samples very fast with a crude 1-bit decision and averages, achieving 24-bit resolution at modest rates; what the ADS1299 uses. . Glossary entry counts, or send microvolts if your firmwareFirmware The program running on the microcontroller, which configures the chip, reads samples on time, and ships them to the computer. Related: SPISPI A simple four-wire bus for talking to chips like the ADS1299 from a microcontroller. . Glossary entry has already scaled them.
The Arduino sketch
Download serial_stream.ino. It reads one or two analog pins at a fixed 250 samples per second using a microsecond scheduler, so the sample rate does not wobble with how long printing takes, and prints them as a line. Change SAMPLE_US for a different rate; 1000 gives 1 kHz, which is what EMGElectromyography (EMG) Recording the electrical activity of muscles, hundreds of microvolts to millivolts, much larger than EEG. Related: Myoelectric prosthesisMyoelectric prosthesis An artificial limb controlled by EMG from the remaining muscles. , Electroencephalography (EEG)Electroencephalography (EEG) Recording the brain's electrical activity from electrodes on the scalp, a few tens of microvolts of blurred, summed cortical activity. . Glossary entry wants. At 1 kHz with two channels, 115200 baud is enough; for eight channels at 1 kHz use 500000.
Browser support
Web Serial exists in Chrome and Edge on Windows, macOS, Linux, and Android. Firefox and Safari do not implement it. If you use one of those, download the Python plotter, which does the same job with pyserial and matplotlib:
pip install pyserial numpy matplotlib
python serial_plot.py /dev/ttyUSB0 250
On Linux you may need to add yourself to the dialout group to open the port. On macOS the port looks like /dev/cu.usbserial-XXXX. On Windows it is COM3 or similar.
Recording
Press Record. Press it again to stop and a CSV downloads with a timestamp column in milliseconds and one column per channel. Open it in Python:
import numpy as np
d = np.loadtxt('recording.csv', delimiter=',', skiprows=1)
t, ch1 = d[:, 0] / 1000, d[:, 1]
fs = 1 / np.median(np.diff(t))
print(f'{len(t)} samples at about {fs:.0f} Hz')
The Python for signals skill page takes it from there: plotting, filtering, and a spectrumSpectrum A plot of how much of a signal lives at each frequency. Related: Fast Fourier transform (FFT)Fast Fourier transform (FFT) The algorithm that breaks a stretch of signal into the sinusoids that would add up to it, giving amplitude and phase at each frequency. , Power spectral density (PSD)Power spectral density (PSD) The spectrum expressed as power per hertz, the standard way to quantify how strong alpha is. . Glossary entry with scipy.signal.welch.
Reading the spectrum panel
The spectrumSpectrum A plot of how much of a signal lives at each frequency. Related: Fast Fourier transform (FFT)Fast Fourier transform (FFT) The algorithm that breaks a stretch of signal into the sinusoids that would add up to it, giving amplitude and phase at each frequency. , Power spectral density (PSD)Power spectral density (PSD) The spectrum expressed as power per hertz, the standard way to quantify how strong alpha is. . Glossary entry is Welch’s estimate over the last two seconds of the selected channel, in decibels. It appears once the plotter has a sample-rate estimate, which takes a second. The horizontal axis stops at half the sample rate or 80 Hz, whichever is lower. A tall spikeSpike Shorthand for an action potential as seen by an electrode, a brief blip about a millisecond wide. Related: Action potentialAction potential The brief, all-or-nothing voltage spike a neuron fires, about a millisecond long and about 100 millivolts tall across its membrane. , Spike sortingSpike sorting Deciding which spikes on an electrode came from which neuron, by clustering their waveform shapes. , Extracellular recordingExtracellular recording Recording with an electrode near neurons rather than inside one; you see small, fast blips from nearby cells rather than the full membrane swing. . Glossary entry at 60 Hz is hum. A hump around 10 Hz with eyes closed is alpha. Everything else is in the artifact bestiary.