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)
Esempio n. 2
0
 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