def test(self, pixel_ind=[0, 0]): """ Test the Pixel analysis of a single pixel :param pixel_ind: Index of the pixel in the dataset that the process needs to be tested on. If a list it is read as [row, column] :type pixel_ind: uint or list :returns: List [inst_freq, tfp, shift] WHERE array inst_freq is the instantaneous frequency array for that pixel float tfp is the time to first peak float shift the frequency shift at time t=tfp (i.e. maximum frequency shift) """ # First read the HDF5 dataset to get the deflection for this pixel if type(pixel_ind) is not list: col = int(pixel_ind % self.parm_dict['num_rows']) row = int(np.floor(pixel_ind % self.parm_dict['num_rows'])) pixel_ind = [row, col] # as an array, not an ffta.Pixel defl = get_utils.get_pixel(self.h5_main, pixel_ind, array_form=True) pix = Pixel(defl, self.parm_dict, **self.pixel_params) tfp, shift, inst_freq = pix.analyze() pix.plot() return self._map_function(defl, self.parm_dict, self.pixel_params, self.impulse)
def analyze_pixel(ibw_file, param_file): ''' Analyzes a single pixel Parameters ---------- ibw_file : str path to \*.ibw file param_file : str path to parameters.cfg file Returns ------- pixel : Pixel The pixel object read and analyzed ''' signal_array = signal(ibw_file) n_pixels, params = configuration(param_file) pixel = Pixel(signal_array, params=params) pixel.analyze() pixel.plot() plt.xlabel('Time Step') plt.ylabel('Freq Shift (Hz)') print('tFP is', pixel.tfp, 's') return pixel.tfp
def _map_function(defl, *args, **kwargs): parm_dict = args[0] pixel_params = args[1] pix = Pixel(defl, parm_dict, **pixel_params) if parm_dict['if_only']: inst_freq, _, _ = pix.generate_inst_freq() tfp = 0 shift = 0 amplitude = 0 phase = 0 pwr_diss = 0 else: tfp, shift, inst_freq = pix.analyze() pix.calculate_power_dissipation() amplitude = pix.amplitude phase = pix.phase pwr_diss = pix.power_dissipated return [inst_freq, amplitude, phase, tfp, shift, pwr_diss]
def get_pixel(h5_path, rc, params={}, pixel_params={}, array_form=False, avg=False, transpose=False): """ Gets a pixel of data, returns all the averages within that pixel Returns a specific key if requested Supplying a direct link to a Dataset is MUCH faster than just the file Note that you should supply the deflection data, not instantaneous_frequency Parameters ---------- h5_path : str or h5py or Dataset Can pass either an h5_path to a file or a file already in use or specific Dataset Again, should pass the deflection data (Rebuilt_Data, or FF_Avg) rc : list [r, c] Pixel location in terms of ROW, COLUMN params: dict If explicitly changing parameters (to test a feature), you can pass any subset and this will overwrite it e.g. parameters = {'drive_freq': 10} will extract the Pixel, then change Pixel.drive_freq = 10 pixel_params : dict, optional Parameters 'fit', 'pycroscopy', 'method', 'fit_form' See ffta.pixel for details. 'pycroscopy' is set to True in this function array_form : bool, optional Returns the raw array contents rather than Pixel class avg : bool, optional Averages the pixels of n_pnts_per_pixel and then creates Pixel of that transpose : bool, optional For legacy FFtrEFM code, pixel is required in (n_points, n_signals) format Returns ------- signal_pixel : 1D numpy array, iff array_form == True Ndarray of the (n_points) in specific pixel pixel_inst : Pixel, iff array_form == False Line class containing the signal_array object and parameters """ # If not a dataset, then find the associated Group if 'Dataset' not in str(type(h5_path)): p = get_params(h5_path) h5_file = px.io.HDFwriter(h5_path).file d = usid.hdf_utils.find_dataset(h5_file, 'FF_Raw')[0] c = p['num_cols'] pnts = int(p['pnts_per_pixel']) parameters = usid.hdf_utils.get_attributes(d.parent) else: d = h5_path[()] parameters = get_params(h5_path) c = parameters['num_cols'] pnts = parameters['pnts_per_pixel'] signal_pixel = d[rc[0] * c + rc[1]:rc[0] * c + rc[1] + pnts, :] if avg == True: signal_pixel = signal_pixel.mean(axis=0) if transpose == True: # this does nothing is avg==True signal_pixel = signal_pixel.transpose() if array_form == True: return signal_pixel if signal_pixel.shape[0] == 1: signal_pixel = np.reshape(signal_pixel, [signal_pixel.shape[1]]) if any(params): for key, val in params.items(): parameters[key] = val pixel_params.update({'pycroscopy': True}) # must be True in this specific case # pixel_inst = Pixel(signal_pixel, parameters, pycroscopy=True) pixel_inst = Pixel(signal_pixel, parameters, **pixel_params) return pixel_inst
def get_pixel(h5_path, rc, params={}, pixel_params={}, array_form=False, avg=False, transpose=False): """ Gets a pixel of data, returns all the averages within that pixel Returns a specific key if requested Supplying a direct link to a Dataset is MUCH faster than just the file Note that you should supply the deflection data, not instantaneous_frequency :param h5_path: Can pass either an h5_path to a file or a file already in use or specific Dataset Again, should pass the deflection data (Rebuilt_Data, or FF_Avg) :type h5_path: str or h5py or Dataset :param rc: Pixel location in terms of ROW, COLUMN :type rc: list [r, c] :param params: If explicitly changing parameters (to test a feature), you can pass any subset and this will overwrite it e.g. parameters = {'drive_freq': 10} will extract the Pixel, then change Pixel.drive_freq = 10 :type params: dict :param pixel_params: Parameters 'fit', 'pycroscopy', 'method', 'fit_form' See ffta.pixel for details. 'pycroscopy' is set to True in this function :type pixel_params: dict, optional :param array_form: Returns the raw array contents rather than Pixel class :type array_form: bool, optional :param avg: Averages the pixels of n_pnts_per_pixel and then creates Pixel of that :type avg: bool, optional :param transpose: For legacy FFtrEFM code, pixel is required in (n_points, n_signals) format :type transpose: bool, optional :returns: 2D numpy array signal_line iff array_form == True, contains hte line OR Line line_inst iff array_form == False, contains signal_array object and parameters """ # If not a dataset, then find the associated Group if 'Dataset' not in str(type(h5_path)): p = get_params(h5_path) h5_file = h5py.File(h5_path) d = usid.hdf_utils.find_dataset(h5_file, 'FF_Raw')[0] r = p['num_rows'] c = p['num_cols'] pnts = int(p['pnts_per_pixel']) parameters = usid.hdf_utils.get_attributes(d.parent) else: d = h5_path[()] parameters = get_params(h5_path) r = parameters['num_rows'] c = parameters['num_cols'] pnts = parameters['pnts_per_pixel'] if rc[1] > c or rc[0] > r: err = 'row and columns must be less than ' + str(r) + ' X ' + str(c) raise ValueError(err) signal_pixel = d[rc[0] * c + rc[1]:rc[0] * c + rc[1] + pnts, :] if avg == True: signal_pixel = signal_pixel.mean(axis=0) if transpose == True: # this does nothing is avg==True signal_pixel = signal_pixel.transpose() if array_form == True: return signal_pixel if signal_pixel.shape[0] == 1: signal_pixel = np.reshape(signal_pixel, [signal_pixel.shape[1]]) if any(params): for key, val in params.items(): parameters[key] = val pixel_params.update({'pycroscopy': True}) # must be True in this specific case # pixel_inst = Pixel(signal_pixel, parameters, pycroscopy=True) pixel_inst = Pixel(signal_pixel, parameters, **pixel_params) return pixel_inst
def _map_function(defl, *args, **kwargs): """ :param defl: :type defl: :param args: :type args: :param kwargs: :type kwargs: :returns: List [inst_freq, amplitude, phase, tfp, shift, pwr_diss] WHERE [type] inst_freq is... [type] amplitude is... [type] phase is... [type] tfp is... [type] shift is... [type] pwr_diss is... """ parm_dict = args[0] pixel_params = args[1] impulse = args[2] pix = Pixel(defl, parm_dict, **pixel_params) if parm_dict['if_only']: inst_freq, _, _ = pix.generate_inst_freq() tfp = 0 shift = 0 amplitude = 0 phase = 0 pwr_diss = 0 elif parm_dict['deconvolve']: iterations = parm_dict['conv_iterations'] impulse = impulse[ parm_dict['impulse_window'][0]:parm_dict['impulse_window'][1]] inst_freq, amplitude, phase = pix.generate_inst_freq() conv = restoration.richardson_lucy(inst_freq, impulse, clip=False, num_iter=iterations) pix.inst_freq = conv pix.find_tfp() tfp = pix.tfp shift = pix.shift pix.calculate_power_dissipation() pwr_diss = pix.power_dissipated else: tfp, shift, inst_freq = pix.analyze() pix.calculate_power_dissipation() amplitude = pix.amplitude phase = pix.phase pwr_diss = pix.power_dissipated return [inst_freq, amplitude, phase, tfp, shift, pwr_diss]
def test_deconv(self, window, pixel_ind=[0, 0], iterations=10): """ Tests the deconvolution by bracketing the impulse around window A reasonable window size might be 100 us pre-trigger to 500 us post-trigger :param window: List of format [left_index, right_index] for impulse :type window: list :param pixel_ind: Index of the pixel in the dataset that the process needs to be tested on. If a list it is read as [row, column] :type pixel_ind: uint or list :param iterations: Number of Richardson-Lucy deconvolution iterations :type iterations: int """ if len(window) != 2 or not isinstance(window, list): raise ValueError('window must be specified[left, right]') if isinstance(window[0], float): # passed a time index window = np.array(window) / self.parm_dict['sampling_rate'] window = int(window) if type(pixel_ind) is not list: col = int(pixel_ind % self.parm_dict['num_rows']) row = int(np.floor(pixel_ind % self.parm_dict['num_rows'])) pixel_ind = [row, col] # as an array, not an ffta.Pixel defl = get_utils.get_pixel(self.h5_main, pixel_ind, array_form=True) pixraw = Pixel(defl, self.parm_dict, **self.pixel_params) tfp, shift, inst_freq = pixraw.analyze() impulse = self.impulse[window[0]:window[1]] self.parm_dict['impulse_window'] = window self.parm_dict['conv_iterations'] = iterations pixconv = restoration.richardson_lucy(inst_freq, impulse, clip=False, num_iter=iterations) pixrl = pixraw tfp_raw = pixraw.tfp fit_raw = pixraw.best_fit if_raw = pixraw.inst_freq pixrl.inst_freq = pixconv pixrl.find_tfp() tfp_conv = pixrl.tfp fit_conv = pixrl.best_fit if_conv = pixrl.inst_freq print(tfp_raw, tfp_conv) # Plot the results of the original+fit compared to deconvolution+fit ridx = int(self.parm_dict['roi'] * self.parm_dict['sampling_rate']) fidx = int(pixraw.tidx) ifx = np.array([fidx - 1100, fidx + ridx ]) * 1e3 / self.parm_dict['sampling_rate'] windx = np.array(window) * 1e3 / self.parm_dict['sampling_rate'] yl0 = [ if_raw[fidx:(fidx + ridx)].min(), if_raw[fidx:(fidx + ridx)].max() ] yl1 = [ if_conv[fidx:(fidx + ridx)].min(), if_conv[fidx:(fidx + ridx)].max() ] yl2 = [ self.impulse[fidx:(fidx + ridx)].min(), self.impulse[fidx:(fidx + ridx)].max() ] fig, ax = plt.subplots(nrows=2, ncols=2, facecolor='white', figsize=(12, 8)) tx = np.arange(0, pixraw.total_time, 1 / pixraw.sampling_rate) * 1e3 ax[0][0].plot(tx, if_raw, 'b', label='Pre-Conv') ax[0][0].plot(tx[fidx:(fidx + ridx)], fit_raw, 'r--', label='Pre-Conv, fit') ax[0][0].set_title('Raw') ax[1][0].plot(tx, if_conv, 'b', label='Conv') ax[1][0].plot(tx[fidx:(fidx + ridx)], fit_conv, 'r--', label='Conv, fit') ax[1][0].set_title('Deconvolved') ax[0][1].plot(tx, self.impulse, 'k') ax[0][1].axvspan(windx[0], windx[1], alpha=0.5, color='red') ax[0][1].set_title('Impulse response') ax[1][1].plot(tx[fidx:(fidx + ridx)], fit_raw, 'r--', label='Pre-Conv, fit') ax[1][1].plot(tx[fidx:(fidx + ridx)], fit_conv, 'k--', label='Conv, fit') ax[1][1].set_title('Comparing fits') ax[1][1].legend() ax[0][0].set_xlim(ifx) ax[0][0].set_ylim(yl0) ax[1][0].set_xlim(ifx) ax[1][0].set_ylim(yl1) ax[0][1].set_xlim(ifx) ax[0][1].set_ylim(yl2) ax[1][1].set_xlim(ifx) ax[1][0].set_xlabel('Time (ms)') ax[1][1].set_xlabel('Time (ms)') plt.tight_layout() return pixrl