示例#1
0
    def run(
        self,
        presto_address: str,
        presto_port: int = None,
        ext_ref_clk: bool = False,
    ) -> str:
        # Instantiate interface class
        with pulsed.Pulsed(
                address=presto_address,
                port=presto_port,
                ext_ref_clk=ext_ref_clk,
                **CONVERTER_CONFIGURATION,
        ) as pls:
            assert pls.hardware is not None

            # figure out frequencies
            assert self.readout_freq_center > (self.readout_freq_span / 2)
            assert self.readout_freq_span < pls.get_fs(
                "dac") / 2  # fits in HSB
            readout_if_center = pls.get_fs("dac") / 4  # middle of HSB
            readout_if_start = readout_if_center - self.readout_freq_span / 2
            readout_if_stop = readout_if_center + self.readout_freq_span / 2
            self.readout_if_arr = np.linspace(readout_if_start,
                                              readout_if_stop,
                                              self.readout_freq_nr)
            self.readout_nco = self.readout_freq_center - readout_if_center
            self.readout_freq_arr = self.readout_nco + self.readout_if_arr

            pls.hardware.set_adc_attenuation(self.sample_port, 0.0)
            pls.hardware.set_dac_current(self.readout_port, DAC_CURRENT)
            pls.hardware.set_dac_current(self.control_port, DAC_CURRENT)
            pls.hardware.set_inv_sinc(self.readout_port, 0)
            pls.hardware.set_inv_sinc(self.control_port, 0)
            pls.hardware.configure_mixer(
                freq=self.readout_nco,
                in_ports=self.sample_port,
                out_ports=self.readout_port,
                sync=False,  # sync in next call
            )
            pls.hardware.configure_mixer(
                freq=self.control_freq,
                out_ports=self.control_port,
                sync=True,  # sync here
            )

            # ************************************
            # *** Setup measurement parameters ***
            # ************************************

            # Setup lookup tables for frequencies
            pls.setup_freq_lut(
                output_ports=self.readout_port,
                group=0,
                frequencies=self.readout_if_arr,
                phases=np.full_like(self.readout_if_arr, 0.0),
                phases_q=np.full_like(self.readout_if_arr, -np.pi / 2),  # HSB
            )
            pls.setup_freq_lut(
                output_ports=self.control_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )

            # Setup lookup tables for amplitudes
            pls.setup_scale_lut(
                output_ports=self.readout_port,
                group=0,
                scales=self.readout_amp,
            )
            pls.setup_scale_lut(
                output_ports=self.control_port,
                group=0,
                scales=self.control_amp,
            )

            # Setup readout and control pulses
            # use setup_long_drive to create a pulse with square envelope
            # setup_long_drive supports smooth rise and fall transitions for the pulse,
            # but we keep it simple here
            readout_pulse = pls.setup_long_drive(
                output_port=self.readout_port,
                group=0,
                duration=self.readout_duration,
                amplitude=1.0,
                amplitude_q=1.0,
                rise_time=0e-9,
                fall_time=0e-9,
            )
            control_ns = int(round(self.control_duration * pls.get_fs("dac"))
                             )  # number of samples in the control template
            control_envelope = sin2(control_ns, drag=self.drag)
            control_pulse = pls.setup_template(
                output_port=self.control_port,
                group=0,
                template=control_envelope,
                envelope=True,
            )

            # Setup sampling window
            pls.set_store_ports(self.sample_port)
            pls.set_store_duration(self.sample_duration)

            # ******************************
            # *** Program pulse sequence ***
            # ******************************
            T = 0.0  # s, start at time zero ...
            for ii in range(2):
                if ii > 0:
                    # pi pulse
                    pls.reset_phase(T, self.control_port)
                    pls.output_pulse(T, control_pulse)
                # Readout pulse starts after control pulse
                T += self.control_duration
                pls.reset_phase(T, self.readout_port)
                pls.output_pulse(T, readout_pulse)
                # Sampling window
                pls.store(T + self.readout_sample_delay)
                # Move to next iteration
                T += self.readout_duration
                if ii > 0:
                    pls.next_frequency(T, self.readout_port)
                T += self.wait_delay

            # **************************
            # *** Run the experiment ***
            # **************************
            pls.run(
                period=T,
                repeat_count=self.readout_freq_nr,
                num_averages=self.num_averages,
                print_time=True,
            )
            self.t_arr, self.store_arr = pls.get_store_data()

            # if self.jpa_params is not None:
            #     pls.hardware.set_lmx(0.0, 0.0, self.jpa_params['pump_port'])
            #     pls.hardware.set_dc_bias(0.0, self.jpa_params['bias_port'])

        return self.save()
