@@ -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