See also

A Jupyter notebook version of this tutorial can be downloaded here.

image0

Resonator flux spectroscopy#

By changing the magnetic flux through a flux-tunable transmon, the frequency of the qubit’s |0⟩ → |1⟩ transition can be controlled. While idling, the qubit is commonly kept at its “flux-sweetspot”, where it is less susceptible to magnetic field noise. To ensure that the qubit is at the sweetspot, the voltage bias over the flux line should be calibrated. To do this we use dependence of the resonator dispersive (Lamb) shift on the qubit frequency, such that any change in the |0⟩ → |1⟩ transition frequency results in a change of the readout frequency. For the experiment, the voltage bias over the flux line is swept while performing resonator spectroscopy experiments. This allows for a course calibration of the necessary bias voltage.

[1]:
from dependencies.analysis_utils import ResonatorFluxSpectroscopyAnalysis
from xarray import open_dataset

from qblox_scheduler import HardwareAgent, Schedule
from qblox_scheduler.experiments import SetParameter
from qblox_scheduler.operations import IdlePulse, Measure
from qblox_scheduler.operations.expressions import DType
from qblox_scheduler.operations.loop_domains import arange, linspace
Generating hash table for SingleQubitClifford.
Hash table generated.
Generating hash table for TwoQubitCliffordCZ.
Hash table generated.
Generating hash table for TwoQubitCliffordZX.
Hash table generated.
Testing decompositions.
Test passed.

Setup#

The hardware agent manages the connection to the instrument and ensures that pulses and acquisitions happen over the appropriate input and output channels of the Cluster. The cell below creates an instance of the HardwareAgent based on the hardware- and device-under-test configuration files in the ./dependencies/configs folder, allowing us to start doing measurements. We also define some convenient aliases to use throughout our measurements. For a more thorough discussion of the hardware- and device-under-test configuration files, check out this tutorial.

[2]:
# Set up hardware agent, this automatically connects to the instrument
hw_agent = HardwareAgent(
    hardware_configuration="./dependencies/configs/hw_config.json",
    quantum_device_configuration="./dependencies/configs/dut_config.json",
)

# convenience aliases
q0 = hw_agent.quantum_device.get_element("q0")
q2 = hw_agent.quantum_device.get_element("q2")
cluster = hw_agent.get_clusters()["cluster"]
hw_options = hw_agent.hardware_configuration.hardware_options
qubit = q0
/builds/0/.venv/lib/python3.10/site-packages/qblox_scheduler/qblox/hardware_agent.py:460: UserWarning: cluster: Trying to instantiate cluster with ip 'None'.Creating a dummy cluster.
  warnings.warn(

Experiment settings#

[3]:
# Frequency settings
frequency_center = qubit.clock_freqs.readout  # Hz
frequency_width = 5e6  # Hz
frequency_npoints = 150

# Flux settings
flux_start = -0.75  # V
flux_stop = 0.75  # V
flux_step = 0.030  # V

repetitions = 100

Before sweeping the voltage over the flux port, we define a new parameter that represents the voltage output of the instrument. This allows us to ensure that the flux bias changes gradually, to avoid that the frequency of the qubit changes due to sudden voltage changes over the flux line. This uses Qcodes under the hood.

[4]:
flux_offset = cluster.module14.out0_offset  # Flux port of q0
flux_offset.inter_delay = 100e-9  # Delay time between consecutive set operations.
flux_offset.step = 0.3e-3  # Stepsize in V that this Parameter uses during set operation.

flux_offset.get()  # Get before setting to avoid jumps.
flux_offset.set(0.0)  # V

Experiment schedule#

[5]:
flux_res_sched = Schedule("flux_resonator_spectroscopy")

with flux_res_sched.loop(
    arange(start=flux_start, stop=flux_stop, step=flux_step, dtype=DType.AMPLITUDE)
) as amp:
    # Set the flux offset voltage.
    flux_res_sched.add(SetParameter(flux_offset, amp))
    with (
        flux_res_sched.loop(arange(0, repetitions, 1, DType.NUMBER)),
        flux_res_sched.loop(
            linspace(
                start=frequency_center - frequency_width / 2,
                stop=frequency_center + frequency_width / 2,
                num=frequency_npoints,
                dtype=DType.FREQUENCY,
            )
        ) as freq,
    ):
        flux_res_sched.add(
            Measure(
                qubit.name,
                freq=freq,
                coords={"frequency": freq, "amplitude": amp},
                acq_channel="S_21",
            )
        )
        flux_res_sched.add(IdlePulse(10e-6))  # Let the resonator decay

# Execute the experiment
flux_res_data = hw_agent.run(flux_res_sched)
if cluster.is_dummy:
    example_data = open_dataset(
        "./dependencies/datasets/flux_resonator_spectroscopy.hdf5", engine="h5netcdf"
    )
    flux_res_data = flux_res_data.update({"S_21": example_data.S_21})

Analyze the experiment#

[6]:
flux_resspec_analysis = ResonatorFluxSpectroscopyAnalysis(flux_res_data).run()
flux_resspec_analysis.display_figs_mpl()
../../../_images/applications_superconducting_flux_tunable_transmon_040_resonator_flux_spectroscopy_12_0.png

Post-run#

[7]:
# Update flux offset
flux_offset(flux_resspec_analysis.quantities_of_interest["sweetspot_1"].nominal_value)

Update the device configuration file#

After measurement, we may store the measured device properties inside a new file to use in future experiments. The time-unique identifier ensures that it is easy to find back previously found measurement results.

[8]:
hw_agent.quantum_device.to_json_file("./dependencies/configs", add_timestamp=True)
[8]:
'./dependencies/configs/two_flux_tunable_transmons_2025-10-30_00-38-44_UTC.json'