def distort_waveform(self, waveform, length_samples: int=None): if length_samples is not None: extra_samples = length_samples - len(waveform) if extra_samples >= 0: y_sig = np.concatenate([waveform, np.zeros(extra_samples)]) else: y_sig = waveform[:extra_samples] else: y_sig = waveform for filt_id in range(self._num_models): filt = self.get('filter_model_{:02}'.format(filt_id)) if not filt: pass # dict is empty else: model = filt['model'] if not self.cfg_hardware_friendly(): if model == 'high-pass': y_sig = kf.bias_tee_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), **filt['params']) elif model == 'exponential': y_sig = kf.exponential_decay_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), **filt['params']) elif model == 'bounce': y_sig = kf.bounce_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), **filt['params']) else: raise KeyError('Model {} not recognized'.format(model)) else: raise NotImplementedError() y_sig *= self.cfg_gain_correction() return y_sig
def fit_high_pass(self, start_time_fit, end_time_fit): ''' Fits a model for a simple RC high-pass exp(-t/tau), tau = RC to the last trace that was measured (self.waveform). The fit model and result are saved in self.fit_model and self.fit_res, respectively. The new predistortion kernel and information about the fit is stored in self.new_kernel_dict. Args: start_time_fit (float): start of the fitted interval end_time_fit (float): end of the fitted interval ''' self._start_idx = np.argmin(np.abs(self.time_pts - start_time_fit)) self._stop_idx = np.argmin(np.abs(self.time_pts - end_time_fit)) # Prepare the fit model: exponential, where only tau is varied self.fit_model = lmfit.Model(fm.ExpDecayFunc) self.fit_model.set_param_hint('tau', value=end_time_fit - start_time_fit, vary=True) self.fit_model.set_param_hint('offset', value=0, vary=False) self.fit_model.set_param_hint('amplitude', value=1, vary=True) self.fit_model.set_param_hint('n', value=1, vary=False) params = self.fit_model.make_params() # Do the fit fit_res = self.fit_model.fit( data=self.waveform[self._start_idx:self._stop_idx], t=self.time_pts[self._start_idx:self._stop_idx], params=params) self.fitted_waveform = fit_res.eval( t=self.time_pts[self._start_idx:self._stop_idx]) tau = fit_res.best_values['tau'] # Check if parameters are physical and print warnings if not if tau < 0: print('Warning: unphysical tau = {} (expect tau > 0).'.format(tau)) # Save the fit results and predicted correction self.fit_res = fit_res self.predicted_waveform = kf.bias_tee_correction( self.waveform, tau=tau, sampling_rate=self.scope_sampling_rate)
def _update_latest_params(self, json_string): """ Uses a JSON formatted string to update the parameters of the latest fit. For each model does the following 1. update the 'fit' dict 4. calculate the new "fit" 5. Plot the new "fit" Currently only supported for the high-pass and exponential model. """ try: par_dict = json.loads(json_string) except Exception as e: print(e) return # 1. update the 'fit' dict self.fit_res.best_values.update(par_dict) self.fitted_waveform = self.fit_res.eval( t=self.time_pts[self._start_idx:self._stop_idx], tau=self.fit_res.best_values['tau']) if self._fit_model_loop == 'high-pass': self.predicted_waveform = kf.bias_tee_correction( self.waveform, tau=self.fit_res.best_values['tau'], sampling_rate=self.scope_sampling_rate) elif self._fit_model_loop == 'exponential': self.predicted_waveform = kf.exponential_decay_correction( self.waveform, tau=self.fit_res.best_values['tau'], amp=self.fit_res.best_values['amp'], sampling_rate=self.scope_sampling_rate) # The fit results still have to be updated self.plot_fit(self._t_start_loop, self._t_stop_loop, nr_plot_pts=self.cfg_nr_plot_points())
def distort_waveform(self, waveform, length_samples: int = None, inverse: bool = False): """ Distorts a waveform using the models specified in the Kernel Object. Args: waveform (array) : waveform to be distorted lenght_samples (int): number of samples after which to cut of wf inverse (bool) : if True apply the inverse of the waveform. Returns: y_sig (array) : waveform with distortion filters applied N.B. the bounce correction does not have an inverse implemented (June 2018) MAR """ if length_samples is not None: extra_samples = length_samples - len(waveform) if extra_samples >= 0: y_sig = np.concatenate([waveform, np.zeros(extra_samples)]) else: y_sig = waveform[:extra_samples] else: y_sig = waveform # Specific real-time filters are turned on below self.set_realtime_distortions_zero() nr_real_time_exp_models = 0 nr_real_time_hp_models = 0 nr_real_time_bounce_models = 0 for filt_id in range(self._num_models): filt = self.get('filter_model_{:02}'.format(filt_id)) if not filt: pass # dict is empty else: model = filt['model'] if model == 'high-pass': if ('real-time' in filt.keys() and filt['real-time']): # Implementation tested and found not working -MAR raise NotImplementedError() nr_real_time_hp_models += 1 if nr_real_time_hp_models > 1: raise ValueError() else: y_sig = kf.bias_tee_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), inverse=inverse, **filt['params']) elif model == 'exponential': if ('real-time' in filt.keys() and filt['real-time']): AWG = self.instr_AWG.get_instr() AWG.set( 'sigouts_{}_precompensation_exponentials' '_{}_timeconstant'.format( self.cfg_awg_channel() - 1, nr_real_time_exp_models), filt['params']['tau']) AWG.set( 'sigouts_{}_precompensation_exponentials' '_{}_amplitude'.format(self.cfg_awg_channel() - 1, nr_real_time_exp_models), filt['params']['amp']) AWG.set( 'sigouts_{}_precompensation_exponentials' '_{}_enable'.format(self.cfg_awg_channel() - 1, nr_real_time_exp_models), 1) nr_real_time_exp_models += 1 if nr_real_time_exp_models > 5: raise ValueError() else: y_sig = kf.exponential_decay_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), inverse=inverse, **filt['params']) elif model == 'bounce': if ('real-time' in filt.keys() and filt['real-time']): AWG = self.instr_AWG.get_instr() AWG.set( 'sigouts_{}_precompensation_bounces' '_{}_delay'.format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), filt['params']['tau']) AWG.set( 'sigouts_{}_precompensation_bounces' '_{}_amplitude'.format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), filt['params']['amp']) AWG.set( 'sigouts_{}_precompensation_bounces' '_{}_enable'.format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), 1) nr_real_time_bounce_models += 1 if nr_real_time_bounce_models > 1: raise ValueError() else: y_sig = kf.first_order_bounce_corr( sig=y_sig, delay=filt['params']['tau'], amp=filt['params']['amp'], awg_sample_rate=2.4e9) else: raise KeyError('Model {} not recognized'.format(model)) if inverse: y_sig /= self.cfg_gain_correction() else: y_sig *= self.cfg_gain_correction() return y_sig
def distort_waveform(self, waveform, length_samples: int = None, inverse: bool = False): """ Distorts a waveform using the models specified in the Kernel Object. Args: waveform (array) : waveform to be distorted lenght_samples (int): number of samples after which to cut of wf inverse (bool) : if True apply the inverse of the waveform. Return: y_sig (array) : waveform with distortion filters applied N.B. The bounce correction does not have an inverse implemented (June 2018) MAR N.B.2 The real-time FIR also does not have an inverse implemented. (May 2019) MAR N.B.3 the real-time distortions are reset and set on the HDAWG every time a waveform is distorted. This is a suboptimal workflow. """ if length_samples is not None: extra_samples = length_samples - len(waveform) if extra_samples >= 0: y_sig = np.concatenate([waveform, np.zeros(extra_samples)]) else: y_sig = waveform[:extra_samples] else: y_sig = waveform # Specific real-time filters are turned on below self.set_unused_realtime_distortions_zero() nr_real_time_exp_models = 0 nr_real_time_hp_models = 0 nr_real_time_bounce_models = 0 for filt_id in range(self._num_models): filt = self.get("filter_model_{:02}".format(filt_id)) if not filt: pass # dict is empty else: model = filt["model"] AWG = self.instr_AWG.get_instr() if model == "high-pass": if "real-time" in filt.keys() and filt["real-time"]: # Implementation tested and found not working -MAR raise NotImplementedError() nr_real_time_hp_models += 1 if nr_real_time_hp_models > 1: raise ValueError() else: y_sig = kf.bias_tee_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), inverse=inverse, **filt["params"]) elif model == "exponential": if "real-time" in filt.keys() and filt["real-time"]: AWG.set( "sigouts_{}_precompensation_exponentials" "_{}_timeconstant".format( self.cfg_awg_channel() - 1, nr_real_time_exp_models), filt["params"]["tau"], ) AWG.set( "sigouts_{}_precompensation_exponentials" "_{}_amplitude".format(self.cfg_awg_channel() - 1, nr_real_time_exp_models), filt["params"]["amp"], ) AWG.set( "sigouts_{}_precompensation_exponentials" "_{}_enable".format(self.cfg_awg_channel() - 1, nr_real_time_exp_models), 1, ) nr_real_time_exp_models += 1 if nr_real_time_exp_models > 5: raise ValueError() else: y_sig = kf.exponential_decay_correction( y_sig, sampling_rate=self.cfg_sampling_rate(), inverse=inverse, **filt["params"]) elif model == "bounce": if "real-time" in filt.keys() and filt["real-time"]: AWG.set( "sigouts_{}_precompensation_bounces" "_{}_delay".format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), filt["params"]["tau"], ) AWG.set( "sigouts_{}_precompensation_bounces" "_{}_amplitude".format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), filt["params"]["amp"], ) AWG.set( "sigouts_{}_precompensation_bounces" "_{}_enable".format(self.cfg_awg_channel() - 1, nr_real_time_bounce_models), 1, ) nr_real_time_bounce_models += 1 if nr_real_time_bounce_models > 1: raise ValueError() else: y_sig = kf.first_order_bounce_corr( sig=y_sig, delay=filt["params"]["tau"], amp=filt["params"]["amp"], awg_sample_rate=2.4e9, ) elif model == "FIR": fir_filter_coeffs = filt["params"]["weights"] if "real-time" in filt.keys() and filt["real-time"]: if len(fir_filter_coeffs) != 40: raise ValueError( "Realtime FIR filter must contain 40 weights") else: AWG.set( "sigouts_{}_precompensation_fir_coefficients". format(self.cfg_awg_channel() - 1), fir_filter_coeffs, ) AWG.set( "sigouts_{}_precompensation_fir_enable".format( self.cfg_awg_channel() - 1), 1, ) else: if not inverse: y_sig = signal.lfilter(fir_filter_coeffs, 1, y_sig) elif inverse: y_sig = signal.lfilter(np.ones(1), fir_filter_coeffs, y_sig) else: raise KeyError("Model {} not recognized".format(model)) if inverse: y_sig /= self.cfg_gain_correction() else: y_sig *= self.cfg_gain_correction() return y_sig