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.
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()
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)