def test_gaussian_kernel(): """Test the gaussian kernel. """ ker = gaussian(1111, 200, 50, 10) assert_allclose(np.linalg.norm(ker), 1) assert_equal(ker >= 0., True)
def high_gamma_estimation(block_path, bands_vals, new_file=''): """ Takes preprocessed LFP data and calculates High-Gamma power from the averaged power of standard Hilbert transform on 70~150 Hz bands. Parameters ---------- block_path : str subject file path bands_vals : [2,nBands] numpy array with Gaussian filter parameters, where: bands_vals[0,:] = filter centers [Hz] bands_vals[1,:] = filter sigmas [Hz] new_file : str if this argument is of form 'path/to/new_file.nwb', High Gamma power will be saved in a new file. If it is an empty string, '', High Gamma power will be saved in the current NWB file. Returns ------- Saves High Gamma power (TimeSeries) in the current or new NWB file. Only if container for this data do not exist in the file. """ # Get filter parameters band_param_0 = bands_vals[0, :] band_param_1 = bands_vals[1, :] with NWBHDF5IO(block_path, 'r+', load_namespaces=True) as io: nwb = io.read() lfp = nwb.processing['ecephys'].data_interfaces[ 'LFP'].electrical_series['preprocessed'] rate = lfp.rate nBands = len(band_param_0) nSamples = lfp.data.shape[0] nChannels = lfp.data.shape[1] Xp = np.zeros( (nBands, nChannels, nSamples)) # power (nBands,nChannels,nSamples) # Apply Hilbert transform --------------------------------------------- print('Running High Gamma estimation...') start = time.time() for ch in np.arange(nChannels): Xch = lfp.data[:, ch] * 1e6 # 1e6 scaling helps with numerical accuracy Xch = Xch.reshape(1, -1) Xch = Xch.astype('float32') # signal (nChannels,nSamples) X_fft_h = None for ii, (bp0, bp1) in enumerate(zip(band_param_0, band_param_1)): kernel = gaussian(Xch.shape[-1], rate, bp0, bp1) X_analytic, X_fft_h = hilbert_transform(Xch, rate, kernel, phase=None, X_fft_h=X_fft_h) Xp[ii, ch, :] = abs(X_analytic).astype('float32') print( 'High Gamma estimation finished in {} seconds'.format(time.time() - start)) # data: (ndarray) dims: num_times * num_channels * num_bands Xp = np.swapaxes(Xp, 0, 2) HG = np.mean(Xp, 2) # average of high gamma bands # Storage of High Gamma on NWB file ----------------------------- if new_file == '' or new_file is None: # on current file # make electrodes table nElecs = HG.shape[1] ecephys_module = nwb.processing['ecephys'] # first check for a table among the file's data_interfaces #### if lfp.electrodes.table.name in ecephys_module.data_interfaces: LFP_dynamic_table = ecephys_module.data_interfaces[ lfp.electrodes.table.name] else: # othewise use the electrodes as the table LFP_dynamic_table = nwb.electrodes #### elecs_region = LFP_dynamic_table.create_region( name='electrodes', region=[i for i in range(nChannels)], description='all electrodes') hg = ElectricalSeries(name='high_gamma', data=HG, electrodes=elecs_region, rate=rate, description='') ecephys_module.add_data_interface(hg) io.write(nwb) print('High Gamma power saved in ' + block_path) else: # on new file with NWBHDF5IO(new_file, 'r+', load_namespaces=True) as io_new: nwb_new = io_new.read() # make electrodes table nElecs = HG.shape[1] elecs_region = nwb_new.electrodes.create_region( name='electrodes', region=np.arange(nElecs).tolist(), description='all electrodes') hg = ElectricalSeries(name='high_gamma', data=HG, electrodes=elecs_region, rate=rate, description='') try: # if ecephys module already exists ecephys_module = nwb_new.processing['ecephys'] except: # creates ecephys ProcessingModule ecephys_module = ProcessingModule( name='ecephys', description='Extracellular electrophysiology data.') nwb_new.add_processing_module(ecephys_module) ecephys_module.add_data_interface(hg) io_new.write(nwb_new) print('High Gamma power saved in ' + new_file)
def test_hilbert_return(self): filters = [ gaussian(50, self.rate, 10, 2), hamming(50, self.rate, 10, 15) ] Xh = hilbert_transform(self.X, self.rate, filters) Xh_expected = (np.array( [ [ -0.21311015 - 0.0607549j, 0.19600701 - 0.01539358j, -0.173067 + 0.05698152j, 0.16533213 - 0.11073435j, -0.11528449 + 0.19558509j, -0.01099088 - 0.23956958j, 0.14327258 + 0.17653984j, -0.18458968 - 0.04880616j, 0.13415315 - 0.03647032j, -0.0869473 + 0.04084354j, 0.10334343 - 0.03818917j, -0.12906154 + 0.10043456j, 0.08385944 - 0.19477458j, 0.03056594 + 0.24082505j, -0.15400577 - 0.2042584j, 0.22998364 + 0.10362084j, -0.23235176 + 0.0114163j, 0.18106783 - 0.09160866j, -0.11846912 + 0.12803714j, 0.0616374 - 0.14137947j, -0.00263204 + 0.13730891j, -0.05106666 - 0.10123634j, 0.06800086 + 0.04061233j, -0.04404788 + 0.00171742j, 0.0226942 - 0.0115417j, -0.0187925 + 0.03051893j, -0.01429313 - 0.07107013j, 0.09650135 + 0.07795065j, -0.174921 - 0.01024875j, 0.18714607 - 0.10299498j, -0.12381878 + 0.19594172j, 0.0300773 - 0.22737868j, 0.04435296 + 0.21050902j, -0.08900898 - 0.18207646j, 0.12224477 + 0.15960843j, -0.15896489 - 0.13540482j, 0.19442573 + 0.09691784j, -0.21726567 - 0.04694222j, 0.22820716 - 0.00885319j, -0.22209987 + 0.07472441j, 0.18310959 - 0.13794065j, -0.12027016 + 0.17057613j, 0.06293843 - 0.16911559j, -0.02503065 + 0.15016524j, 0.01000077 - 0.12699406j, -0.0166137 + 0.12012645j, 0.01741438 - 0.1460833j, 0.02050994 + 0.18394571j, -0.09605629 - 0.19316342j, 0.17592968 + 0.14807635j ], [ 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j ] ]), np.array([[ 12.66153466 + 0.j, -8.52937982 + 2.82208427j, 14.7942873 + 7.52162635j, 11.10045364 + 3.52566249j, -4.45306874 + 1.51630448j, -15.9713513 + 6.17519069j, -12.79444213 - 3.10589728j, 7.48901625 + 4.52892871j, -26.31533498 - 14.97259445j, -13.34218938 - 5.91763703j, -6.37207362 - 7.78666016j, 9.73243576 + 0.81983001j, -7.31044034 - 10.82940129j, -13.95317074 + 6.17574407j, -13.04640635 - 4.2499415j, -8.50946101 + 23.85947587j, 3.63491644 + 8.31427148j, 10.54954233 + 5.55684696j, -7.73593253 - 7.06994243j, -3.63069263 - 4.01064809j, -0.58244679 - 0.45476267j, 0.3190497 - 17.87031979j, -16.3983279 + 10.94541315j, -15.21443532 + 3.27680235j, 0.55694424 - 9.41396278j, 0. + 0.j, 0. + 0.j, 0. - 0.j, 0. - 0.j, 0. + 0.j, -0. + 0.j, -0. + 0.j, -0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 0.j, -0. + 0.j, 0. - 0.j, -0. + 0.j, 0. + 0.j, -0. + 0.j, -0. + 0.j, -0. + 0.j, 0. + 0.j, -0. + 0.j, 0. - 0.j, 0. - 0.j, 0. + 0.j, 0. + 0.j, 0. - 0.j ]])) np.testing.assert_almost_equal(Xh[0], Xh_expected[0]) np.testing.assert_almost_equal(Xh[1], Xh_expected[1]) Xh = hilbert_transform(self.X, self.rate) Xh_expected = ( np.array( [ -2.06641947 - 0.01287173j, 0.51412168 - 1.48267793j, 1.09878248 - 0.2770345j, 1.51753214 + 1.04348296j, -1.17911981 + 1.40558571j, 0.14574649 - 1.35839109j, 1.24439672 + 1.55083418j, -1.71511502 + 0.64355861j, 0.08780536 - 1.05022613j, 0.68712687 + 0.47911231j, -0.49986941 + 1.32336045j, -2.4298324 - 0.32441863j, 0.02200754 - 2.43445411j, 0.53061521 - 0.23437869j, 0.25228739 - 1.73350628j, 2.02750313 + 0.27984872j, -0.62058197 + 0.45810456j, 0.55911732 - 0.78389594j, 0.11008321 - 0.06264994j, 0.72111797 - 0.74545203j, 0.38719571 + 0.13653827j, 0.59216716 - 1.05822436j, 1.88259492 + 0.22982255j, 0.45529182 + 1.40341331j, -0.87420952 + 0.45050791j, -0.46801216 - 1.17055015j, 1.41085796 - 1.23975681j, 1.54165835 + 0.78468877j, 0.01297562 + 0.11350984j, 1.75234722 + 0.23771566j, -0.32490902 + 1.84850866j, -0.40531575 - 0.56893904j, 0.2552225 + 0.44197517j, -0.01341803 - 0.68464856j, 0.8537156 + 0.27623658j, 0.43782839 - 0.38555419j, 1.48900852 + 1.13057857j, -0.60367646 + 1.05556027j, -0.04352692 + 0.77890928j, -1.61591018 - 0.01930377j, 0.62662236 - 1.11621127j, -0.04878076 + 0.60438919j, -0.07048588 - 0.4217956j, -0.52055125 + 0.12783525j, -0.3065798 - 1.47275369j, 0.87571683 - 1.19296222j, 2.02126317 - 0.75806081j, 1.38610296 + 1.35508274j, 0.56164995 + 0.43484911j, 0.40738592 + 1.99470883j ]), np.array([[ 12.66153466 + 0.j, -8.52937982 + 2.82208427j, 14.7942873 + 7.52162635j, 11.10045364 + 3.52566249j, -4.45306874 + 1.51630448j, -15.9713513 + 6.17519069j, -12.79444213 - 3.10589728j, 7.48901625 + 4.52892871j, -26.31533498 - 14.97259445j, -13.34218938 - 5.91763703j, -6.37207362 - 7.78666016j, 9.73243576 + 0.81983001j, -7.31044034 - 10.82940129j, -13.95317074 + 6.17574407j, -13.04640635 - 4.2499415j, -8.50946101 + 23.85947587j, 3.63491644 + 8.31427148j, 10.54954233 + 5.55684696j, -7.73593253 - 7.06994243j, -3.63069263 - 4.01064809j, -0.58244679 - 0.45476267j, 0.3190497 - 17.87031979j, -16.3983279 + 10.94541315j, -15.21443532 + 3.27680235j, 0.55694424 - 9.41396278j, 0. + 0.j, 0. + 0.j, 0. - 0.j, 0. - 0.j, 0. + 0.j, -0. + 0.j, -0. + 0.j, -0. + 0.j, 0. + 0.j, 0. + 0.j, 0. - 0.j, -0. + 0.j, 0. - 0.j, -0. + 0.j, 0. + 0.j, -0. + 0.j, -0. + 0.j, -0. + 0.j, 0. + 0.j, -0. + 0.j, 0. - 0.j, 0. - 0.j, 0. + 0.j, 0. + 0.j, 0. - 0.j ]])) np.testing.assert_almost_equal(Xh[0], Xh_expected[0]) np.testing.assert_almost_equal(Xh[1], Xh_expected[1])
def spectral_decomposition(block_path, bands_vals): """ Takes preprocessed LFP data and does the standard Hilbert transform on different bands. Takes about 20 minutes to run on 1 10-min block. Parameters ---------- block_path : str subject file path bands_vals : [2,nBands] numpy array with Gaussian filter parameters, where: bands_vals[0,:] = filter centers [Hz] bands_vals[1,:] = filter sigmas [Hz] Returns ------- Saves spectral power (DecompositionSeries) in the current NWB file. Only if container for this data do not exist in the file. """ # Get filter parameters band_param_0 = bands_vals[0, :] band_param_1 = bands_vals[1, :] with NWBHDF5IO(block_path, 'r+', load_namespaces=True) as io: nwb = io.read() lfp = nwb.processing['ecephys'].data_interfaces[ 'LFP'].electrical_series['preprocessed'] rate = lfp.rate nBands = len(band_param_0) nSamples = lfp.data.shape[0] nChannels = lfp.data.shape[1] Xp = np.zeros( (nBands, nChannels, nSamples)) # power (nBands,nChannels,nSamples) # Apply Hilbert transform --------------------------------------------- print('Running Spectral Decomposition...') start = time.time() for ch in np.arange(nChannels): Xch = lfp.data[:, ch] * 1e6 # 1e6 scaling helps with numerical accuracy Xch = Xch.reshape(1, -1) Xch = Xch.astype('float32') # signal (nChannels,nSamples) X_fft_h = None for ii, (bp0, bp1) in enumerate(zip(band_param_0, band_param_1)): kernel = gaussian(Xch.shape[-1], rate, bp0, bp1) X_analytic, X_fft_h = hilbert_transform(Xch, rate, kernel, phase=None, X_fft_h=X_fft_h) Xp[ii, ch, :] = abs(X_analytic).astype('float32') print('Spectral Decomposition finished in {} seconds'.format( time.time() - start)) # data: (ndarray) dims: num_times * num_channels * num_bands Xp = np.swapaxes(Xp, 0, 2) # Spectral band power # bands: (DynamicTable) frequency bands that signal was decomposed into band_param_0V = VectorData( name='filter_param_0', description='frequencies for bandpass filters', data=band_param_0) band_param_1V = VectorData( name='filter_param_1', description='frequencies for bandpass filters', data=band_param_1) bandsTable = DynamicTable( name='bands', description='Series of filters used for Hilbert transform.', columns=[band_param_0V, band_param_1V], colnames=['filter_param_0', 'filter_param_1']) decs = DecompositionSeries( name='DecompositionSeries', data=Xp, description='Analytic amplitude estimated with Hilbert transform.', metric='amplitude', unit='V', bands=bandsTable, rate=rate, source_timeseries=lfp) # Storage of spectral decomposition on NWB file ------------------------ ecephys_module = nwb.processing['ecephys'] ecephys_module.add_data_interface(decs) io.write(nwb) print('Spectral decomposition saved in ' + block_path)