24
24
25
25
import datetime
26
26
from collections import OrderedDict
27
+ import re
27
28
28
29
import numpy as np
29
30
@@ -146,7 +147,7 @@ def _parse_header(self):
146
147
147
148
# Update tqdm with the number of bytes processed in this iteration
148
149
if self .progress_bar :
149
- progress_bar .update (length )
150
+ progress_bar .update (length ) # This was clever, Sam : )
150
151
151
152
if self .progress_bar :
152
153
progress_bar .close ()
@@ -231,6 +232,7 @@ def _parse_header(self):
231
232
# signals channels
232
233
sig_channels = []
233
234
all_sig_length = []
235
+ source_id = []
234
236
if self .progress_bar :
235
237
chan_loop = trange (nb_sig_chan , desc = "Parsing signal channels" , leave = True )
236
238
else :
@@ -242,6 +244,7 @@ def _parse_header(self):
242
244
length = self ._data_blocks [5 ][chan_id ]["size" ].sum () // 2
243
245
if length == 0 :
244
246
continue # channel not added
247
+ source_id .append (h ["SrcId" ])
245
248
all_sig_length .append (length )
246
249
sampling_rate = float (h ["ADFreq" ])
247
250
sig_dtype = "int16"
@@ -255,7 +258,7 @@ def _parse_header(self):
255
258
0.5 * (2 ** global_header ["BitsPerSpikeSample" ]) * h ["Gain" ] * h ["PreampGain" ]
256
259
)
257
260
offset = 0.0
258
- stream_id = "0"
261
+ stream_id = "0" # This is overwritten later
259
262
sig_channels .append ((name , str (chan_id ), sampling_rate , sig_dtype , units , gain , offset , stream_id ))
260
263
261
264
sig_channels = np .array (sig_channels , dtype = _signal_channel_dtype )
@@ -264,22 +267,49 @@ def _parse_header(self):
264
267
signal_streams = np .array ([], dtype = _signal_stream_dtype )
265
268
266
269
else :
267
- # detect groups (aka streams)
268
- all_sig_length = all_sig_length = np .array (all_sig_length )
269
- groups = set (zip (sig_channels ["sampling_rate" ], all_sig_length ))
270
+ # Detect streams
271
+ all_sig_length = np .asarray (all_sig_length )
272
+
273
+ # names are WB{number}, FPX{number}, SPKCX{number}, AI{number}, etc
274
+ pattern = r"^\D+" # Match any non-digit character at the beginning of the string
275
+ channels_prefixes = np .asarray ([re .match (pattern , name ).group (0 ) for name in sig_channels ["name" ]])
276
+ buffer_stream_groups = set (zip (channels_prefixes , sig_channels ["sampling_rate" ], all_sig_length ))
277
+
278
+ # There are explanations of the streams based on channel names
279
+ # provided by a Plexon Engineer, see here:
280
+ # https://github.com/NeuralEnsemble/python-neo/pull/1495#issuecomment-2184256894
281
+ channel_prefix_to_stream_name = {
282
+ "WB" : "WB-Wideband" ,
283
+ "FP" : "FPl-Low Pass Filtered " ,
284
+ "SP" : "SPKC-High Pass Filtered" ,
285
+ "AI" : "AI-Auxiliary Input" ,
286
+ }
287
+
288
+ # Using a mapping to ensure consistent order of stream_index
289
+ channel_prefix_to_stream_id = {
290
+ "WB" : "0" ,
291
+ "FP" : "1" ,
292
+ "SP" : "2" ,
293
+ "AI" : "3" ,
294
+ }
270
295
271
296
signal_streams = []
272
297
self ._signal_length = {}
273
298
self ._sig_sampling_rate = {}
274
- for stream_index , (sr , length ) in enumerate (groups ):
275
- stream_id = str (stream_index )
299
+
300
+ for stream_index , (channel_prefix , sr , length ) in enumerate (buffer_stream_groups ):
301
+ # The users of plexon can modify the prefix of the channel names (e.g. `my_prefix` instead of `WB`). This is not common but in that case
302
+ # We assign the channel_prefix both as stream_name and stream_id
303
+ stream_name = channel_prefix_to_stream_name .get (channel_prefix , channel_prefix )
304
+ stream_id = channel_prefix_to_stream_id .get (channel_prefix , channel_prefix )
305
+
276
306
mask = (sig_channels ["sampling_rate" ] == sr ) & (all_sig_length == length )
277
307
sig_channels ["stream_id" ][mask ] = stream_id
278
308
279
309
self ._sig_sampling_rate [stream_index ] = sr
280
310
self ._signal_length [stream_index ] = length
281
311
282
- signal_streams .append (("Signals " + stream_id , stream_id ))
312
+ signal_streams .append ((stream_name , stream_id ))
283
313
284
314
signal_streams = np .array (signal_streams , dtype = _signal_stream_dtype )
285
315
@@ -363,8 +393,8 @@ def _segment_t_start(self, block_index, seg_index):
363
393
def _segment_t_stop (self , block_index , seg_index ):
364
394
t_stop = float (self ._last_timestamps ) / self ._global_ssampling_rate
365
395
if hasattr (self , "_signal_length" ):
366
- for stream_id in self ._signal_length :
367
- t_stop_sig = self ._signal_length [stream_id ] / self ._sig_sampling_rate [stream_id ]
396
+ for stream_index in self ._signal_length . keys () :
397
+ t_stop_sig = self ._signal_length [stream_index ] / self ._sig_sampling_rate [stream_index ]
368
398
t_stop = max (t_stop , t_stop_sig )
369
399
return t_stop
370
400
0 commit comments