@@ -90,7 +90,10 @@ class IntanRawIO(BaseRawIO):
9090 Examples
9191 --------
9292 >>> import neo.rawio
93+ >>> # for a header-attached file
9394 >>> reader = neo.rawio.IntanRawIO(filename='data.rhd')
95+ >>> # for the other formats we point to the info.rhd
96+ >>> reader = neo.rawioIntanRawIO(filename='info.rhd')
9497 >>> reader.parse_header()
9598 >>> raw_chunk = reader.get_analogsignal_chunk(block_index=0,
9699 seg_index=0
@@ -113,8 +116,8 @@ def _source_name(self):
113116 return self .filename
114117
115118 def _parse_header (self ):
116-
117- self .filename = Path (self .filename )
119+
120+ self .filename = Path (self .filename )
118121
119122 # Input checks
120123 if not self .filename .is_file ():
@@ -201,12 +204,14 @@ def _parse_header(self):
201204 self ._raw_data [stream_index ].append (channel_memmap )
202205
203206 # Data Integrity checks
207+ # strictness of check is controlled by ignore_integrity_checks
208+ # which is set at __init__
204209 self ._assert_timestamp_continuity ()
205210
206211 # signals
207212 signal_channels = []
208213 self .native_channel_order = {}
209- for c , chan_info in enumerate ( self ._ordered_channel_info ) :
214+ for chan_info in self ._ordered_channel_info :
210215 name = chan_info ["custom_channel_name" ]
211216 channel_id = chan_info ["native_channel_name" ]
212217 sig_dtype = chan_info ["dtype" ]
@@ -558,15 +563,47 @@ def _assert_timestamp_continuity(self):
558563 raise NeoReadWriteError (error_msg )
559564
560565
566+ ###################################
567+ # Header reading helper functions
568+
569+
561570def read_qstring (f ):
571+ """
572+ Reads the optional notes included in the Intan RHX software
573+
574+ Parameters
575+ ----------
576+ f: BinaryIO
577+ The file object
578+
579+ Returns
580+ -------
581+ txt: str
582+ The string
583+ """
562584 length = np .fromfile (f , dtype = "uint32" , count = 1 )[0 ]
563585 if length == 0xFFFFFFFF or length == 0 :
564586 return ""
565587 txt = f .read (length ).decode ("utf-16" )
566588 return txt
567589
568590
569- def read_variable_header (f , header ):
591+ def read_variable_header (f , header : list ):
592+ """
593+ Reads the information from the binary file for the header info dict
594+
595+ Parameters
596+ ----------
597+ f: BinaryIO
598+ The file object
599+ header: list[tuple]
600+ The list of header sections along with their associated dtype
601+
602+ Returns
603+ -------
604+ info: dict
605+ The dictionary containing the information contained in the header
606+ """
570607 info = {}
571608 for field_name , field_type in header :
572609 if field_type == "QString" :
@@ -654,7 +691,11 @@ def read_rhs(filename, file_format: str):
654691 with open (filename , mode = "rb" ) as f :
655692 global_info = read_variable_header (f , rhs_global_header )
656693
657- # We use signal_type in the header as stream_id in neo
694+ # We use signal_type in the header as stream_id in neo with the following
695+ # complications: for rhs files in the header-attaached stream_id 0 also
696+ # contains information for stream_id 10 and stream_id 11 so we need to
697+ # break these up. See notes throughout code base; for timestamps we always
698+ # force them to be the last stream_id.
658699 stream_id_to_channel_info_list = {k : [] for k in [0 , 3 , 4 , 5 , 6 ]}
659700 if not file_format == "header-attached" :
660701 # data_dtype for rhs is complicated. There is not 1, 2 (supply and aux),
@@ -667,7 +708,11 @@ def read_rhs(filename, file_format: str):
667708 for c in range (group_info ["channel_num" ]):
668709 chan_info = read_variable_header (f , rhs_signal_channel_header )
669710 if chan_info ["signal_type" ] in (1 , 2 ):
670- raise NeoReadWriteError ("signal_type of 1 or 2 is not yet implemented in Neo" )
711+ error_msg = (
712+ "signal_type of 1 or 2 does not exist for rhs files. If you have an rhs file "
713+ "with these formats open an issue on the python-neo github page"
714+ )
715+ raise NeoReadWriteError (error_msg )
671716 if bool (chan_info ["channel_enabled" ]):
672717 stream_id_to_channel_info_list [chan_info ["signal_type" ]].append (chan_info )
673718
@@ -708,6 +753,7 @@ def read_rhs(filename, file_format: str):
708753
709754 if bool (global_info ["dc_amplifier_data_saved" ]):
710755 # if we have dc amp we need to grab the correct number of channels
756+ # the channel number is the same as the count for amplifier data
711757 channel_number_dict [10 ] = channel_number_dict [0 ]
712758 for chan_info in stream_id_to_channel_info_list [0 ]:
713759 chan_info_dc = dict (chan_info )
@@ -724,6 +770,7 @@ def read_rhs(filename, file_format: str):
724770 data_dtype += [(name + "_DC" , "uint16" , BLOCK_SIZE )]
725771 else :
726772 data_dtype [10 ] = "uint16"
773+
727774 # I can't seem to get stim files to generate for one-file-per-channel
728775 # so let's skip for now and can be given on request
729776
@@ -749,7 +796,9 @@ def read_rhs(filename, file_format: str):
749796 else :
750797 warnings .warn ("Stim not implemented for `one-file-per-channel` due to lack of test files" )
751798
752- # No supply or aux for rhs files (ie no stream 1 and 2)
799+ # No supply or aux for rhs files (ie no stream_id 1 and 2)
800+ # We have an error above that requests test files to help if the spec is changed
801+ # in the future.
753802
754803 # 3: Analog input channel.
755804 # 4: Analog output channel.
@@ -772,7 +821,9 @@ def read_rhs(filename, file_format: str):
772821 for stream_id in [5 , 6 ]:
773822 for chan_info in stream_id_to_channel_info_list [stream_id ]:
774823 chan_info ["sampling_rate" ] = sr
775- chan_info ["units" ] = "a.u." # arbitrary units TTL for logic
824+ # arbitrary units are used to indicate that Intan does not
825+ # store raw voltages but only the boolean TTL state
826+ chan_info ["units" ] = "a.u."
776827 chan_info ["gain" ] = 1.0
777828 chan_info ["offset" ] = 0.0
778829 chan_info ["dtype" ] = "uint16"
@@ -1045,7 +1096,9 @@ def read_rhd(filename, file_format: str):
10451096 for stream_id in [4 , 5 ]:
10461097 for chan_info in stream_id_to_channel_info_list [stream_id ]:
10471098 chan_info ["sampling_rate" ] = sr
1048- chan_info ["units" ] = "a.u." # arbitrary units TTL for logic
1099+ # arbitrary units are used to indicate that Intan does not
1100+ # store raw voltages but only the boolean TTL state
1101+ chan_info ["units" ] = "a.u."
10491102 chan_info ["gain" ] = 1.0
10501103 chan_info ["offset" ] = 0.0
10511104 chan_info ["dtype" ] = "uint16"
@@ -1079,7 +1132,7 @@ def read_rhd(filename, file_format: str):
10791132
10801133
10811134##########################################################################
1082- # RHX Zone for Binary Files
1135+ # RHX Zone for Binary Files (note this is for version 3+ of Intan software)
10831136# This section provides all possible headerless binary files in both the rhs and rhd
10841137# formats.
10851138
0 commit comments