See also

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

Fixed Frequency Transmon#

This notebook shows a typical tuneup sequence for fixed frequency transmon qubits. The notebook aims to be as compact as possible, for more details, please refer to the respective experiments.

Time of flight measurement#

Here show how to measure time of flight for your system. This is useful to calibrate the acquisition delay for subsequent experiments.

[1]:
import json
from functools import partial
from typing import Literal

import matplotlib.pyplot as plt
import numpy as np
import rich  # noqa:F401
from qcodes.parameters import ManualParameter
from sklearn.metrics import ConfusionMatrixDisplay

import quantify_core.data.handling as dh
from quantify_core.analysis.readout_calibration_analysis import ReadoutCalibrationAnalysis
from quantify_core.analysis.time_of_flight_analysis import TimeOfFlightAnalysis
from quantify_scheduler import Schedule
from quantify_scheduler.backends.qblox import constants
from quantify_scheduler.device_under_test.quantum_device import QuantumDevice
from quantify_scheduler.enums import BinMode
from quantify_scheduler.gettables import ScheduleGettable
from quantify_scheduler.math import closest_number_ceil
from quantify_scheduler.operations.gate_library import Measure, Reset, Rxy, X
from quantify_scheduler.operations.pulse_library import IdlePulse
from quantify_scheduler.schedules.timedomain_schedules import ramsey_sched

from utils import initialize_hardware, run  # noqa:F401
[2]:
hw_config_path = "configs/tuning_transmon_coupled_pair_hardware_config.json"
device_path = "devices/transmon_device_2q.json"
[3]:
with open(hw_config_path) as hw_cfg_json_file:
    hardware_cfg = json.load(hw_cfg_json_file)

