20
20
Author: Samuel Garcia
21
21
"""
22
22
23
+ import numpy as np
24
+
25
+ from xml .etree import ElementTree
26
+
23
27
from .baserawio import (
24
28
BaseRawIO ,
25
29
_signal_channel_dtype ,
26
30
_signal_stream_dtype ,
27
31
_spike_channel_dtype ,
28
32
_event_channel_dtype ,
29
33
)
30
-
31
- import numpy as np
32
-
33
- from xml .etree import ElementTree
34
+ from neo .core import NeoReadWriteError
34
35
35
36
36
37
class SpikeGadgetsRawIO (BaseRawIO ):
@@ -79,6 +80,24 @@ def __init__(self, filename="", selected_streams=None):
79
80
def _source_name (self ):
80
81
return self .filename
81
82
83
+ def _produce_ephys_channel_ids (self , n_total_channels , n_channels_per_chip ):
84
+ """Compute the channel ID labels
85
+ The ephys channels in the .rec file are stored in the following order:
86
+ hwChan ID of channel 0 of first chip, hwChan ID of channel 0 of second chip, ..., hwChan ID of channel 0 of Nth chip,
87
+ hwChan ID of channel 1 of first chip, hwChan ID of channel 1 of second chip, ..., hwChan ID of channel 1 of Nth chip,
88
+ ...
89
+ So if there are 32 channels per chip and 128 channels (4 chips), then the channel IDs are:
90
+ 0, 32, 64, 96, 1, 33, 65, 97, ..., 128
91
+ See also: https://github.com/NeuralEnsemble/python-neo/issues/1215
92
+ """
93
+ ephys_channel_ids_list = []
94
+ for hw_channel in range (n_channels_per_chip ):
95
+ hw_channel_list = [
96
+ hw_channel + chip * n_channels_per_chip for chip in range (int (n_total_channels / n_channels_per_chip ))
97
+ ]
98
+ ephys_channel_ids_list .append (hw_channel_list )
99
+ return [channel for channel_list in ephys_channel_ids_list for channel in channel_list ]
100
+
82
101
def _parse_header (self ):
83
102
# parse file until "</Configuration>"
84
103
header_size = None
@@ -104,6 +123,20 @@ def _parse_header(self):
104
123
self ._sampling_rate = float (hconf .attrib ["samplingRate" ])
105
124
num_ephy_channels = int (hconf .attrib ["numChannels" ])
106
125
126
+ # check for agreement with number of channels in xml
127
+ sconf_channels = np .sum ([len (x ) for x in sconf ])
128
+ if sconf_channels < num_ephy_channels :
129
+ num_ephy_channels = sconf_channels
130
+ if sconf_channels > num_ephy_channels :
131
+ raise NeoReadWriteError (
132
+ "SpikeGadgets: the number of channels in the spike configuration is larger than the number of channels in the hardware configuration"
133
+ )
134
+
135
+ try :
136
+ num_chan_per_chip = int (sconf .attrib ["chanPerChip" ])
137
+ except KeyError :
138
+ num_chan_per_chip = 32 # default value for Intan chips
139
+
107
140
# explore sub stream and count packet size
108
141
# first bytes is 0x55
109
142
packet_size = 1
@@ -174,6 +207,7 @@ def _parse_header(self):
174
207
signal_streams .append ((stream_name , stream_id ))
175
208
self ._mask_channels_bytes [stream_id ] = []
176
209
210
+ channel_ids = self ._produce_ephys_channel_ids (num_ephy_channels , num_chan_per_chip )
177
211
chan_ind = 0
178
212
self .is_scaleable = "spikeScalingToUv" in sconf [0 ].attrib
179
213
if not self .is_scaleable :
@@ -190,8 +224,8 @@ def _parse_header(self):
190
224
units = ""
191
225
192
226
for schan in trode :
193
- name = "trode" + trode . attrib [ "id" ] + "chan" + schan . attrib [ "hwChan" ]
194
- chan_id = schan . attrib [ "hwChan" ]
227
+ chan_id = str ( channel_ids [ chan_ind ])
228
+ name = "hwChan" + chan_id
195
229
196
230
offset = 0.0
197
231
signal_channels .append (
0 commit comments