Resonator sweep with the qubit in the excited state

pulsed frequency sweep of the resonator with and without a \(\pi\) pulse on the qubit. The qubit-control pulse has a \(\sin^2\) envelope, while the resonator-readout pulse has a square envelope. We sweep the readout frequency.

excited sweep pulse sequence

The full source code of the class ExcitedSweep for performing the experiment is available at presto-measure/excited_sweep.py. Here, we first run the experiment and then look at the most interesting parts of the code.

You can create a new experiment and run it on your Presto. Be sure to change the parameters of ExcitedSweep to match your experiment and change presto_address to match the IP address of your Presto:

from excited_sweep import ExcitedSweep

experiment = ExcitedSweep(
    readout_freq_center=6.2e9,
    readout_freq_span=4.2e6,
    readout_freq_nr=101,
    control_freq=4e9,
    readout_amp=0.1,
    control_amp=0.5,
    readout_duration=2.5e-6,
    control_duration=100e-9,
    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:

experiment = ExcitedSweep.load("data/excited_sweep_20220402_201551.h5")

In either case, we analyze the data to get a nice plot:

experiment.analyze()
../_images/excited_sweep_light.svg ../_images/excited_sweep_dark.svg

The figure above shows the amplitude (top panel) and phase (middle panel) of the readout-resonator response when the qubit is prepared in its ground or excited state. The bottom panel shows the distance in the complex plane between the two traces: the optimal readout frequency that maximizes the separation is marked with a vertical dashed line.

Code explanation

Here we look under the hood of the ExcitedSweep class and discuss the pulse sequence and the phase reset on the resonator-readout pulse. You can find the full source code at presto-measure/excited_sweep.py.

Note

If this is your first measurement in pulsed mode, you might want to first have a look at the Rabi amplitude chapter in this tutorial. There we describe the code more pedagogically and in more detail.

We set up the digital up-conversion similarly as in the previous chapter of this tutorial, Ramsey fringes. This time, however, the settings on the qubit control and resonator readout are reversed: we use zero intermediate frequency (IF) on the qubit-control pulse, and we use single-sideband modulation (SSB) in the upper sideband (USB) for the resonator-readout pulse:

pls.hardware.configure_mixer(
    self.readout_nco,  # <-- up-conversion frequency (nonzero IF)
    in_ports=self.sample_port,
    out_ports=self.readout_port,
)
pls.hardware.configure_mixer(
    self.control_freq,  # <-- output frequency (zero IF)
    out_ports=self.control_port,
)

pls.setup_freq_lut(
    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),  # <-- USB
)

For each resonator frequency, we repeat the measurement twice: once with the qubit in the ground state (no qubit-control pulse), and a second time with a \(\pi\) pulse to put the qubit in the excited state. In both cases, we perform the readout right after the state preparation. Finally, after the second run, we call next_frequency() to repeat both measurements at all the resonator frequencies:

T = 0.0  # s, start at time zero ...
for ii in range(2):
    # state preparation
    if ii == 0:
        pass  # no pulse
    else:
        pls.output_pulse(T, control_pulse)  # π pulse
    T += self.control_duration

    # 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

    if ii == 0:
        pass  # keep same frequency for next iteration
    else:
        pls.next_frequency(T, self.readout_port)
    T += self.wait_delay  # wait for decay

For the readout, we call reset_phase() to make sure the resonator-readout pulse repeats always with the exact same phase, regardless of the repetition period of the experiment and the pulse frequency of the current iteration. This ensures that the interleaved averaging performed by store() happens coherently and correctly.


Finally, we call run() to execute the pulse sequence readout_freq_nr number of times:

pls.run(period=T, repeat_count=self.readout_freq_nr, num_averages=self.num_averages)