Skip to content

Electrophysiology rig formats and BIDS sidecars (0.10.0) - #10

Merged
aaronkanzer merged 2 commits into
mainfrom
feat/ephys-bids
Oct 26, 2026
Merged

aaronkanzer merged 2 commits into
mainfrom
feat/ephys-bids

Conversation

@aaronkanzer

Copy link
Copy Markdown
Member

Six new decoders: what an EEG, iEEG or Neuropixels rig writes beside its raw samples, plus the sidecars that describe a dataset organised to the Brain Imaging Data Structure. These are the formats BIDS wraps, so a pipeline that only reads .nii and .nwb sees a session it cannot describe.

Format Extensions Checked against
EDF, EDF+, BDF, BDF+ .edf, .bdf pyedflib, on a PhysioNet Sleep-EDF recording and 6 pyedflib files
BrainVision .vhdr, .vmrk mne, on all 64 non-empty .vhdr files in bids-standard/bids-examples; all 64 agreed
SpikeGLX run metadata .meta neo, on Neuropixels 1.0 and 2.0 files
Neuralynx Cheetah and Pegasus .ncs, .nev, .nse, .ntt, .nvt python-neo's header grammar, four generations
Open Ephys manifest structure.oebin three real manifests, GUI 0.4.4.1 / 0.4.5 / 0.6.0
BIDS sidecars .json, .tsv the whole bids-examples corpus, 5853 files

Notes worth a reviewer's attention:

  • .json and .tsv are now registered extensions. Both are maximally generic, so the BIDS decoders decline anything without a key the standard defines or one of its column signatures. A name-registered decoder (zarr.json, .zattrs, attributes.json) still wins over the extension. tests/test_zarr.py previously asserted that no decoder claimed a generic .json name; it now asserts the stronger thing, that unrelated JSON content decodes to nothing.
  • BIDS key names are kept exactly as the standard spells them (RepetitionTime, not repetitionTime). These are the names the standard, its validator and downstream tools use, and recasing them would make a record impossible to match against the specification.
  • Neuralynx has no public sample that was reachable, so its fixtures are headers built to python-neo's documented per-version grammar and parsed by neo, not copies of a rig's output. README Limitations says so.
  • SpikeGLX microvolts per bit is computed only for the two probe generations the metadata reference defines it for without consulting the probe table; any other probe is left alone rather than guessed at. The 2016 Phase 3A file in the fixture is one neo itself raises on, and this decoder still describes it.

Golden fixtures follow the existing contract (hex in, expected record out) so the Go port can load the same files. Suite is 587 passed, 2 skipped, green on Python 3.9 and 3.12 and on an interpreter with nothing but pytest installed.

Six decoders for what an EEG, iEEG or Neuropixels rig writes beside its
samples, and for the sidecars that describe a BIDS dataset.

- EDF/EDF+/BDF/BDF+: flavour, bit depth, start time resolved from the EDF+
  recording field, patient and recording subfields, record count and
  duration, and per signal label, units, ranges, rate, transducer and
  prefiltering. Checked against pyedflib.
- BrainVision .vhdr and .vmrk: format, orientation, channel table, sampling
  rate, duration, markers by type and the segment timestamp. Checked against
  mne on all 64 non-empty .vhdr files in bids-standard/bids-examples.
- SpikeGLX .meta: the only description a headerless Neuropixels binary has.
  Rate, AP/LF/sync counts, run name with gate and trigger, probe identity,
  derived sample count and microvolts per bit. Checked against neo.
- Neuralynx .ncs/.nev/.nse/.ntt/.nvt: the 16 KiB ASCII header in both
  dialects. Checked against python-neo's header grammar.
- Open Ephys structure.oebin: streams, rates, channel counts and scaling.
- BIDS sidecars under .json and .tsv, content-sniffed so neither generic
  extension is claimed without a key or column signature the standard
  defines. Swept over the whole bids-examples corpus.

Registering .json and .tsv means dispatch now reaches a decoder for those
extensions; a name-registered decoder still wins and non-BIDS content is
declined, which is what tests/test_zarr.py now asserts.
pyedflib refuses to open a file whose samples are absent and PhysioNet
truncated every attempt to download all 48 MB of SC4001E0-PSG.edf, so that
case rests on the header's own redundancy, not on a reference reader. The
other five were checked against pyedflib.
@aaronkanzer
aaronkanzer merged commit d0712ed into main Oct 26, 2026
3 checks passed
@aaronkanzer
aaronkanzer deleted the feat/ephys-bids branch October 26, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant