@@ -78,6 +78,7 @@ def __init__(self, dirname='', load_sync_channel=False, load_channel_location=Fa
7878 self .dirname = dirname
7979 self .load_sync_channel = load_sync_channel
8080 self .load_channel_location = load_channel_location
81+ self ._use_direct_evt_timestamps = None
8182
8283 def _source_name (self ):
8384 return self .dirname
@@ -136,6 +137,22 @@ def _parse_header(self):
136137
137138 # No events
138139 event_channels = []
140+ # This is true only in case of 'nidq' stream
141+ for stream_name in stream_names :
142+ if 'nidq' in stream_name :
143+ info = self .signals_info_dict [0 , stream_name ]
144+ if len (info ['digital_channels' ]) > 0 :
145+ # add event channels
146+ for local_chan in info ['digital_channels' ]:
147+ chan_name = local_chan
148+ chan_id = f'{ stream_name } #{ chan_name } '
149+ event_channels .append ((chan_name , chan_id , 'event' ))
150+ # add events_memmap
151+ data = np .memmap (info ['bin_file' ], dtype = 'int16' , mode = 'r' , offset = 0 , order = 'C' )
152+ data = data .reshape (- 1 , info ['num_chan' ])
153+ # The digital word is usually the last channel, after all the individual analog channels
154+ extracted_word = data [:,len (info ['analog_channels' ])]
155+ self ._events_memmap = np .unpackbits (extracted_word .astype (np .uint8 )[:,None ], axis = 1 )
139156 event_channels = np .array (event_channels , dtype = _event_channel_dtype )
140157
141158 # No spikes
@@ -233,6 +250,38 @@ def _get_analogsignal_chunk(self, block_index, seg_index, i_start, i_stop,
233250 raw_signals = memmap [slice (i_start , i_stop ), channel_selection ]
234251
235252 return raw_signals
253+
254+ def _event_count (self , event_channel_idx , block_index = None , seg_index = None ):
255+ timestamps , _ , _ = self ._get_event_timestamps (block_index , seg_index , event_channel_index ,
256+ None , None )
257+ return timestamps .size
258+
259+ def _get_event_timestamps (self , block_index , seg_index , event_channel_index , t_start = None , t_stop = None ):
260+ timestamps , durations , labels = [], None , []
261+ info = self .signals_info_dict [0 , 'nidq' ] # There are no events that are not in the nidq stream
262+ dig_ch = info ['digital_channels' ]
263+ if len (dig_ch ) > 0 :
264+ event_data = self ._events_memmap
265+ channel = dig_ch [event_channel_index ]
266+ ch_idx = 7 - int (channel [2 :]) # They are in the reverse order
267+ this_stream = event_data [:,ch_idx ]
268+ this_rising = np .where (np .diff (this_stream )== 1 )[0 ] + 1
269+ this_falling = np .where (np .diff (this_stream )== - 1 )[0 ] + 1
270+ if len (this_rising ) > 0 :
271+ timestamps .extend (this_rising )
272+ labels .extend ([channel + ' ON' ]* len (this_rising ))
273+ if len (this_falling ) > 0 :
274+ timestamps .extend (this_falling )
275+ labels .extend ([channel + ' OFF' ]* len (this_falling ))
276+ return np .asarray (timestamps ), np .asarray (durations ), np .asarray (labels )
277+
278+ def _rescale_event_timestamp (self , event_timestamps , dtype , event_channel_index ):
279+ info = self .signals_info_dict [0 , 'nidq' ] # There are no events that are not in the nidq stream
280+ if not self ._use_direct_evt_timestamps :
281+ event_times = event_timestamps .astype (dtype ) / float (info ['sampling_rate' ])
282+ else : # Does this ever happen?
283+ event_times = event_timestamps .astype (dtype )
284+ return event_times
236285
237286
238287def scan_files (dirname ):
@@ -452,5 +501,16 @@ def extract_stream_info(meta_file, meta):
452501 info ['channel_gains' ] = channel_gains
453502 info ['channel_offsets' ] = np .zeros (info ['num_chan' ])
454503 info ['has_sync_trace' ] = has_sync_trace
504+
505+ if 'nidq' in device :
506+ info ['digital_channels' ] = []
507+ info ['analog_channels' ] = [channel for channel in info ['channel_names' ] if not channel .startswith ('XD' )]
508+ # Digital/event channels are encoded within the digital word, so that will need more handling
509+ for item in meta ['niXDChans1' ].split (',' ):
510+ if ':' in item :
511+ start , end = map (int , item .split (':' ))
512+ info ['digital_channels' ].extend ([f"XD{ i } " for i in range (start , end + 1 )])
513+ else :
514+ info ['digital_channels' ].append (f"XD{ int (item )} " )
455515
456- return info
516+ return info
0 commit comments