Bench modeSteps, parts, and safety only. Big type for a phone at the bench.
Phase 1: First contactTool15 min to set up

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.

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.

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 spectrum of one channel, and records to a CSV file you can open in Python.

Web Serial plotter
This interactive needs JavaScript. If you are reading a printout, the caption describes what it shows.
Figure 1. The plotter. Without a board, press Demo to see a simulated three-channel stream at 250 Hz. With one, press Connect.

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 ADC counts, or send microvolts if your firmware 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 EMG 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 spectrum with scipy.signal.welch.

Reading the spectrum panel

The spectrum 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 spike at 60 Hz is hum. A hump around 10 Hz with eyes closed is alpha. Everything else is in the artifact bestiary.

Recall
What is the entire protocol the plotter expects from a board?
One line per sample: numbers separated by commas, newline at the end. Any number of channels.
Recall
Why does the sketch use a microsecond scheduler instead of delay()?
So the sample interval stays fixed regardless of how long Serial.print takes; a wobbling sample rate distorts the spectrum and the timing.