示例#2
0
    def run(
        self,
        presto_address: str,
        presto_port: int = None,
        ext_ref_clk: bool = False,
    ) -> str:
        # Instantiate interface class
        with pulsed.Pulsed(
                address=presto_address,
                port=presto_port,
                ext_ref_clk=ext_ref_clk,
                **CONVERTER_CONFIGURATION,
        ) as pls:
            assert pls.hardware is not None

            pls.hardware.set_adc_attenuation(self.sample_port, 0.0)
            pls.hardware.set_dac_current(self.readout_port, DAC_CURRENT)
            pls.hardware.set_dac_current(self.control_port, DAC_CURRENT)
            pls.hardware.set_inv_sinc(self.readout_port, 0)
            pls.hardware.set_inv_sinc(self.control_port, 0)
            pls.hardware.configure_mixer(
                freq=self.readout_freq,
                in_ports=self.sample_port,
                out_ports=self.readout_port,
                sync=False,  # sync in next call
            )
            pls.hardware.configure_mixer(
                freq=self.control_freq,
                out_ports=self.control_port,
                sync=True,  # sync here
            )
            if self.jpa_params is not None:
                pls.hardware.set_lmx(self.jpa_params['pump_freq'],
                                     self.jpa_params['pump_pwr'],
                                     self.jpa_params['pump_port'])
                pls.hardware.set_dc_bias(self.jpa_params['bias'],
                                         self.jpa_params['bias_port'])
                pls.hardware.sleep(1.0, False)

            # ************************************
            # *** Setup measurement parameters ***
            # ************************************

            # Setup lookup tables for frequencies
            # we only need to use carrier 1
            pls.setup_freq_lut(
                output_ports=self.readout_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )
            pls.setup_freq_lut(
                output_ports=self.control_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )

            # Setup lookup tables for amplitudes
            pls.setup_scale_lut(
                output_ports=self.readout_port,
                group=0,
                scales=self.readout_amp,
            )
            pls.setup_scale_lut(
                output_ports=self.control_port,
                group=0,
                scales=self.control_amp,
            )

            # Setup readout and control pulses
            # use setup_long_drive to create a pulse with square envelope
            # setup_long_drive supports smooth rise and fall transitions for the pulse,
            # but we keep it simple here
            readout_pulse = pls.setup_long_drive(
                output_port=self.readout_port,
                group=0,
                duration=self.readout_duration,
                amplitude=1.0,
                amplitude_q=1.0,
                rise_time=0e-9,
                fall_time=0e-9,
            )
            control_ns = int(round(self.control_duration * pls.get_fs("dac"))
                             )  # number of samples in the control template
            control_envelope = sin2(control_ns, drag=self.drag)
            control_pulse = pls.setup_template(
                output_port=self.control_port,
                group=0,
                template=control_envelope,
                template_q=control_envelope if self.drag == 0.0 else None,
                envelope=True,
            )

            # Setup sampling window
            pls.set_store_ports(self.sample_port)
            pls.set_store_duration(self.sample_duration)

            # ******************************
            # *** Program pulse sequence ***
            # ******************************
            T = 0.0  # s, start at time zero ...
            for delay in self.delay_arr:
                # pi pulse
                pls.reset_phase(T, self.control_port)
                pls.output_pulse(T, control_pulse)
                T += self.control_duration
                # increasing delay
                T += delay
                # Readout
                pls.reset_phase(T, self.readout_port)
                pls.output_pulse(T, readout_pulse)
                pls.store(T + self.readout_sample_delay)
                T += self.readout_duration
                # Wait for decay
                T += self.wait_delay

            if self.jpa_params is not None:
                # adjust period to minimize effect of JPA idler
                idler_freq = self.jpa_params['pump_freq'] - self.readout_freq
                idler_if = abs(idler_freq -
                               self.readout_freq)  # NCO at readout_freq
                idler_period = 1 / idler_if
                T_clk = int(round(T * pls.get_clk_f()))
                idler_period_clk = int(round(idler_period * pls.get_clk_f()))
                # first make T a multiple of idler period
                if T_clk % idler_period_clk > 0:
                    T_clk += idler_period_clk - (T_clk % idler_period_clk)
                # then make it off by one clock cycle
                T_clk += 1
                T = T_clk * pls.get_clk_T()

            # **************************
            # *** Run the experiment ***
            # **************************
            pls.run(
                period=T,
                repeat_count=1,
                num_averages=self.num_averages,
                print_time=True,
            )
            self.t_arr, self.store_arr = pls.get_store_data()

            if self.jpa_params is not None:
                pls.hardware.set_lmx(0.0, 0.0, self.jpa_params['pump_port'])
                pls.hardware.set_dc_bias(0.0, self.jpa_params['bias_port'])

        return self.save()
