Skip to content

[Bug] NeuralynxRawIO doesn't differentiate signals per stream #1778

@h-mayorquin

Description

@h-mayorquin

Currently the neuralynx code is creating streams based on the sampling rate, the number of packages and the first package's timestamp:

stream_names = [f"Stream (rate,#packet,t0): {sp}" for sp in stream_props]

In addition of not being user friendly this has caused problems before because it depends on the version of numpy.

A bigger problem with defining and naming streams this way is that it does not correctly differentiate signals of different nature. I have an example session with the following files:

.
├── CSC145.ncs
├── CSC146.ncs
└── csc23_100.ncs

1 directory, 3 files

Two of them are eye tracking and one of them is an extracellular electrophysiology signal. If we check the headers, they have different gains (e.g. InputRange) and signal filtering parameters which matches their nature, but, as I mentioned above, the NeuralynxRawIO is incorrectly identifying the three of them as the same stream. The reason for this is because they share the same sampling frequency, number of records and timestamp of the first block.

Click here for the headers

Command: find . -type f -iname "*.ncs" -exec sh -c 'echo ">>> $1"; head -c 16384 "$1"' _ {} \;
Output:
>>> ./CSC145.ncs ######## Neuralynx Data File Header
 -FileType NCS
 -FileVersion 3.4
 -FileUUID fb4d4862-546b-426e-9af0-db1316e21c12
 -SessionUUID 845b834f-9def-4465-a3be-672ffa54a575
 -ProbeName 
 -OriginalFileName "D:\CheetahData\2024-09-27_08-49-25\CSC145.ncs"
 -TimeCreated 2024/09/27 08:49:53
 -TimeClosed 2024/09/27 15:12:31
 
 -RecordSize 1044
 -ApplicationName Cheetah "6.5.0 "
 -AcquisitionSystem AcqSystem1 DigitalLynxSX
 -ReferenceChannel "Source 05 Panel Ground"
 -SamplingFrequency 32000
 -ADMaxValue 32767
 -ADBitVolts 0.000003051757812500000169
 -AcqEntName CSC145
 -NumADChannels 1
 -ADChannel 144
 -InputRange 100000
 -InputInverted False
 
 -DSPLowCutFilterEnabled False
 -DspLowCutFrequency 0.1
 -DspLowCutNumTaps 0
 -DspLowCutFilterType DCO
 -DSPHighCutFilterEnabled True
 -DspHighCutFrequency 8000
 -DspHighCutNumTaps 256
 -DspHighCutFilterType FIR
 -DspDelayCompensation Enabled
 -DspFilterDelay_�s 3984

  ######## Neuralynx Data File Header
 -FileType NCS
 -FileVersion 3.4
 -FileUUID 9b187ad2-3512-41f3-a618-88da16bbbd10
 -SessionUUID 845b834f-9def-4465-a3be-672ffa54a575
 -ProbeName 
 -OriginalFileName "D:\CheetahData\2024-09-27_08-49-25\CSC76.ncs"
 -TimeCreated 2024/09/27 08:49:53
 -TimeClosed 2024/09/27 15:12:27
 
 -RecordSize 1044
 -ApplicationName Cheetah "6.5.0 "
 -AcquisitionSystem AcqSystem1 DigitalLynxSX
 -ReferenceChannel "Source 01 Reference 1"
 -SamplingFrequency 32000
 -ADMaxValue 32767
 -ADBitVolts 0.000000030517578125000001
 -AcqEntName CSC76
 -NumADChannels 1
 -ADChannel 75
 -InputRange 1000
 -InputInverted False
 
 -DSPLowCutFilterEnabled True
 -DspLowCutFrequency 0.1
 -DspLowCutNumTaps 0
 -DspLowCutFilterType DCO
 -DSPHighCutFilterEnabled True
 -DspHighCutFrequency 8000
 -DspHighCutNumTaps 256
 -DspHighCutFilterType FIR
 -DspDelayCompensation Enabled
 -DspFilterDelay_µs 3984

  ######## Neuralynx Data File Header
 -FileType NCS
 -FileVersion 3.4
 -FileUUID 2a57a2a9-e436-4690-bf99-ac531122b436
 -SessionUUID 845b834f-9def-4465-a3be-672ffa54a575
 -ProbeName 
 -OriginalFileName "D:\CheetahData\2024-09-27_08-49-25\CSC146.ncs"
 -TimeCreated 2024/09/27 08:49:53
 -TimeClosed 2024/09/27 15:12:31
 
 -RecordSize 1044
 -ApplicationName Cheetah "6.5.0 "
 -AcquisitionSystem AcqSystem1 DigitalLynxSX
 -ReferenceChannel "Source 05 Panel Ground"
 -SamplingFrequency 32000
 -ADMaxValue 32767
 -ADBitVolts 0.000003051757812500000169
 -AcqEntName CSC146
 -NumADChannels 1
 -ADChannel 145
 -InputRange 100000
 -InputInverted False
 
 -DSPLowCutFilterEnabled False
 -DspLowCutFrequency 0.1
 -DspLowCutNumTaps 0
 -DspLowCutFilterType DCO
 -DSPHighCutFilterEnabled True
 -DspHighCutFrequency 8000
 -DspHighCutNumTaps 256
 -DspHighCutFilterType FIR
 -DspDelayCompensation Enabled
 -DspFilterDelay_�s 3984
 

I think the reader should separate these signals into different streams. We have the Input Range and filtering information that differentiates them in the headers so we can do this. On top of that, I think we should take this opportunity to fix #1678 and provide a better convention for stream names in this reader.

Thoughts?

Related links:
#1041
#1038

cc @weiglszonja

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions