44See:
55https://www.3brain.com/products/single-well/biocam-x
66
7- Author : Alessio Buccino
7+ Authors : Alessio Buccino, Robert Wolff
88"""
99
1010from .baserawio import (BaseRawIO , _signal_channel_dtype , _signal_stream_dtype ,
1111 _spike_channel_dtype , _event_channel_dtype )
1212
1313import numpy as np
14+ import json
1415
1516
1617
@@ -118,51 +119,88 @@ def open_biocam_file_header(filename):
118119 import h5py
119120
120121 rf = h5py .File (filename , 'r' )
121- # Read recording variables
122- rec_vars = rf .require_group ('3BRecInfo/3BRecVars/' )
123- bit_depth = rec_vars ['BitDepth' ][0 ]
124- max_uv = rec_vars ['MaxVolt' ][0 ]
125- min_uv = rec_vars ['MinVolt' ][0 ]
126- n_frames = rec_vars ['NRecFrames' ][0 ]
127- sampling_rate = rec_vars ['SamplingRate' ][0 ]
128- signal_inv = rec_vars ['SignalInversion' ][0 ]
129-
130- # Get the actual number of channels used in the recording
131- file_format = rf ['3BData' ].attrs .get ('Version' , None )
132- format_100 = False
133- if file_format == 100 :
134- n_channels = len (rf ['3BData/Raw' ][0 ])
135- format_100 = True
136- elif file_format in (101 , 102 ) or file_format is None :
137- n_channels = int (rf ['3BData/Raw' ].shape [0 ] / n_frames )
138- else :
139- raise Exception ('Unknown data file format.' )
140-
141- # # get channels
142- channels = rf ['3BRecInfo/3BMeaStreams/Raw/Chs' ][:]
143-
144- # determine correct function to read data
145- if format_100 :
146- if signal_inv == 1 :
147- read_function = readHDF5t_100
148- elif signal_inv == 1 :
149- read_function = readHDF5t_100_i
122+
123+ if '3BRecInfo' in rf .keys (): # brw v3.x
124+ # Read recording variables
125+ rec_vars = rf .require_group ('3BRecInfo/3BRecVars/' )
126+ bit_depth = rec_vars ['BitDepth' ][0 ]
127+ max_uv = rec_vars ['MaxVolt' ][0 ]
128+ min_uv = rec_vars ['MinVolt' ][0 ]
129+ num_frames = rec_vars ['NRecFrames' ][0 ]
130+ sampling_rate = rec_vars ['SamplingRate' ][0 ]
131+ signal_inv = rec_vars ['SignalInversion' ][0 ]
132+
133+ # Get the actual number of channels used in the recording
134+ file_format = rf ['3BData' ].attrs .get ('Version' , None )
135+ format_100 = False
136+ if file_format == 100 :
137+ num_channels = len (rf ['3BData/Raw' ][0 ])
138+ format_100 = True
139+ elif file_format in (101 , 102 ) or file_format is None :
140+ num_channels = int (rf ['3BData/Raw' ].shape [0 ] / num_frames )
150141 else :
151- raise Exception ("Unknown signal inversion" )
152- else :
153- if signal_inv == 1 :
154- read_function = readHDF5t_101
155- elif signal_inv == 1 :
156- read_function = readHDF5t_101_i
142+ raise Exception ('Unknown data file format.' )
143+
144+ # # get channels
145+ channels = rf ['3BRecInfo/3BMeaStreams/Raw/Chs' ][:]
146+
147+ # determine correct function to read data
148+ if format_100 :
149+ if signal_inv == 1 :
150+ read_function = readHDF5t_100
151+ elif signal_inv == 1 :
152+ read_function = readHDF5t_100_i
153+ else :
154+ raise Exception ("Unknown signal inversion" )
157155 else :
158- raise Exception ("Unknown signal inversion" )
159-
160- gain = (max_uv - min_uv ) / (2 ** bit_depth )
161- offset = min_uv
162-
163- return dict (file_handle = rf , num_frames = n_frames , sampling_rate = sampling_rate , num_channels = n_channels ,
164- channels = channels , file_format = file_format , signal_inv = signal_inv ,
165- read_function = read_function , gain = gain , offset = offset )
156+ if signal_inv == 1 :
157+ read_function = readHDF5t_101
158+ elif signal_inv == 1 :
159+ read_function = readHDF5t_101_i
160+ else :
161+ raise Exception ("Unknown signal inversion" )
162+
163+ gain = (max_uv - min_uv ) / (2 ** bit_depth )
164+ offset = min_uv
165+
166+ return dict (file_handle = rf , num_frames = num_frames , sampling_rate = sampling_rate ,
167+ num_channels = num_channels , channels = channels , file_format = file_format ,
168+ signal_inv = signal_inv , read_function = read_function , gain = gain , offset = offset )
169+ else : # brw v4.x
170+ # Read recording variables
171+ experiment_settings = json .JSONDecoder ().decode (rf ['ExperimentSettings' ][0 ].decode ())
172+ max_uv = experiment_settings ['ValueConverter' ]['MaxAnalogValue' ]
173+ min_uv = experiment_settings ['ValueConverter' ]['MinAnalogValue' ]
174+ max_digital = experiment_settings ['ValueConverter' ]['MaxDigitalValue' ]
175+ min_digital = experiment_settings ['ValueConverter' ]['MinDigitalValue' ]
176+ scale_factor = experiment_settings ['ValueConverter' ]['ScaleFactor' ]
177+ sampling_rate = experiment_settings ['TimeConverter' ]['FrameRate' ]
178+
179+ for key in rf :
180+ if key [:5 ] == 'Well_' :
181+ num_channels = len (rf [key ]['StoredChIdxs' ])
182+ if len (rf [key ]['Raw' ]) % num_channels :
183+ raise RuntimeError (
184+ f"Length of raw data array is not multiple of channel number in { key } " )
185+ num_frames = len (rf [key ]['Raw' ]) // num_channels
186+ break
187+ try :
188+ num_channels_x = num_channels_y = int (np .sqrt (num_channels ))
189+ except NameError :
190+ raise RuntimeError ("No Well found in the file" )
191+ if num_channels_x * num_channels_y != num_channels :
192+ raise RuntimeError (
193+ f'Cannot determine structure of the MEA plate with { num_channels } channels' )
194+ channels = 1 + np .concatenate (np .transpose (np .meshgrid (
195+ range (num_channels_x ), range (num_channels_y ))))
196+
197+ gain = scale_factor * (max_uv - min_uv ) / (max_digital - min_digital )
198+ offset = min_uv
199+ read_function = readHDF5t_brw4
200+
201+ return dict (file_handle = rf , num_frames = num_frames , sampling_rate = sampling_rate ,
202+ num_channels = num_channels , channels = channels , read_function = read_function ,
203+ gain = gain , offset = offset )
166204
167205
168206def readHDF5t_100 (rf , t0 , t1 , nch ):
@@ -179,3 +217,9 @@ def readHDF5t_101(rf, t0, t1, nch):
179217
180218def readHDF5t_101_i (rf , t0 , t1 , nch ):
181219 return 4096 - rf ['3BData/Raw' ][nch * t0 :nch * t1 ].reshape ((t1 - t0 , nch ), order = 'C' )
220+
221+
222+ def readHDF5t_brw4 (rf , t0 , t1 , nch ):
223+ for key in rf :
224+ if key [:5 ] == 'Well_' :
225+ return rf [key ]['Raw' ][nch * t0 :nch * t1 ].reshape ((t1 - t0 , nch ), order = 'C' )
0 commit comments