def test_first_order_bounce_correction(self): hw_corr = ZI_kf.first_order_bounce_corr(self.distorted_waveform, self.bounce_delay, self.bounce_amp, self.sampling_rate) ainv1 = ZI_kf.first_order_bounce_kern(self.bounce_delay, -self.bounce_amp, self.sampling_rate) first_order_corr = signal.lfilter(ainv1, 1, self.distorted_waveform) np.testing.assert_almost_equal(hw_corr, first_order_corr, 4)
def test_first_order_bounce_correction(self): hw_corr = ZI_kf.first_order_bounce_corr(self.distorted_waveform, self.bounce_delay, self.bounce_amp, self.sampling_rate) b = ZI_kf.first_order_bounce_kern( self.bounce_delay, ZI_kf.coef_round(self.bounce_amp, force_bshift=0), self.sampling_rate) first_order_corr = signal.lfilter(b, 1.0, self.distorted_waveform) np.testing.assert_almost_equal(hw_corr, first_order_corr, 6)
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
step = np.zeros(len(time)) step[time >= 0.0] = 1.0 # Apply forward filter to impulse and step response impulse_response = signal.lfilter([1.0], a, impulse) step_response = signal.lfilter([1.0], a, step) # Compute ideal inverted filter kernel b_ideal = ZI_kf.ideal_inverted_fir_kernel(impulse_response, zero_ind) # Apply ideal inverted filter to impulse response and step response impulse_response_corr = signal.lfilter(b_ideal, 1.0, impulse_response) step_response_corr = signal.lfilter(b_ideal, 1.0, step_response) # Apply hardware-friendly filter to impulse response and step response impulse_response_corr_hw = ZI_kf.first_order_bounce_corr( impulse_response, bounce_delay, bounce_amp, fs) step_response_corr_hw = ZI_kf.first_order_bounce_corr(step_response, bounce_delay, bounce_amp, fs) # Plot impulse response comparison plt.figure(1, figsize=(10, 14)) plt.subplot(3, 1, 1) plt.plot(time * 1e9, impulse_response) plt.xlabel('Time, t (ns)') plt.ylabel('Amplitude (a.u)') plt.title('(a) Impulse response') plt.subplot(3, 1, 2) plt.plot(time * 1e9, impulse_response_corr)
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