Add Neuropixels SpikeGLX reader support to NDR#92
Conversation
Implement format functions and reader class for Neuropixels probes acquired with SpikeGLX: Format functions (ndr.format.neuropixelsGLX): - readmeta: Parse .meta key=value files into structs - header: Extract standardized recording parameters (sample rate, channel counts, gains, voltage range, channel subsets) - read: Read interleaved int16 binary data with time/channel subsetting - samples2volts: Convert raw int16 to voltage using per-channel gains Reader class (ndr.reader.neuropixelsGLX): - Handles one probe's AP stream per instance (.ap.bin + .ap.meta) - Neural channels as analog_in (ai1..aiN), sync as digital_in (di1) - Returns raw int16 for efficient storage; use samples2volts for voltage - Supports channel subsets (fewer than 384 channels saved) - Registered in ndr_reader_types.json as neuropixelsGLX/neuropixels/spikeglx/imec Tests: - matlab.unittest parameterized tests (384, 32, 8 channel configs) - Legacy-style test function matching existing NDR test conventions - Synthetic data generation with known values for verification Documentation: - NeuropixelsGLX_format.md covering file layout, naming conventions, binary format, metadata fields, voltage conversion, and design decisions https://claude.ai/code/session_01RMRXufEXExJQUhrnsgrtP2
Use V = int16 * imAiRangeMax / imMaxInt / gain instead of Vrange / (2 * maxInt * gain). Numerically identical for symmetric ranges but matches the official SGLX_readMeta.m convention. https://claude.ai/code/session_01RMRXufEXExJQUhrnsgrtP2
| % See also: ndr.reader.base | ||
| end | ||
|
|
||
| function ec = epochclock(obj, epochstreams, epoch_select) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| % See also: ndr.reader.base | ||
| end | ||
|
|
||
| function ec = epochclock(obj, epochstreams, epoch_select) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| % See also: ndr.reader.base | ||
| end | ||
|
|
||
| function ec = epochclock(obj, epochstreams, epoch_select) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| ec = {ndr.time.clocktype('dev_local_time')}; | ||
| end | ||
|
|
||
| function t0t1 = t0_t1(obj, epochstreams, epoch_select) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| t0t1 = {[0 t_end]}; | ||
| end | ||
|
|
||
| function channels = getchannelsepoch(obj, epochstreams, epoch_select) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| case {'analog_in', 'ai'} | ||
| % Read neural channels (1-based channel numbers map to | ||
| % file columns 1:n_neural_chans) | ||
| [data, ~] = ndr.format.neuropixelsGLX.read(binfile, -Inf, Inf, ... |
Check warning
Code scanning / Code Analyzer
Value assigned to variable might be unused. Consider replacing the variable with ~ instead. Warning
| end | ||
| end | ||
|
|
||
| function sr = samplerate(obj, epochstreams, epoch_select, channeltype, channel) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| end | ||
| end | ||
|
|
||
| function sr = samplerate(obj, epochstreams, epoch_select, channeltype, channel) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
| sr = repmat(info.sample_rate, size(channel)); | ||
| end | ||
|
|
||
| function metafile = filenamefromepochfiles(obj, filename_array) |
Check warning
Code scanning / Code Analyzer
Input argument might be unused. Consider replacing the argument with ~ instead. Warning
Reduce per-channel offset from 100 to 50 so that max test value (383*50+1000=20150) stays within int16 range (32767). Previously channels >= 329 would saturate, causing size mismatches in testReadAllChannels assertions. https://claude.ai/code/session_01RMRXufEXExJQUhrnsgrtP2
Summary
This PR adds comprehensive support for reading Neuropixels data acquired with SpikeGLX software to the Neuroscience Data Reader (NDR) framework. The implementation includes a complete reader class, format handlers, metadata parsing, and extensive unit tests.
Key Changes
New Reader Class (
ndr.reader.neuropixelsGLX): Implements the NDR reader interface for SpikeGLX AP-band binary files, handling channel enumeration, sample rate reporting, data reading, and time management.Format Support Functions:
ndr.format.neuropixelsGLX.readmeta(): Parses SpikeGLX .meta text files into structured datandr.format.neuropixelsGLX.header(): Extracts standardized recording parameters (sample rate, channel counts, voltage ranges, probe info) from metadatandr.format.neuropixelsGLX.read(): Reads interleaved int16 binary data with support for partial channel/time rangesndr.format.neuropixelsGLX.samples2volts(): Converts raw int16 samples to voltage using per-channel gains from imroTblComprehensive Testing:
TestNeuropixelsGLX) covering full 384-channel and subset recordingsDocumentation: Added detailed format specification document explaining SpikeGLX file organization, binary format, metadata fields, and NDR design decisions.
Reader Registration: Updated
ndr_reader_types.jsonto register the new reader with multiple type aliases (neuropixelsGLX, neuropixels, spikeglx, imec).Implementation Details
snsSaveChanSubsetparsinganalog_in(ai1..aiN), sync channel asdigital_in(di1), and computed time astime(t1)ndr.format.binarymatrix.readfor partial file accesssamples2volts()https://claude.ai/code/session_01RMRXufEXExJQUhrnsgrtP2