Skip to content

Commit 088580f

Browse files
committed
Minimum working example
1 parent 0b73a67 commit 088580f

File tree

1 file changed

+58
-15
lines changed

1 file changed

+58
-15
lines changed

neo/rawio/spikeglxrawio.py

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def _get_event_timestamps(self, block_index, seg_index, event_channel_index, t_s
297297
dig_ch = info["digital_channels"]
298298
if len(dig_ch) > 0:
299299
event_data = self._events_memmap
300-
channel = dig_ch[event_channel_index]
300+
channel = dig_ch[event_channel_index] # 'XD0', 'XD1', etc.
301301
ch_idx = 7 - int(channel[2:]) # They are in the reverse order
302302
this_stream = event_data[:, ch_idx]
303303
timestamps, durations, labels = self._find_events_in_channel(this_stream, channel)
@@ -309,18 +309,59 @@ def _get_event_timestamps(self, block_index, seg_index, event_channel_index, t_s
309309

310310
return timestamps, durations, labels
311311

312-
def _get_sync_events(self, stream_index):
313-
#find sync events in the 'SY0' channel of imec streams
314-
channel = 'SY0'
315-
sync_data = self.get_analogsignal_chunk(channel_names = [channel], stream_index = stream_index)
316-
#uint16 word to uint8 bytes to bits
317-
sync_data_uint8 = sync_data.view(np.uint8)
318-
unpacked_sync_data = np.unpackbits(sync_data_uint8, axis=1)
319-
#sync line is the 6th bit (so 1st bit because reversed order)
320-
#https://billkarsh.github.io/SpikeGLX/Sgl_help/Metadata_30.html
321-
sync_line = unpacked_sync_data[:,1]
322-
raise NotImplementedError("Work in progress")
323-
return self._find_events_in_channel(sync_line, "SY0")
312+
def _get_sync_events(self, stream_index, seg_index = 0):
313+
'''
314+
Find sync events in the stream.
315+
For imec streams, the sync events are found in the 'SY0' channel,
316+
which should be the 6th bit in the last 'analog' channel in the stream.
317+
For nidq streams, the sync events are found in the channel specified by the metadata fields
318+
'syncNiChanType' and 'syncNiChan'.
319+
320+
Meta file descriptions taken from:
321+
https://billkarsh.github.io/SpikeGLX/Sgl_help/Metadata_30.html
322+
323+
Returns timestamps, durations, labels of rising or falling edges in these channels
324+
'''
325+
326+
stream_name = self.header["signal_streams"][stream_index]["name"]
327+
info = self.signals_info_dict[seg_index, stream_name]
328+
329+
if 'imec' in stream_name:
330+
if not self.load_sync_channel:
331+
raise ValueError("SYNC channel was not loaded. Try setting load_sync_channel=True")
332+
if not info["has_sync_trace"]:
333+
raise ValueError("SYNC channel is not present in the recording."
334+
" Cannot find sync events based on metadata field 'snsApLfSy'")
335+
336+
#find sync events in the 'SY0' channel of imec streams
337+
channel = 'SY0'
338+
sync_data = self.get_analogsignal_chunk(channel_names = [channel],
339+
stream_index = stream_index,
340+
seg_index = seg_index)
341+
#uint16 word to uint8 bytes to bits
342+
sync_data_uint8 = sync_data.view(np.uint8)
343+
unpacked_sync_data = np.unpackbits(sync_data_uint8, axis=1)
344+
sync_line = unpacked_sync_data[:,1]
345+
return self._find_events_in_channel(sync_line, channel)
346+
elif 'nidq' in self.header['signal_streams'][stream_index]['name']:
347+
#find channel from metafile
348+
meta = info['meta']
349+
niChanType = int(meta['syncNiChanType'])
350+
niChan = int(meta['syncNiChan'])
351+
if niChanType == 0: #digital channel
352+
return self._get_event_timestamps(0, seg_index, niChan)
353+
elif niChanType == 1: #analog channel
354+
niThresh = float(meta['syncNiThresh']) #volts
355+
sync_line = self.get_analogsignal_chunk(channel_names = [f'XA{niChan}'],
356+
stream_index = stream_index,
357+
seg_index = seg_index)
358+
#Does this need to be scaled by channel gain before threshold?
359+
sync_line = sync_line > niThresh
360+
raise NotImplementedError("Analog sync events not yet implemented")
361+
return self._find_events_in_channel(sync_line, f'XA{niChan}')
362+
else:
363+
raise ValueError("Unknown stream type, cannot find sync events")
364+
324365

325366
def _find_events_in_channel(self, channel_data, channel_name):
326367

@@ -343,8 +384,10 @@ def _find_events_in_channel(self, channel_data, channel_name):
343384
labels = np.asarray(labels)
344385
return timestamps, durations, labels
345386

346-
def _rescale_event_timestamp(self, event_timestamps, dtype, event_channel_index):
347-
info = self.signals_info_dict[0, "nidq"] # There are no events that are not in the nidq stream
387+
def _rescale_event_timestamp(self, event_timestamps, dtype=np.float64, event_channel_index=0,
388+
stream_index = 0):
389+
stream_name = self.header["signal_streams"][stream_index]["name"]
390+
info = self.signals_info_dict[0, stream_name] # get sampling rate from first segment
348391
event_times = event_timestamps.astype(dtype) / float(info["sampling_rate"])
349392
return event_times
350393

0 commit comments

Comments
 (0)