示例#3
0
    # use setup_long_drive to create a pulse with square envelope
    # setup_long_drive supports smooth rise and fall transitions for the pulse,
    # but we keep it simple here
    readout_pulse = pls.setup_long_drive(
        output_port=readout_port,
        group=0,
        duration=readout_duration,
        amplitude=1.0,
        amplitude_q=1.0,
        rise_time=0e-9,
        fall_time=0e-9,
    )
    control_ns = int(
        round(control_duration *
              pls.get_fs("dac")))  # number of samples in the control template
    control_envelope = sin2(control_ns)
    control_pulse = pls.setup_template(
        output_port=control_port,
        group=0,
        template=control_envelope,
        template_q=control_envelope,
        envelope=True,
    )
    control_pulse_pi_div2 = pls.setup_template(
        output_port=control_port,
        group=0,
        template=control_envelope / 2,
        template_q=control_envelope / 2,
        envelope=True,
    )
示例#4
0
    def run(
        self,
        presto_address,
        presto_port=None,
        ext_ref_clk=False,
    ):

        # Instantiate interface class
        with pulsed.Pulsed(
                address=presto_address,
                port=presto_port,
                ext_ref_clk=ext_ref_clk,
                adc_mode=AdcMode.Mixed,
                adc_fsample=AdcFSample.G2,
                dac_mode=[DacMode.Mixed42, DacMode.Mixed02, DacMode.Mixed02, DacMode.Mixed02],
                dac_fsample=[DacFSample.G10, DacFSample.G6, DacFSample.G6, DacFSample.G6],
        ) as pls:
            pls.hardware.set_adc_attenuation(self.sample_port, 0.0)
            pls.hardware.set_dac_current(self.readout_port, 32_000)
            pls.hardware.set_dac_current(self.control_port, 32_000)
            pls.hardware.set_inv_sinc(self.readout_port, 0)
            pls.hardware.set_inv_sinc(self.control_port, 0)
            pls.hardware.configure_mixer(
                freq=self.readout_freq,
                in_ports=self.sample_port,
                out_ports=self.readout_port,
                sync=False,  # sync in next call
            )
            pls.hardware.configure_mixer(
                freq=self.control_freq,
                out_ports=self.control_port,
                sync=True,  # sync here
            )
            if self.jpa_params is not None:
                pls.hardware.set_lmx(self.jpa_params['jpa_pump_freq'], self.jpa_params['jpa_pump_pwr'])
                set_dc_bias(self.jpa_params['jpa_bias_port'], self.jpa_params['jpa_bias'])
                time.sleep(1.0)

            # ************************************
            # *** Setup measurement parameters ***
            # ************************************

            # Setup lookup tables for frequencies
            # we only need to use carrier 1
            pls.setup_freq_lut(
                output_ports=self.readout_port,
                group=1,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )
            pls.setup_freq_lut(
                output_ports=self.readout_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )
            pls.setup_freq_lut(
                output_ports=self.control_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )

            # Setup lookup tables for amplitudes
            pls.setup_scale_lut(
                output_ports=self.readout_port,
                group=1,
                scales=self.first_pulse_amp_arr,
            )
            pls.setup_scale_lut(
                output_ports=self.readout_port,
                group=0,
                scales=self.readout_amp,
            )
            pls.setup_scale_lut(
                output_ports=self.control_port,
                group=0,
                scales=self.control_amp,
            )

            # Setup readout and control pulses
            # use setup_long_drive to create a pulse with square envelope
            # setup_long_drive supports smooth rise and fall transitions for the pulse,
            # but we keep it simple here
            first_pulse = pls.setup_long_drive(
                output_port=self.readout_port,
                group=1,
                duration=self.readout_duration,
                amplitude=1.0,
                amplitude_q=1.0,
                rise_time=0e-9,
                fall_time=0e-9,
            )
            readout_pulse = pls.setup_long_drive(
                output_port=self.readout_port,
                group=0,
                duration=self.readout_duration,
                amplitude=1.0,
                amplitude_q=1.0,
                rise_time=0e-9,
                fall_time=0e-9,
            )
            control_ns = int(round(self.control_duration *
                                   pls.get_fs("dac")))  # number of samples in the control template
            control_envelope = sin2(control_ns)
            control_pulse = pls.setup_template(
                output_port=self.control_port,
                group=0,
                template=control_envelope,
                template_q=control_envelope,
                envelope=True,
            )

            # Setup sampling window
            pls.set_store_ports(self.sample_port)
            pls.set_store_duration(self.sample_duration)

            # ******************************
            # *** Program pulse sequence ***
            # ******************************
            T = 0.0  # s, start at time zero ...
            for ramsey_delay in self.ramsey_delay_arr:
                # first "readout" pulse
                pls.reset_phase(T, self.readout_port)
                pls.output_pulse(T, first_pulse)
                T += self.readout_duration
                T_end_first = T
                # first pi/2 pulse
                pls.reset_phase(T, self.control_port)
                pls.output_pulse(T, control_pulse)
                T += self.control_duration
                # Ramsey delay
                T += ramsey_delay
                # second pi/2 pulse
                pls.output_pulse(T, control_pulse)
                T += self.control_duration
                # Readout pulse starts after control pulse,
                # `buffer_time` away from the first pulse
                assert T <= T_end_first + self.buffer_time
                T = T_end_first + self.buffer_time
                pls.reset_phase(T, self.readout_port)
                pls.output_pulse(T, readout_pulse)
                # Sampling window
                pls.store(T + self.readout_sample_delay)
                # Move to next iteration
                T += self.readout_duration
                T += self.wait_delay
            # next scale on first pulse
            pls.next_scale(T, self.readout_port, 1)
            T += self.wait_delay

            # **************************
            # *** Run the experiment ***
            # **************************
            pls.run(
                period=T,
                repeat_count=len(self.first_pulse_amp_arr),
                num_averages=self.num_averages,
                print_time=True,
            )
            t_arr, (data_I, data_Q) = pls.get_store_data()

            if self.jpa_params is not None:
                pls.hardware.set_lmx(0.0, 0.0)
                set_dc_bias(self.jpa_params['jpa_bias_port'], 0.0)

        self.t_arr = t_arr
        self.store_arr = data_I + 1j * data_Q

        return self.save()