# Enter your own dataset directory here!
dh.set_datadir(dh.default_datadir())
Data will be saved in:
/root/quantify-data
[4]:
quantum_device = QuantumDevice.from_json_file(device_path)
qubit = quantum_device.get_element("q0")
quantum_device.hardware_config(hardware_cfg)
meas_ctrl, _, cluster = initialize_hardware(quantum_device, ip=None)
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1220: ValidationWarning: Setting `auto_lo_cal=on_lo_interm_freq_change` will overwrite settings `dc_offset_i=0.0` and `dc_offset_q=0.0`. To suppress this warning, do not set either `dc_offset_i` or `dc_offset_q` for this port-clock.
  warnings.warn(
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(

Schedule definition#

[5]:
def tof_trace_schedule(
    qubit_name: str,
    repetitions: int = 1,
) -> Schedule:
    schedule = Schedule("Trace measurement schedule", repetitions=repetitions)
    schedule.add(Measure(qubit_name, acq_protocol="Trace"))
    return schedule

Measuring time of flight with trace acquisition#

[6]:
def set_readout_attenuation_hardware_config(attenuation_dB: int):
    hwcfg = quantum_device.hardware_config()
    output_att = hwcfg["hardware_options"]["output_att"]
    output_att[f"{qubit.ports.readout()}-{qubit.name}.ro"] = attenuation_dB
    quantum_device.hardware_config(hwcfg)


set_readout_attenuation_hardware_config(0)
qubit.measure.pulse_duration(300e-9)
qubit.measure.integration_time(1e-6)
qubit.measure.pulse_amp(0.1)
qubit.measure.acq_delay(4e-9)
[7]:
tof_t = ManualParameter(name="tof_t", unit="ns", label="Trace acquisition sample")
tof_t.batched = True
tof_t.batch_size = round(qubit.measure.integration_time() * constants.SAMPLING_RATE)

tof_sched_kwargs = dict(
    qubit_name=qubit.name,
)

# set gettable
gettable = ScheduleGettable(
    quantum_device,
    schedule_function=tof_trace_schedule,
    schedule_kwargs=tof_sched_kwargs,
    real_imag=False,
    batched=True,
)

# set measurement control
meas_ctrl.gettables(gettable)
[8]:
tof_t_setpoints = np.arange(tof_t.batch_size)

meas_ctrl.settables(tof_t)
meas_ctrl.setpoints(tof_t_setpoints)

# replace the get method for the gettable in case the cluster is a dummy
if "dummy" in str(cluster._transport):

    def get_fake_tof_data():
        """Generate mock data for a time of flight measurement."""
        y = (
            np.heaviside(tof_t_setpoints - 200, 0.5)
            - np.heaviside(tof_t_setpoints - tof_t_setpoints.size * 0.7, 0.5)
        ) * 30e-3
        y += np.random.normal(loc=0.0, scale=1e-3, size=y.size)
        return [y, np.zeros_like(y)]

    gettable.get = get_fake_tof_data

tof_ds = dh.to_gridded_dataset(meas_ctrl.run("Time of flight measurement " + qubit.name))
tof_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         tof_t
Batch size limit: 1000

[8]:
<xarray.Dataset> Size: 24kB
Dimensions:  (x0: 1000)
Coordinates:
  * x0       (x0) int64 8kB 0 1 2 3 4 5 6 7 ... 992 993 994 995 996 997 998 999
Data variables:
    y0       (x0) float64 8kB 0.001493 -0.0005849 ... 0.002208 0.0007401
    y1       (x0) float64 8kB 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
Attributes:
    tuid:                             20241113-023632-482-9d6ba1
    name:                             Time of flight measurement q0
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False

Analysis#

[9]:
tof_analysis = TimeOfFlightAnalysis(tuid=dh.get_latest_tuid())
tof_analysis.run(playback_delay=149e-9).display_figs_mpl()
../../../_images/applications_quantify_transmon_fixed_freq_transmon_13_0.png
[10]:
fit_results = tof_analysis.quantities_of_interest
nco_prop_delay = fit_results["nco_prop_delay"]
measured_tof = fit_results["tof"]

qubit.measure.acq_delay(
    closest_number_ceil(
        measured_tof * constants.SAMPLING_RATE, constants.MIN_TIME_BETWEEN_OPERATIONS
    )
    / constants.SAMPLING_RATE
)
[11]:
quantum_device.to_json_file("devices/")
[11]:
'devices/device_2q_2024-11-13_02-36-33_UTC.json'

Resonator Spectroscopy#

Here we go through resonator discovery and punchout spectroscopy for identifying the resonator and measuring it’s resonant frequency.

Resonator Spectroscopy#

[12]:
def resonator_spectroscopy_schedule(
    qubit,  # noqa: ANN001
    freqs: np.array,
    repetitions: int = 1,
) -> Schedule:
    """Schedule to sweep the resonator frequency."""
    sched = Schedule("schedule", repetitions=repetitions)
    for i, freq in enumerate(freqs):
        sched.add(
            Measure(
                qubit.name,
                acq_index=i,
                freq=freq,
            )
        )
        sched.add(IdlePulse(8e-9))
    return sched


freqs = ManualParameter(name="freq", unit="Hz", label="Frequency")
freqs.batched = True
freqs.batch_size = 100

spec_sched_kwargs = dict(
    qubit=qubit,
    freqs=freqs,
)
gettable = ScheduleGettable(
    quantum_device,
    schedule_function=resonator_spectroscopy_schedule,
    schedule_kwargs=spec_sched_kwargs,
    real_imag=False,
    batched=True,
)

meas_ctrl.gettables(gettable)
[13]:
quantum_device.cfg_sched_repetitions(400)

center = 7.7e9
frequency_setpoints = np.linspace(center - 20e6, center + 20e6, 300)
meas_ctrl.settables(freqs)
meas_ctrl.setpoints(frequency_setpoints)

rs_ds = meas_ctrl.run("resonator spectroscopy")
rs_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         freq
Batch size limit: 100

/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
[13]:
<xarray.Dataset> Size: 7kB
Dimensions:  (dim_0: 300)
Coordinates:
    x0       (dim_0) float64 2kB 7.68e+09 7.68e+09 ... 7.72e+09 7.72e+09
Dimensions without coordinates: dim_0
Data variables:
    y0       (dim_0) float64 2kB nan nan nan nan nan nan ... nan nan nan nan nan
    y1       (dim_0) float64 2kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023633-465-576657
    name:                             resonator spectroscopy
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False
[14]:
qubit.clock_freqs.readout(7.9e9)

Resonator punchout#

[15]:
def resonator_punchout_schedule(
    qubit,  # noqa: ANN001
    freqs: np.array,
    ro_pulse_amps: np.array,
    repetitions: int = 1,
) -> Schedule:
    """Schedule to sweep the resonator frequency."""
    sched = Schedule("schedule", repetitions=repetitions)
    index = 0
    freqs, ro_pulse_amps = np.unique(freqs), np.unique(ro_pulse_amps)
    for freq in freqs:
        for amp in ro_pulse_amps:
            sched.add(Measure(qubit.name, acq_index=index, freq=freq, pulse_amp=amp))
            sched.add(IdlePulse(8e-9))
            index += 1
    return sched


freqs = ManualParameter(name="freq", unit="Hz", label="Frequency")
freqs.batched = True

ro_pulse_amps = ManualParameter(name="ro_pulse_amp", unit="", label="Readout pulse amplitude")
ro_pulse_amps.batched = True

spec_sched_kwargs = dict(
    qubit=qubit,
    freqs=freqs,
    ro_pulse_amps=ro_pulse_amps,
)

gettable = ScheduleGettable(
    quantum_device,
    schedule_function=resonator_punchout_schedule,
    schedule_kwargs=spec_sched_kwargs,
    real_imag=False,
    batched=True,
)

meas_ctrl.gettables(gettable)
[16]:
quantum_device.cfg_sched_repetitions(80)
center = 7.7e9
frequency_setpoints = np.linspace(center - 20e6, center + 20e6, 100)
amplitude_setpoints = np.linspace(0, 1, 10)

meas_ctrl.settables([freqs, ro_pulse_amps])
meas_ctrl.setpoints_grid((frequency_setpoints, amplitude_setpoints))

punchout_ds = meas_ctrl.run("resonator punchout")
punchout_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         freq, ro_pulse_amp
Batch size limit: 1000

/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
[16]:
<xarray.Dataset> Size: 32kB
Dimensions:  (dim_0: 1000)
Coordinates:
    x0       (dim_0) float64 8kB 7.68e+09 7.68e+09 ... 7.72e+09 7.72e+09
    x1       (dim_0) float64 8kB 0.0 0.0 0.0 0.0 0.0 0.0 ... 1.0 1.0 1.0 1.0 1.0
Dimensions without coordinates: dim_0
Data variables:
    y0       (dim_0) float64 8kB nan nan nan nan nan nan ... nan nan nan nan nan
    y1       (dim_0) float64 8kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023634-137-fd08b0
    name:                             resonator punchout
    grid_2d:                          True
    grid_2d_uniformly_spaced:         True
    1d_2_settables_uniformly_spaced:  False
    xlen:                             100
    ylen:                             10
[17]:
quantum_device.to_json_file("devices/")
[17]:
'devices/device_2q_2024-11-13_02-36-35_UTC.json'

Single transmon qubit spectroscopy#

Here we will carry out qubit spectroscopy on a single transmon in order to find the \(|0\rangle \rightarrow |1\rangle\) drive frequency.

Qubit spectroscopy#

[18]:
def two_tone_spec_sched_nco(
    qubit,  # noqa: ANN001
    spec_pulse_frequencies: np.array,
    repetitions: int = 1,
) -> Schedule:
    """
    Generate a batched schedule for performing fast two-tone spectroscopy.

    Using the X gate to perform the frequency sweep on the qubit.

    Parameters
    ----------
    qubit
        qubit that should be used.
    spec_pulse_frequencies
        Sample frequencies for the spectroscopy pulse in Hertz.
    repetitions
        The amount of times the Schedule will be repeated.

    """
    sched = Schedule("two-tone", repetitions)

    for acq_idx, spec_pulse_freq in enumerate(spec_pulse_frequencies):
        sched.add(Reset(qubit.name))
        sched.add(X(qubit.name, freq=spec_pulse_freq))
        sched.add(Measure(qubit.name, acq_index=acq_idx), rel_time=200e-9)
    return sched
[19]:
freqs = ManualParameter(name="freq", unit="Hz", label="Frequency")
freqs.batched = True

qubit_spec_sched_kwargs = dict(
    qubit=qubit,
    spec_pulse_frequencies=freqs,
)

gettable = ScheduleGettable(
    quantum_device,
    schedule_function=two_tone_spec_sched_nco,
    schedule_kwargs=qubit_spec_sched_kwargs,
    real_imag=False,
    batched=True,
)

meas_ctrl.gettables(gettable)
[20]:
quantum_device.cfg_sched_repetitions(300)
center = 6.1e9
frequency_setpoints = np.linspace(center - 20e6, center + 20e6, 300)
meas_ctrl.settables(freqs)
meas_ctrl.setpoints(frequency_setpoints)

qs_ds = meas_ctrl.run("Two-tone")
qs_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         freq
Batch size limit: 300

/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
[20]:
<xarray.Dataset> Size: 7kB
Dimensions:  (dim_0: 300)
Coordinates:
    x0       (dim_0) float64 2kB 6.08e+09 6.08e+09 ... 6.12e+09 6.12e+09
Dimensions without coordinates: dim_0
Data variables:
    y0       (dim_0) float64 2kB nan nan nan nan nan nan ... nan nan nan nan nan
    y1       (dim_0) float64 2kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023635-397-20f804
    name:                             Two-tone
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False
[21]:
qubit.clock_freqs.f01(6.1e9)
[22]:
quantum_device.to_json_file("devices/")
[22]:
'devices/device_2q_2024-11-13_02-36-35_UTC.json'

Rabi Oscillations#

Here we will carry out an experiment to measure the Rabi frequency that is required to excite the qubit to \(|1\rangle\).

Rabi Oscillations#

[23]:
pulse_amps = np.linspace(-0.14, 0.14, 200)
sched = Schedule("rabi_amplitude", 400)

for acq_idx, pulse_amp in enumerate(pulse_amps):
    sched.add(Reset(qubit.name))
    sched.add(X(qubit.name, amp180=pulse_amp))
    sched.add(Measure(qubit.name, acq_index=acq_idx), rel_time=20e-9)  # wait 20ns before measuring

rabi_ds = run(schedule=sched, quantum_device=quantum_device)
rabi_ds
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
[23]:
<xarray.Dataset> Size: 5kB
Dimensions:      (acq_index_0: 200)
Coordinates:
  * acq_index_0  (acq_index_0) int64 2kB 0 1 2 3 4 5 ... 194 195 196 197 198 199
Data variables:
    0            (acq_index_0) complex128 3kB (nan+nanj) ... (nan+nanj)
[24]:
qubit.rxy.amp180(0.07)
[25]:
quantum_device.to_json_file("devices/")
[25]:
'devices/device_2q_2024-11-13_02-36-36_UTC.json'

T1#

Here we measure the \(T_1\) decoherence time of the qubit.

[26]:
import numpy as np
from qcodes.parameters import ManualParameter

from quantify_scheduler.gettables import ScheduleGettable
from quantify_scheduler.schedules.timedomain_schedules import t1_sched

T1#

[27]:
tau = ManualParameter(name="tau_delay", unit="s", label="Delay")
tau.batched = True

t1_sched_kwargs = {"qubit": qubit.name, "times": tau}

gettable = ScheduleGettable(
    quantum_device,
    schedule_function=t1_sched,
    schedule_kwargs=t1_sched_kwargs,
    real_imag=False,
    batched=True,
)
meas_ctrl.gettables(gettable)
[28]:
delay_setpoints = np.arange(40e-9, 200e-6, 500e-9)

meas_ctrl.settables(tau)
meas_ctrl.setpoints(delay_setpoints)

quantum_device.cfg_sched_repetitions(300)
t1_ds = meas_ctrl.run("T1 experiment")
t1_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         tau_delay
Batch size limit: 400

/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
[28]:
<xarray.Dataset> Size: 10kB
Dimensions:  (dim_0: 400)
Coordinates:
    x0       (dim_0) float64 3kB 4e-08 5.4e-07 1.04e-06 ... 0.000199 0.0001995
Dimensions without coordinates: dim_0
Data variables:
    y0       (dim_0) float64 3kB nan nan nan nan nan nan ... nan nan nan nan nan
    y1       (dim_0) float64 3kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023636-259-6f8c68
    name:                             T1 experiment
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False
[29]:
quantum_device.to_json_file("devices/")
[29]:
'devices/device_2q_2024-11-13_02-36-36_UTC.json'

Ramsey Spectroscopy#

Here we demonstrate Ramsey Spectroscopy, which is used to tune the \(|0\rangle \rightarrow |1\rangle\) drive frequency more precisely. Ramsey spectroscopy is also used to find \(T_2^*\).

Ramsey oscillations#

[30]:
tau = ManualParameter(name="tau", unit="s", label="Time")
tau.batched = True

ramsey_sched_kwargs = {
    "qubit": qubit.name,
    "times": tau,
    "artificial_detuning": 0.0,
}

gettable = ScheduleGettable(
    quantum_device,
    schedule_function=ramsey_sched,
    schedule_kwargs=ramsey_sched_kwargs,
    real_imag=False,
    batched=True,
)
meas_ctrl.gettables(gettable)
[31]:
tau_setpoints = np.arange(20e-9, 4e-6, 32e-9)

meas_ctrl.settables(tau)
meas_ctrl.setpoints(tau_setpoints)

quantum_device.cfg_sched_repetitions(500)
ramsey_ds = meas_ctrl.run("ramsey")
ramsey_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         tau
Batch size limit: 125

/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/types/qblox.py:1235: ValidationWarning: Setting `auto_sideband_cal=on_interm_freq_change` will overwrite settings `amp_ratio=1.0` and `phase_error=0.0`. To suppress this warning, do not set either `amp_ratio` or `phase_error` for this port-clock.
  warnings.warn(
/builds/qblox/packages/software/qblox_instruments_docs/.venv/lib/python3.9/site-packages/quantify_scheduler/backends/qblox/compiler_abc.py:634: RuntimeWarning: Operation is interrupting previous Pulse because it starts before the previous ends, offending operation: Pulse "Rxy(90, 0, 'q0')" (t0=0.00010002000000000001, duration=4e-08)
  warnings.warn(
[31]:
<xarray.Dataset> Size: 3kB
Dimensions:  (dim_0: 125)
Coordinates:
    x0       (dim_0) float64 1kB 2e-08 5.2e-08 8.4e-08 ... 3.956e-06 3.988e-06
Dimensions without coordinates: dim_0
Data variables:
    y0       (dim_0) float64 1kB nan nan nan nan nan nan ... nan nan nan nan nan
    y1       (dim_0) float64 1kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023636-750-341505
    name:                             ramsey
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False
[32]:
qubit.clock_freqs.f01(qubit.clock_freqs.f01() + 100e3)
[33]:
quantum_device.to_json_file("devices/")
[33]:
'devices/device_2q_2024-11-13_02-36-37_UTC.json'

Discriminated Single Shot Readout#

Here we show how to run a readout calibration experiment and fit a discriminator with a linear discriminant analysis. This experiment is sometimes called multi-state discrimination.

Schedule definition#

[34]:
def readout_calibration_sched(
    qubit: str,
    prepared_states: list[int],
    repetitions: int = 1,
    acq_protocol: Literal[
        "SSBIntegrationComplex", "ThresholdedAcquisition"
    ] = "SSBIntegrationComplex",
) -> Schedule:
    """
    Make a schedule for readout calibration.

    Parameters
    ----------
    qubit
        The name of the qubit e.g., :code:`"q0"` to perform the experiment on.
    prepared_states
        A list of integers indicating which state to prepare the qubit in before measuring.
        The ground state corresponds to 0 and the first-excited state to 1.
    repetitions
        The number of times the schedule will be repeated. Fixed to 1 for this schedule.
    acq_protocol
        The acquisition protocol used for the readout calibration. By default
        "SSBIntegrationComplex", but "ThresholdedAcquisition" can be
        used for verifying thresholded acquisition parameters.

    Returns
    -------
    :
        An experiment schedule.

    Raises
    ------
    NotImplementedError
        If the prepared state is > 1.

    """
    schedule = Schedule(f"Readout calibration {qubit}", repetitions=1)

    for i, prep_state in enumerate(prepared_states):
        schedule.add(Reset(qubit), label=f"Reset {i}")
        if prep_state == 0:
            pass
        elif prep_state == 1:
            schedule.add(Rxy(qubit=qubit, theta=180, phi=0))
        else:
            raise NotImplementedError(
                "Preparing the qubit in the higher excited states is not supported yet."
            )
        schedule.add(
            Measure(qubit, acq_index=i, bin_mode=BinMode.APPEND, acq_protocol=acq_protocol),
            label=f"Measurement {i}",
        )
    return schedule

SSRO with single side band (SSB) integration#

[35]:
states = ManualParameter(name="states", unit="", label="Prepared state")
states.batch_size = 400
states.batched = True

readout_calibration_sched_kwargs = dict(
    qubit=qubit.name, prepared_states=states, acq_protocol="SSBIntegrationComplex"
)

# set gettable
ssro_gettable = ScheduleGettable(
    quantum_device,
    schedule_function=readout_calibration_sched,
    schedule_kwargs=readout_calibration_sched_kwargs,
    real_imag=True,
    batched=True,
)

# set measurement control
meas_ctrl.gettables(ssro_gettable)
[36]:
num_shots = 1000
state_setpoints = np.asarray([0, 1] * num_shots)

# replace the get method for the gettable in case the cluster is a dummy
if "dummy" in str(cluster._transport):
    from fake_data import get_fake_ssro_data

    ssro_gettable.get = partial(get_fake_ssro_data, num_shots=num_shots)

meas_ctrl.settables(states)
meas_ctrl.setpoints(state_setpoints)

ssro_ds = dh.to_gridded_dataset(meas_ctrl.run("Single shot readout experiment"))
ssro_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         states
Batch size limit: 400

[36]:
<xarray.Dataset> Size: 48kB
Dimensions:  (x0: 2000)
Coordinates:
  * x0       (x0) int64 16kB 0 1 0 1 0 1 0 1 0 1 0 1 ... 0 1 0 1 0 1 0 1 0 1 0 1
Data variables:
    y0       (x0) float64 16kB 0.01177 0.0186 0.03126 ... 0.01101 0.03909
    y1       (x0) float64 16kB 0.01881 0.03123 0.03309 ... 0.01339 0.0264
Attributes:
    tuid:                             20241113-023637-072-4cdbd5
    name:                             Single shot readout experiment
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False

Fit line discriminator with linear discriminant analysis (LDA)#

[37]:
ssro_analysis = ReadoutCalibrationAnalysis(tuid=dh.get_latest_tuid())
ssro_analysis.run().display_figs_mpl()
../../../_images/applications_quantify_transmon_fixed_freq_transmon_56_0.png
[38]:
fit_results = ssro_analysis.fit_results["linear_discriminator"].params
acq_threshold = fit_results["acq_threshold"].value
acq_rotation = (np.rad2deg(fit_results["acq_rotation_rad"].value)) % 360

qubit.measure.acq_threshold(acq_threshold)
qubit.measure.acq_rotation(acq_rotation)

SSRO with thresholded acquisition#

[39]:
disc_ssro_gettable_kwargs = dict(
    qubit=qubit.name, prepared_states=states, acq_protocol="ThresholdedAcquisition"
)

# set gettable
disc_ssro_gettable = ScheduleGettable(
    quantum_device,
    schedule_function=readout_calibration_sched,
    schedule_kwargs=disc_ssro_gettable_kwargs,
    real_imag=True,
    batched=True,
)

# set measurement control
meas_ctrl.gettables(disc_ssro_gettable)
[40]:
num_shots = 10_000
state_setpoints = np.asarray([0, 1] * num_shots)

# replace the get method for the gettable in case the cluster is a dummy
if "dummy" in str(cluster._transport):
    from fake_data import get_fake_binary_ssro_data

    disc_ssro_gettable.get = partial(get_fake_binary_ssro_data, num_shots=num_shots)

meas_ctrl.settables(states)
meas_ctrl.setpoints(state_setpoints)

disc_ssro_ds = dh.to_gridded_dataset(meas_ctrl.run("Discriminated single shot readout experiment"))
disc_ssro_ds
Starting batched measurement...
Iterative settable(s) [outer loop(s)]:
         --- (None) ---
Batched settable(s):
         states
Batch size limit: 400

[40]:
<xarray.Dataset> Size: 480kB
Dimensions:  (x0: 20000)
Coordinates:
  * x0       (x0) int64 160kB 0 1 0 1 0 1 0 1 0 1 0 1 ... 1 0 1 0 1 0 1 0 1 0 1
Data variables:
    y0       (x0) float64 160kB 0.0 1.0 0.0 1.0 0.0 1.0 ... 1.0 0.0 0.0 0.0 1.0
    y1       (x0) float64 160kB nan nan nan nan nan nan ... nan nan nan nan nan
Attributes:
    tuid:                             20241113-023638-522-7a7579
    name:                             Discriminated single shot readout exper...
    grid_2d:                          False
    grid_2d_uniformly_spaced:         False
    1d_2_settables_uniformly_spaced:  False
[41]:
ConfusionMatrixDisplay.from_predictions(disc_ssro_ds.x0.data, disc_ssro_ds.y0.data)
plt.title("Confusion Matrix")
plt.xlabel("Measured State")
plt.ylabel("Prepared State")
[41]:
Text(0, 0.5, 'Prepared State')
../../../_images/applications_quantify_transmon_fixed_freq_transmon_61_1.png
[42]:
quantum_device.to_json_file("devices/")
[42]:
'devices/device_2q_2024-11-13_02-36-38_UTC.json'