Skip to content

Commit 9afcc15

Browse files
authored
Merge pull request #1524 from h-mayorquin/fix_plexon_streams
Fix-ate plexon signal streams
2 parents 643fedf + 87a79a6 commit 9afcc15

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

neo/rawio/plexonrawio.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import datetime
2626
from collections import OrderedDict
27+
import re
2728

2829
import numpy as np
2930

@@ -146,7 +147,7 @@ def _parse_header(self):
146147

147148
# Update tqdm with the number of bytes processed in this iteration
148149
if self.progress_bar:
149-
progress_bar.update(length)
150+
progress_bar.update(length) # This was clever, Sam : )
150151

151152
if self.progress_bar:
152153
progress_bar.close()
@@ -231,6 +232,7 @@ def _parse_header(self):
231232
# signals channels
232233
sig_channels = []
233234
all_sig_length = []
235+
source_id = []
234236
if self.progress_bar:
235237
chan_loop = trange(nb_sig_chan, desc="Parsing signal channels", leave=True)
236238
else:
@@ -242,6 +244,7 @@ def _parse_header(self):
242244
length = self._data_blocks[5][chan_id]["size"].sum() // 2
243245
if length == 0:
244246
continue # channel not added
247+
source_id.append(h["SrcId"])
245248
all_sig_length.append(length)
246249
sampling_rate = float(h["ADFreq"])
247250
sig_dtype = "int16"
@@ -255,7 +258,7 @@ def _parse_header(self):
255258
0.5 * (2 ** global_header["BitsPerSpikeSample"]) * h["Gain"] * h["PreampGain"]
256259
)
257260
offset = 0.0
258-
stream_id = "0"
261+
stream_id = "0" # This is overwritten later
259262
sig_channels.append((name, str(chan_id), sampling_rate, sig_dtype, units, gain, offset, stream_id))
260263

261264
sig_channels = np.array(sig_channels, dtype=_signal_channel_dtype)
@@ -264,22 +267,49 @@ def _parse_header(self):
264267
signal_streams = np.array([], dtype=_signal_stream_dtype)
265268

266269
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+
}
270295

271296
signal_streams = []
272297
self._signal_length = {}
273298
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+
276306
mask = (sig_channels["sampling_rate"] == sr) & (all_sig_length == length)
277307
sig_channels["stream_id"][mask] = stream_id
278308

279309
self._sig_sampling_rate[stream_index] = sr
280310
self._signal_length[stream_index] = length
281311

282-
signal_streams.append(("Signals " + stream_id, stream_id))
312+
signal_streams.append((stream_name, stream_id))
283313

284314
signal_streams = np.array(signal_streams, dtype=_signal_stream_dtype)
285315

@@ -363,8 +393,8 @@ def _segment_t_start(self, block_index, seg_index):
363393
def _segment_t_stop(self, block_index, seg_index):
364394
t_stop = float(self._last_timestamps) / self._global_ssampling_rate
365395
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]
368398
t_stop = max(t_stop, t_stop_sig)
369399
return t_stop
370400

neo/test/iotest/test_plexonio.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class TestPlexonIO(
1818
"plexon/File_plexon_1.plx",
1919
"plexon/File_plexon_2.plx",
2020
"plexon/File_plexon_3.plx",
21+
"plexon/4chDemoPLX.plx"
2122
]
2223

2324

neo/test/rawiotest/test_plexonrawio.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TestPlexonRawIO(
1515
"plexon/File_plexon_1.plx",
1616
"plexon/File_plexon_2.plx",
1717
"plexon/File_plexon_3.plx",
18+
"plexon/4chDemoPLX.plx"
1819
]
1920

2021

0 commit comments

Comments
 (0)