# Rabi time Using {mod}`.pulsed` mode, we measure Rabi oscillations by driving the qubit with a square pulse of variable duration. We also sweep the amplitude of the qubit pulse to get a 2D sweep. We fit the amplitude-dependent Rabi rate. ![Rabi time pulse sequence](images/Rabi_time_pulse_sequence.svg){align=center} The full source code for this experiment is available at [presto-measure/rabi_time.py][rabi_time.py]. Here, we first run the Rabi experiment and analyze the data in order to fit the amplitude-dependent Rabi rate, and then we have a more detailed look at the most important parts of the code. You can create a new experiment and run it on your Presto. Be sure to change the parameters of `RabiTime` to match your experiment and change `presto_address` to match the IP address of your Presto: ```python from rabi_time import RabiTime import numpy as np experiment = RabiTime( readout_freq=6.2e9, control_freq=4.2e9, readout_amp=0.1, control_amp_arr=np.linspace(0.001, 0.01, 21), readout_duration=2.1e-6, control_duration_arr=np.linspace(100e-9, 10e-6, 100), sample_duration=2.5e-6, readout_port=1, control_port=4, sample_port=1, wait_delay=100e-6, readout_sample_delay=0e-9, num_averages=100, ) presto_address = "192.168.88.65" # your Presto IP address save_filename = experiment.run(presto_address) ``` Or you can also load older data: ```python experiment = RabiTime.load("data/rabi_time_20230328_181549.h5") ``` In either case, we analyze the data to get a nice plot: ```python experiment.analyze() ``` ```{image} images/rabi_time_light.svg :align: center :class: only-light ``` ```{image} images/rabi_time_dark.svg :align: center :class: only-dark ``` The frequency of Rabi oscillations (left panel) is fitted for each drive amplitude individually. The linear dependence of the Rabi rate and drive amplitude is shown in the right panel. ## Code explanation Here we discuss the main parts of the code in [presto-measure/rabi_time.py][rabi_time.py]. :::{note} If this is your first measurement in {mod}`.pulsed` mode, you might want to first have a look at the [Rabi amplitude](rabi_amp) chapter in this tutorial. There we describe the code more pedagogically and in more detail. ::: We program all the control amplitudes we want to sweep in the scale look-up table (LUT), just like we did in [Rabi amplitude](rabi_amp). ```python pls.setup_scale_lut(self.readout_port, group=0, scales=self.readout_amp) pls.setup_scale_lut(self.control_port, group=0, scales=self.control_amp_arr) ``` --- We want to change the duration of the qubit-control pulse for each iteration of the experiment. The easiest way to achieve that is to create a {class}`.LongDrive` using {meth}`.setup_long_drive`: ```python control_pulse = pls.setup_long_drive( self.control_port, group=0, duration=self.control_duration_arr[0], amplitude=1.0 + 1j, envelope=False, ) ``` We initialize the pulse duration to the first value in `control_duration_arr`, we will then update the duration when we program the experimental sequence. A `LongDrive` supports smooth rise and fall, but in this case we'll just use a square pulse shape. --- The core of the measurement is the definition of the experimental sequence: ```python T = 0.0 # s, start at time zero ... for control_duration in self.control_duration_arr: control_pulse.set_total_duration(control_duration) # Set control pulse length pls.output_pulse(T, control_pulse) T += control_duration pls.output_pulse(T, readout_pulse) # Readout pls.store(T + self.readout_sample_delay) T += self.readout_duration T += self.wait_delay # Wait for decay pls.next_scale(T, self.control_port, group=0) T += self.wait_delay ``` We use a `for` loop to repeat the measurement for each duration of the qubit-control pulse. We update the length of the qubit-control pulse with {meth}`~.LongDrive.set_total_duration`, and then we schedule its output. As usual, the resonator-readout pulse and the data acquisition are scheduled right after the control pulse. After that, we wait for the qubit to decay back to the ground state. When the `for` loop is exhausted, we call {meth}`~.Pulsed.next_scale` to change the amplitude of the qubit-control pulse to the next entry in the scale LUT. --- To finally execute the measurement, we call {meth}`~.Pulsed.run`: ```python nr_amps = len(self.control_amp_arr) pls.run(period=T, repeat_count=nr_amps, num_averages=self.num_averages) ``` A single sequence already contains `len(control_duration_arr)` measurements due to the `for` loop, each with a different duration for the qubit-control pulse. This long sequence is then repeated `nr_amps` times due to the `repeat_count` parameter, each with a different amplitude of the qubit-control pulse. Finally, the whole 2D sweep is repeated `num_averages` times to perform interleaved averaging. [rabi_time.py]: https://github.com/intermod-pro/presto-measure/blob/master/rabi_time.py