Data hygiene and metadata
A first-look checklist for any recording, EEG-BIDS naming, a QC log, and catching flat, DC-offset and mislabelled channels.
Prerequisites: L0.5 · The artifact atlas
2 claims on this page are unverified. TODO(confirm) marks a specific statement the author has not yet checked against a
primary source. Everything else on this page has been reviewed. Treat a marked claim as
provisional and go to the cited source rather than quoting the sentence.
Objectives
- Run a first-look checklist on any recording
- Adopt EEG-BIDS naming
- Keep a QC log
- Recognize flat, DC-offset and mislabelled channels
Why this matters
Most analyses that go wrong go wrong before the first filter: a channel that was never connected, a header that claims the wrong sampling rate, an event table with overlapping timestamps, a “subject” that is two people or one person twice. None of these is subtle once you look, and all of them are invisible if you do not. This lesson turns the looking into a checklist you run on every file, a naming convention that makes files self-describing, and a log that records what you found and decided. Level 0’s capstone is that checklist applied to real files and written up.
Concepts
The first-look checklist
Run this on every recording before anything else, and write down the answers. Each item has a “what wrong looks like”.
- Sampling rate. Read
info['sfreq'], then verify it: the number of samples divided by the recording duration from an independent source (the file’s timestamps, the event spacing, a known block length). A header that says 500 Hz for data recorded at 250 Hz makes every frequency wrong by a factor of two and every latency wrong by half; it is one of the two planted problems in this lesson’s exercise file. - Channel count and types. How many channels, how many of each type (EEG, EOG, ECG, trigger, misc), and do the labels match the types? An EOG channel typed as EEG will pollute an average reference; an EEG channel typed as misc will silently vanish from every analysis.
- Duration. Does it match the protocol (a one-minute baseline, a three-minute block, sixteen alternating blocks)? A file that is too short lost data; a file that is too long may contain a second run, a restart, or a break.
- Event counts. Count events per code and compare with the design: the expected number of trials per condition, the expected first and last onsets, plausible inter-event intervals. Overlapping or non-monotonic timestamps mean the event stream is corrupt; a code that appears once means a typo or a crash.
- Power spectral density. One PSD per channel, up to the Nyquist frequency: the alpha peak (if eyes were closed), the mains line and harmonics, the hardware roll-off, the noise floor. A channel whose spectrum is flat and white is not EEG; a channel with a huge low-frequency rise is drifting or disconnected.
- Flat channels. Zero (or near-zero) variance over the file. One flat channel is usually the recording reference (
ds-iowapd’s Pz) or a dead contact; several flat channels are a disconnected connector. - DC offsets. A large constant offset on a channel (millivolts, in a DC-coupled recording) means a poor contact or a missing high-pass, and a channel whose offset jumps during the recording had a pop.
Everything here is cheap. The notebook wraps it in a reusable first_look_report() that produces an HTML summary, so that the cost of looking is zero after the first time.
Recognizing flat, DC-offset and mislabelled channels
- Flat: variance at or near zero, or a straight line with only line noise on it. Decide whether it is the reference (expected, keep the knowledge, drop the channel from the montage) or dead (mark bad).
- DC offset: the mean is far from zero and the trace sits off its slot in the viewer; the spectrum has all its power at the lowest frequencies. Not an error in itself in a DC recording, but a warning about the contact.
- Mislabelled: the data contradict the label. A channel called
Fp1that shows no blinks whileO1shows large rounded frontal-looking deflections has had its labels swapped or its cable misrouted; a channel labelled as EEG whose signal is a clean square wave is a trigger line; an “EEG” channel that carries the heartbeat at millivolt scale is the ECG. The check is the topography of things whose topography you know from L0.5: blinks are frontal-polar, alpha is posterior, mu is central. This is the other planted problem in the exercise file.
EEG-BIDS
The Brain Imaging Data Structure extension for EEG (EEG-BIDS, (Pernet et al., 2019) ) fixes where files go and what they are called, so that a dataset describes itself. The pieces you will read and write:
- Folder and file names encode the entities:
sub-01/ses-01/eeg/sub-01_ses-01_task-rest_eeg.edf, withrun-,acq-and other entities where needed.ds-dortmundusesacq-preandacq-postfor the blocks recorded before and after a cognitive battery within one session, which is not the same as its two longitudinal sessions (ses-1,ses-2): a metadata-reading trap the catalog documents. _eeg.jsonsidecar:SamplingFrequency,PowerLineFrequency,EEGReference,EEGGround,SoftwareFilters,HardwareFilters,RecordingDuration,EEGChannelCount, and the task description. Fill it from the amplifier’s settings, not from the converter’s defaults._channels.tsv: one row per channel withname,type,units,status(good or bad) andstatus_description. This is where a QC decision about a channel belongs._events.tsv:onset,duration,trial_type, and any columns you need, with_events.jsondescribing them.participants.tsvanddataset_description.json: who, and what the dataset is, including its license.
Adopting the convention costs an afternoon once and saves it on every subsequent project; more importantly, every tool that reads BIDS (MNE-BIDS, the BIDS validator, pipeline frameworks in L7.8) can then check your files for you.
Provenance and the QC log
A QC log is a plain record, per file, of what the checklist found and what you decided. Minimum content: file identity (dataset, subject, session, run, a checksum), the loader and its version, the header values and the verified values where they differ, channels marked bad and why, segments marked bad and why, subjects excluded and why, and the date. Put decisions where tools can read them (status and status_description in _channels.tsv, annotations in the raw file) and keep the reasoning in the log. The log is what lets you, or a reviewer, answer “why was S088 excluded?” a year later without re-doing the work.
Provenance is the same idea for derived data: every figure and every number should be traceable to the file, the code and the parameters that produced it. On this site, every shipped snippet carries its dataset, subject, run, start time, license and generating script in a sidecar and in data/manifest.json; your own outputs deserve the same.
Real files with real problems
The catalog documents several data-hygiene cases you will meet on this site:
ds-eegbci: subjects S088, S089, S092 and S100 carry inconsistent event timestamps (community-reported; not stated on the PhysioNet page), and S038 and S104 are also often dropped. The event-count check catches the timestamp defect, and in S088’s task run R03 the EDF header also reports 128 Hz where every other run reports 160 Hz, so the sampling-rate check fires too (the dropped-samples pitfall shows both against S001).helpers.load_spineexcludes the four by default and says so.ds-arithmetic: PhysioNet lists N = 36 participants, not the 41 that the file prefixes suggest; counting subjects from file names is a mistake here. ICA was applied upstream, so removed components are unrecoverable.ds-dortmund:preandpostare within-session labels, not the two longitudinal sessions.ds-lemon: subject counts drift between snapshots of the release; report the N you actually loaded.
Every item in the checklist ends in a decision: keep, fix, flag, or exclude. Write the decision and the reason next to the finding. A report that lists a flat channel without saying what you did about it has not finished the job; a pipeline that “handles” it without a log has hidden the job.
Explore
This lesson has no widget. The exploration is the checklist itself, run in the notebook on two files. What to look for, in order:
- the header sampling rate against the rate you compute from samples and duration;
- channel labels against channel content (blinks frontal-polar, alpha posterior, a square wave is a trigger line);
- the event table’s counts, first and last onsets, and whether onsets are monotonic and non-overlapping;
- the per-channel PSD for the alpha peak, the mains line and the hardware roll-off;
- variance per channel, for flat channels and channels with a DC offset that is far from its neighbours.
Practice
Data hygiene and metadata: the first-look checklist as code, an HTML report, and two planted problems nb-0-6-first-look-report
Downloads from ds-eegbci.
The notebook builds first_look_report(), a reusable function that prints and renders as HTML every item of the checklist, then runs it on the two exercise files: a labelled synthetic derivative of ds-eegbci S001R01 with two planted problems (§4.5: synthetic: true, derived_from, modifications), and the real event table of ds-eegbci S088 or S089.
Exercises
Exercise ex-0-6-planted-problems
Multiple selectRun the first-look report on the synthetic ds-eegbci S001R01 derivative. Which two problems were planted in it? Select exactly the problems the report reveals.
Exercise ex-0-6-event-table-defect
Multiple selectThe second file is real: a task run of ds-eegbci S088 (or S089) with its event table. Which checklist items flag its documented defect? Select every item that fires.
Pitfalls
Dropped samples and clock drift
- Symptom
- Events drift relative to the data across the recording.
- Cause
Two mechanisms, often together. Dropped samples: the acquisition buffer overflows (a busy computer, a slow disk, a wireless link) and a block of samples is lost without a gap being written; every later sample is now earlier in the file than it was in time, by the length of the dropped block, and events timestamped by a separate clock no longer match. Clock drift: two devices with their own oscill…
- Detect
- Compare the sample count with the sampling rate times the recorded duration (from an independent clock: the file’s start and end timestamps, or the stimulus log). - Plot the interval between successive periodic events (a fixed-rate stimulus, a clock marker) across the recording: dropped samples show as a jump, drift as a slope. - Look for discontinuities in the data at the moment of a drop: an…
- Fix
- Prevent it at acquisition: hardware triggers on the amplifier’s own clock, adequate buffers, a wired link, and a periodic hardware sync pulse recorded in both streams. - For drift with a known reference (a sync pulse or periodic marker), resample or linearly rescale the event times to the EEG clock; LSL-style recordings store the offsets needed to do it. - For dropped samples that can be locate…
In other tools
In other toolsEEGLAB · FieldTrip — names only
The equivalents of what this lesson does, for a reader who works in another toolbox. Function names only: their own documentation is the place to learn how to call them.
EEGLAB
pop_exportbidsEEG-BIDS plugin
FieldTrip
data2bidsFieldTrip
Names checked 2026-09-18 against EEGLAB 2026.0.0 (plugins at the versions in EEGLAB’s own plugin list) and FieldTrip 20251218.
Reading
- Pernet et al. (2019). EEG-BIDS. unverified