示例#5
0
def measure_t1(which_qubit):
    if which_qubit == 1:
        readout_freq = readout_freq_1
        control_freq = control_freq_1
        control_amp = control_amp_pi_1
        control_port = control_port_1
    else:
        readout_freq = readout_freq_2
        control_freq = control_freq_2
        control_amp = control_amp_pi_2
        control_port = control_port_2

    nr_delays = 128  # number of steps when changing delay between control and readout pulses
    dt_delays = 4 * 1e-6  # s, step size when changing delay between control and readout pulses

    with pulsed.Pulsed(
            address=ADDRESS,
            ext_ref_clk=EXT_REF_CLK,
            adc_mode=AdcMode.Mixed,
            adc_fsample=AdcFSample.G2,
            dac_mode=[
                DacMode.Mixed42, DacMode.Mixed02, DacMode.Mixed02,
                DacMode.Mixed02
            ],
            dac_fsample=[
                DacFSample.G10, DacFSample.G6, DacFSample.G6, DacFSample.G6
            ],
    ) as pls:
        pls.hardware.set_adc_attenuation(sample_port, 0.0)
        pls.hardware.set_dac_current(readout_port, 32_000)
        pls.hardware.set_dac_current(control_port, 32_000)
        pls.hardware.set_inv_sinc(readout_port, 0)
        pls.hardware.set_inv_sinc(control_port, 0)
        pls.hardware.configure_mixer(
            freq=readout_freq,
            in_ports=sample_port,
            out_ports=readout_port,
            sync=False,  # sync in next call
        )
        pls.hardware.configure_mixer(
            freq=control_freq,
            out_ports=control_port,
            sync=True,  # sync here
        )

        # ************************************
        # *** Setup measurement parameters ***
        # ************************************

        # Setup lookup tables for frequencies
        # we only need to use carrier 1
        pls.setup_freq_lut(
            output_ports=readout_port,
            group=0,
            frequencies=0.0,
            phases=0.0,
            phases_q=0.0,
        )
        pls.setup_freq_lut(
            output_ports=control_port,
            group=0,
            frequencies=0.0,
            phases=0.0,
            phases_q=0.0,
        )

        # Setup lookup tables for amplitudes
        pls.setup_scale_lut(
            output_ports=readout_port,
            group=0,
            scales=readout_amp,
        )
        pls.setup_scale_lut(
            output_ports=control_port,
            group=0,
            scales=control_amp,
        )

        # Setup readout and control pulses
        # use setup_long_drive to create a pulse with square envelope
        # setup_long_drive supports smooth rise and fall transitions for the pulse,
        # but we keep it simple here
        readout_pulse = pls.setup_long_drive(
            output_port=readout_port,
            group=0,
            duration=readout_duration,
            amplitude=1.0,
            amplitude_q=1.0,
            rise_time=0e-9,
            fall_time=0e-9,
        )
        control_ns = int(round(
            control_duration *
            pls.get_fs("dac")))  # number of samples in the control template
        control_envelope = sin2(control_ns)
        control_pulse = pls.setup_template(
            output_port=control_port,
            group=0,
            template=control_envelope,
            template_q=control_envelope,
            envelope=True,
        )

        # Setup sampling window
        pls.set_store_ports(sample_port)
        pls.set_store_duration(sample_duration)

        # ******************************
        # *** Program pulse sequence ***
        # ******************************
        T = 0.0  # s, start at time zero ...
        for ii in range(nr_delays):
            # pi pulse
            pls.reset_phase(T, control_port)
            pls.output_pulse(T, control_pulse)
            # Readout pulse starts after control pulse,
            # with an increasing delay
            T += control_duration + ii * dt_delays
            pls.reset_phase(T, readout_port)
            pls.output_pulse(T, readout_pulse)
            # Sampling window
            pls.store(T + readout_sample_delay)
            # Move to next iteration
            T += readout_duration
            T += wait_delay

        # **************************
        # *** Run the experiment ***
        # **************************
        pls.run(
            period=T,
            repeat_count=1,
            num_averages=num_averages,
            print_time=True,
        )
        t_arr, (data_I, data_Q) = pls.get_store_data()

    store_arr = data_I + 1j * data_Q

    idx_low = np.argmin(np.abs(t_arr - t_low))
    idx_high = np.argmin(np.abs(t_arr - t_high))
    idx = np.arange(idx_low, idx_high)

    # Analyze T1
    resp_arr = np.mean(store_arr[:, 0, idx], axis=-1)
    resp_arr = rotate_opt(resp_arr)
    delay_arr = dt_delays * np.arange(nr_delays)

    # Fit data
    popt_x, perr_x = t1_fit_simple(delay_arr, np.real(resp_arr))

    T1 = popt_x[0]
    T1_err = perr_x[0]

    return T1, T1_err
    def run(
        self,
        presto_address: str,
        presto_port: int = None,
        ext_ref_clk: bool = False,
    ) -> str:
        with pulsed.Pulsed(
                address=presto_address,
                port=presto_port,
                ext_ref_clk=ext_ref_clk,
                **CONVERTER_CONFIGURATION,
        ) as pls:
            assert pls.hardware is not None

            # figure out frequencies
            assert self.control_freq_center > (self.control_freq_span / 2)
            assert self.control_freq_span < pls.get_fs(
                "dac") / 2  # fits in HSB
            control_if_center = pls.get_fs("dac") / 4  # middle of HSB
            control_if_start = control_if_center - self.control_freq_span / 2
            control_if_stop = control_if_center + self.control_freq_span / 2
            control_if_arr = np.linspace(control_if_start, control_if_stop,
                                         self.control_freq_nr)
            control_nco = self.control_freq_center - control_if_center
            self.control_freq_arr = control_nco + control_if_arr

            pls.hardware.set_adc_attenuation(self.sample_port, 0.0)
            pls.hardware.set_dac_current(self.readout_port, DAC_CURRENT)
            pls.hardware.set_dac_current(self.control_port, DAC_CURRENT)
            pls.hardware.set_inv_sinc(self.readout_port, 0)
            pls.hardware.set_inv_sinc(self.control_port, 0)
            pls.hardware.configure_mixer(
                freq=self.readout_freq,
                in_ports=self.sample_port,
                out_ports=self.readout_port,
                sync=False,  # sync in next call
            )
            pls.hardware.configure_mixer(
                freq=control_nco,
                out_ports=self.control_port,
                sync=True,  # sync here
            )
            if self.jpa_params is not None:
                pls.hardware.set_lmx(self.jpa_params['pump_freq'],
                                     self.jpa_params['pump_pwr'],
                                     self.jpa_params['pump_port'])
                pls.hardware.set_dc_bias(self.jpa_params['bias'],
                                         self.jpa_params['bias_port'])
                pls.hardware.sleep(1.0, False)

            # ************************************
            # *** Setup measurement parameters ***
            # ************************************

            # Setup lookup tables for frequencies
            pls.setup_freq_lut(
                output_ports=self.readout_port,
                group=0,
                frequencies=0.0,
                phases=0.0,
                phases_q=0.0,
            )
            pls.setup_freq_lut(
                output_ports=self.control_port,
                group=0,
                frequencies=control_if_arr,
                phases=np.full_like(control_if_arr, 0.0),
                phases_q=np.full_like(control_if_arr, -np.pi / 2),  # HSB
            )

            # Setup lookup tables for amplitudes
            pls.setup_scale_lut(
                output_ports=self.readout_port,
                group=0,
                scales=self.readout_amp,
            )
            pls.setup_scale_lut(
                output_ports=self.control_port,
                group=0,
                scales=self.control_amp,
            )

            # Setup readout and control pulses
            # use setup_long_drive to create a pulse with square envelope
            # setup_long_drive supports smooth rise and fall transitions for the pulse,
            # but we keep it simple here
            readout_pulse = pls.setup_long_drive(
                output_port=self.readout_port,
                group=0,
                duration=self.readout_duration,
                amplitude=1.0,
                amplitude_q=1.0,
                rise_time=0e-9,
                fall_time=0e-9,
            )
            # For the control pulse we create a sine-squared envelope,
            # and use setup_template to use the user-defined envelope
            control_ns = int(round(self.control_duration * pls.get_fs("dac"))
                             )  # number of samples in the control template
            control_envelope = sin2(control_ns)
            control_pulse = pls.setup_template(
                output_port=self.control_port,
                group=0,
                template=control_envelope,
                template_q=control_envelope,
                envelope=True,
            )

            # Setup sampling window
            pls.set_store_ports(self.sample_port)
            pls.set_store_duration(self.sample_duration)

            # ******************************
            # *** Program pulse sequence ***
            # ******************************
            T = 0.0  # s, start at time zero ...
            # Control pulse
            pls.reset_phase(T, self.control_port)
            pls.output_pulse(T, control_pulse)
            # Readout pulse starts right after control pulse
            T += self.control_duration
            pls.reset_phase(T, self.readout_port)
            pls.output_pulse(T, readout_pulse)
            # Sampling window
            pls.store(T + self.readout_sample_delay)
            # Move to next Rabi amplitude
            T += self.readout_duration
            pls.next_frequency(
                T, self.control_port
            )  # every iteration will have a different frequency
            # Wait for decay
            T += self.wait_delay

            if self.jpa_params is not None:
                # adjust period to minimize effect of JPA idler
                idler_freq = self.jpa_params['pump_freq'] - self.readout_freq
                idler_if = abs(idler_freq -
                               self.readout_freq)  # NCO at readout_freq
                idler_period = 1 / idler_if
                T_clk = int(round(T * pls.get_clk_f()))
                idler_period_clk = int(round(idler_period * pls.get_clk_f()))
                # first make T a multiple of idler period
                if T_clk % idler_period_clk > 0:
                    T_clk += idler_period_clk - (T_clk % idler_period_clk)
                # then make it off by one clock cycle
                T_clk += 1
                T = T_clk * pls.get_clk_T()

            # **************************
            # *** Run the experiment ***
            # **************************
            # repeat the whole sequence `rabi_n` times
            # then average `num_averages` times
            pls.run(
                period=T,
                repeat_count=self.control_freq_nr,
                num_averages=self.num_averages,
                print_time=True,
            )
            self.t_arr, self.store_arr = pls.get_store_data()

            if self.jpa_params is not None:
                pls.hardware.set_lmx(0.0, 0.0, self.jpa_params['pump_port'])
                pls.hardware.set_dc_bias(0.0, self.jpa_params['bias_port'])

        return self.save()