@@ -211,7 +211,7 @@ def __init__(self, filename=None, nsx_override=None, nev_override=None,
211211 '2.1' : self .__read_nev_data_variant_a ,
212212 '2.2' : self .__read_nev_data_variant_a ,
213213 '2.3' : self .__read_nev_data_variant_b ,
214- '3.0' : self .__read_nev_data_variant_b
214+ '3.0' : self .__read_nev_data_variant_c
215215 }
216216 self .__waveform_size = {
217217 '2.1' : self .__get_waveform_size_variant_a ,
@@ -770,12 +770,12 @@ def __extract_nev_file_spec(self):
770770 ('ver_minor' , 'uint8' )]
771771
772772 nev_file_id = np .fromfile (filename , count = 1 , dtype = dt0 )[0 ]
773- if nev_file_id ['file_id' ].decode () == 'NEURALEV' :
773+ if nev_file_id ['file_id' ].decode () in [ 'NEURALEV' , 'BREVENTS' ] :
774774 spec = '{}.{}' .format (
775775 nev_file_id ['ver_major' ], nev_file_id ['ver_minor' ])
776776 else :
777777 raise IOError ('NEV file type {} is not supported' .format (
778- nev_file_id ['file_id' ]))
778+ nev_file_id ['file_id' ]. decode () ))
779779
780780 return spec
781781
@@ -1097,11 +1097,18 @@ def __read_nev_data(self, nev_data_masks, nev_data_types):
10971097 data_size = self .__nev_basic_header ['bytes_in_data_packets' ]
10981098 header_size = self .__nev_basic_header ['bytes_in_headers' ]
10991099
1100+ if self .__nev_basic_header ['ver_major' ] >= 3 :
1101+ ts_format = 'uint64'
1102+ header_skip = 10
1103+ else :
1104+ ts_format = 'uint32'
1105+ header_skip = 6
1106+
11001107 # read all raw data packets and markers
11011108 dt0 = [
1102- ('timestamp' , 'uint32' ),
1109+ ('timestamp' , ts_format ),
11031110 ('packet_id' , 'uint16' ),
1104- ('value' , 'S{}' .format (data_size - 6 ))]
1111+ ('value' , 'S{}' .format (data_size - header_skip ))]
11051112
11061113 raw_data = np .memmap (filename , offset = header_size , dtype = dt0 , mode = 'r' )
11071114
@@ -1136,14 +1143,13 @@ def __get_event_segment_ids(self, raw_event_data, masks, nev_data_masks):
11361143 # No pause or reset mechanism present for file version 2.1 and 2.2
11371144 return np .zeros (len (raw_event_data ), dtype = int )
11381145
1139- elif self .__nev_spec == '2.3' :
1146+ elif self .__nev_spec in [ '2.3' , '3.0' ] :
11401147 reset_ev_mask = self .__get_reset_event_mask (raw_event_data , masks , nev_data_masks )
11411148 reset_ev_ids = np .where (reset_ev_mask )[0 ]
11421149
11431150 # consistency check for monotone increasing time stamps
1144- # explicitly converting to int to allow for negative diff values
1145- jump_ids = \
1146- np .where (np .diff (np .asarray (raw_event_data ['timestamp' ], dtype = int )) < 0 )[0 ] + 1
1151+ # Use logical comparator (instead of np.diff) to avoid unsigned dtype issues.
1152+ jump_ids = np .where (raw_event_data ['timestamp' ][1 :] < raw_event_data ['timestamp' ][:- 1 ])[0 ] + 1
11471153 overlap = np .in1d (jump_ids , reset_ev_ids )
11481154 if not all (overlap ):
11491155 # additional resets occurred without a reset event being stored
@@ -1160,6 +1166,9 @@ def __get_event_segment_ids(self, raw_event_data, masks, nev_data_masks):
11601166 self ._nb_segment_nev = len (reset_ev_ids ) + 1
11611167 return event_segment_ids
11621168
1169+ else :
1170+ raise ValueError ("Unknown File Spec {}" .formate (self .__nev_spec ))
1171+
11631172 def __match_nsx_and_nev_segment_ids (self , nsx_nb ):
11641173 """
11651174 Ensure matching ids of segments detected in nsx and nev file for version 2.3
@@ -1301,6 +1310,30 @@ def __read_nev_data_variant_b(self):
13011310
13021311 return self .__read_nev_data (nev_data_masks , nev_data_types )
13031312
1313+ def __read_nev_data_variant_c (self ):
1314+ """
1315+ Extract nev data from a 3.0 .nev file
1316+ """
1317+ nev_data_masks = {
1318+ 'NonNeural' : 'a' ,
1319+ 'Spikes' : 'b' ,
1320+ 'Comments' : 'a' ,
1321+ 'VideoSync' : 'a' ,
1322+ 'TrackingEvents' : 'a' ,
1323+ 'ButtonTrigger' : 'a' ,
1324+ 'ConfigEvent' : 'a' }
1325+
1326+ nev_data_types = {
1327+ 'NonNeural' : 'c' ,
1328+ 'Spikes' : 'b' ,
1329+ 'Comments' : 'b' ,
1330+ 'VideoSync' : 'b' ,
1331+ 'TrackingEvents' : 'b' ,
1332+ 'ButtonTrigger' : 'b' ,
1333+ 'ConfigEvent' : 'b' }
1334+
1335+ return self .__read_nev_data (nev_data_masks , nev_data_types )
1336+
13041337 def __nev_ext_header_types (self ):
13051338 """
13061339 Defines extended header types for different .nev file specifications.
@@ -1463,30 +1496,61 @@ def __nev_data_types(self, data_size):
14631496 ('analog_input_channel_3' , 'int16' ),
14641497 ('analog_input_channel_4' , 'int16' ),
14651498 ('analog_input_channel_5' , 'int16' ),
1466- ('unused' , 'S{}' .format (data_size - 20 ))],
1467- # Version>=2.3
1499+ ('unused' , 'S{}' .format (data_size - 20 ))
1500+ ],
1501+ # Version=2.3
14681502 'b' : [
14691503 ('timestamp' , 'uint32' ),
14701504 ('packet_id' , 'uint16' ),
14711505 ('packet_insertion_reason' , 'uint8' ),
14721506 ('reserved' , 'uint8' ),
14731507 ('digital_input' , 'uint16' ),
1474- ('unused' , 'S{}' .format (data_size - 10 ))]},
1508+ ('unused' , 'S{}' .format (data_size - 10 ))
1509+ ],
1510+ # Version >= 3.0
1511+ 'c' : [
1512+ ('timestamp' , 'uint64' ),
1513+ ('packet_id' , 'uint16' ),
1514+ ('packet_insertion_reason' , 'uint8' ),
1515+ ('dlen' , 'uint8' ),
1516+ ('digital_input' , 'uint16' ),
1517+ ('unused' , 'S{}' .format (data_size - 14 ))
1518+ ]
1519+ },
14751520 'Spikes' : {
14761521 'a' : [
14771522 ('timestamp' , 'uint32' ),
14781523 ('packet_id' , 'uint16' ),
14791524 ('unit_class_nb' , 'uint8' ),
14801525 ('reserved' , 'uint8' ),
1481- ('waveform' , 'S{}' .format (data_size - 8 ))]},
1526+ ('waveform' , 'S{}' .format (data_size - 8 ))
1527+ ],
1528+ 'b' : [
1529+ ('timestamp' , 'uint64' ),
1530+ ('packet_id' , 'uint16' ),
1531+ ('unit_class_nb' , 'uint8' ),
1532+ ('dlen' , 'uint8' ),
1533+ ('waveform' , 'S{}' .format (data_size - 12 ))
1534+ ]
1535+ },
14821536 'Comments' : {
14831537 'a' : [
14841538 ('timestamp' , 'uint32' ),
14851539 ('packet_id' , 'uint16' ),
14861540 ('char_set' , 'uint8' ),
14871541 ('flag' , 'uint8' ),
14881542 ('color' , 'uint32' ),
1489- ('comment' , 'S{}' .format (data_size - 12 ))]},
1543+ ('comment' , 'S{}' .format (data_size - 12 ))
1544+ ],
1545+ 'b' : [
1546+ ('timestamp' , 'uint64' ),
1547+ ('packet_id' , 'uint16' ),
1548+ ('char_set' , 'uint8' ),
1549+ ('flag' , 'uint8' ),
1550+ ('color' , 'uint32' ),
1551+ ('comment' , 'S{}' .format (data_size - 16 ))
1552+ ]
1553+ },
14901554 'VideoSync' : {
14911555 'a' : [
14921556 ('timestamp' , 'uint32' ),
@@ -1495,7 +1559,18 @@ def __nev_data_types(self, data_size):
14951559 ('video_frame_nb' , 'uint32' ),
14961560 ('video_elapsed_time' , 'uint32' ),
14971561 ('video_source_id' , 'uint32' ),
1498- ('unused' , 'int8' , (data_size - 20 ,))]},
1562+ ('unused' , 'int8' , (data_size - 20 ,))
1563+ ],
1564+ 'b' : [
1565+ ('timestamp' , 'uint64' ),
1566+ ('packet_id' , 'uint16' ),
1567+ ('video_file_nb' , 'uint16' ),
1568+ ('video_frame_nb' , 'uint32' ),
1569+ ('video_elapsed_time' , 'uint32' ),
1570+ ('video_source_id' , 'uint32' ),
1571+ ('unused' , 'int8' , (data_size - 24 ,))
1572+ ]
1573+ },
14991574 'TrackingEvents' : {
15001575 'a' : [
15011576 ('timestamp' , 'uint32' ),
@@ -1504,19 +1579,47 @@ def __nev_data_types(self, data_size):
15041579 ('node_id' , 'uint16' ),
15051580 ('node_count' , 'uint16' ),
15061581 ('point_count' , 'uint16' ),
1507- ('tracking_points' , 'uint16' , ((data_size - 14 ) // 2 ,))]},
1582+ ('tracking_points' , 'uint16' , ((data_size - 14 ) // 2 ,))
1583+ ],
1584+ 'b' : [
1585+ ('timestamp' , 'uint64' ),
1586+ ('packet_id' , 'uint16' ),
1587+ ('parent_id' , 'uint16' ),
1588+ ('node_id' , 'uint16' ),
1589+ ('node_count' , 'uint16' ),
1590+ ('point_count' , 'uint16' ),
1591+ ('tracking_points' , 'uint16' , ((data_size - 18 ) // 2 ,))
1592+ ]
1593+ },
15081594 'ButtonTrigger' : {
15091595 'a' : [
15101596 ('timestamp' , 'uint32' ),
15111597 ('packet_id' , 'uint16' ),
15121598 ('trigger_type' , 'uint16' ),
1513- ('unused' , 'int8' , (data_size - 8 ,))]},
1599+ ('unused' , 'int8' , (data_size - 8 ,))
1600+ ],
1601+ 'b' : [
1602+ ('timestamp' , 'uint64' ),
1603+ ('packet_id' , 'uint16' ),
1604+ ('trigger_type' , 'uint16' ),
1605+ ('unused' , 'int8' , (data_size - 12 ,))
1606+ ]
1607+ },
15141608 'ConfigEvent' : {
15151609 'a' : [
15161610 ('timestamp' , 'uint32' ),
15171611 ('packet_id' , 'uint16' ),
15181612 ('config_change_type' , 'uint16' ),
1519- ('config_changed' , 'S{}' .format (data_size - 8 ))]}}
1613+ ('config_changed' , 'S{}' .format (data_size - 8 ))
1614+ ],
1615+ 'b' : [
1616+ ('timestamp' , 'uint64' ),
1617+ ('packet_id' , 'uint16' ),
1618+ ('config_change_type' , 'uint16' ),
1619+ ('config_changed' , 'S{}' .format (data_size - 12 ))
1620+ ]
1621+ }
1622+ }
15201623
15211624 return __nev_data_types
15221625
0 commit comments