# Minimal Setup Requirements

For the experiments described in this section, we require a minimal setup consisting of a single Zurich Instruments HDAWG Arbitrary Waveform Generator as well as one UHFQA Quantum Analyzer, connected to a PQSC Programmable Quantum System Controller. Additionally, we assume an external 10 MHz clock is available as a common reference for synchronization between UHFQA and PQSC. Alternatively, the descriptor below could be replaced with a setup using a SHFQA, SHFSG, and PQSC or a standalone SHFQC.

In the Single Qubit Tuneup Notebook the code is organized in sections and is intended to be executed from top to bottom. Here we will only discuss the most relevant code blocks for the single qubit calibration experiments. Many details of the setup definition and configuration have already been discussed previously in Setting up Devices.

The notebook starts with import statements for required python modules as well as some definitions of additional helper functions - these are mostly used for data handling, fitting of results and extraction of parameters. Next, we define a setup descriptor, which provides information on the setup used, specifically the identifiers for the HDAWG, the UHFQA and the PQSC as well as the IP address and port number of the LabOne dataserver used to connect to the instruments.

descriptor_mySetup="""\
instruments:
HDAWG:
uid: device_hdawg
UHFQA:
uid: device_uhfqa
PQSC:
uid: device_pqsc
connections:
device_hdawg:
- iq_signal: q0/drive_line
ports: [SIGOUTS/0, SIGOUTS/1]
- iq_signal: q1/drive_line
ports: [SIGOUTS/2, SIGOUTS/3]
- rf_signal: q0/flux_line
ports: [SIGOUTS/4]
- rf_signal: q1/flux_line
ports: [SIGOUTS/5]
- to: device_uhfqa
port: DIOS/0
device_uhfqa:
- iq_signal: q0/measure_line
ports: [SIGOUTS/0, SIGOUTS/1]
- acquire_signal: q0/acquire_line
- iq_signal: q1/measure_line
ports: [SIGOUTS/0, SIGOUTS/1]
- acquire_signal: q1/acquire_line
device_pqsc:
- to: device_hdawg
port: ZSYNCS/0
"""

This descriptor will be consumed by a function that creates the DeviceSetup object containing information on the instruments and their wiring. For the simple examples here, the instrument wiring is very basic; the IQ drive for the two qubits is provided by the first two channel pairs of the HDAWG, and the next channel pair can be used for flux biasing of the two qubits. The UHFQA is set up to generate the qubit readout pulses and digitize and analyze the return signals. The PQSC generates the central trigger and controls the HDAWG directly through a ZSync connection and the UHFQA indirectly via its DIO connection to the HDAWG.

We also define a dictionary of qubit parameters. These will be used in the experiments as pulse parameters, and some of them, like the readout resonator frequency, will be updated by the experimental results. Some of these parameters will also be used to configure the device settings, like the oscillator frequency used to modulate the signal on the qubit drive line.

# a collection of qubit parameters - change as appropriate
qubit_parameters = {
'ro_freq_q0' :  50e6,       # readout frequency of qubit 0 in [Hz] - relative to local oscillator for readout drive upconversion
'ro_freq_q1' :  100e6,      # readout frequency of qubit 1 in [Hz] - relative to local oscillator for readout drive upconversion
'ro_amp' : 1.0,             # readout amplitude
'ro_amp_spec': 1.0,         # readout amplitude for spectroscopy
'ro_len' : 1.0e-6,          # readout pulse length in [s]
'ro_len_spec' : 15e-6,      # readout pulse length for spectroscopy in [s]
'ro_delay': 100e-9,         # readout delay after last drive signal in [s]
'ro_int_delay' : 500e-9,    # readout line offset calibration - delay between readout pulse and start of signal acquisition in [s]
'qb0_freq': 100e6,          # qubit 0 drive frequency in [Hz] - relative to local oscillator for qubit drive upconversion
'qb1_freq': 50e6,           # qubit 1 drive frequency in [Hz] - relative to local oscillator for qubit drive upconversion
'qb_amp_spec': 1.0,         # drive amplitude of qubit spectrosopy
'qb_len_spec': 15e-6 ,      # drive pulse length for qubit spectroscopy in [s]
'qb_len' : 20e-9,           # qubit drive pulse length in [s]
'pi_amp' : 1.0,             # qubit drive amplitude for pi pulse
'pihalf_amp' : 0.5,         # qubit drive amplitude for pi/2 pulse
'ramsey_det' : 1e6,         # detuning applied to drive for Ramsey experiment  in [Hz]
'T1' : 10e-6,               # qubit lifetime T1 in [s]
'T2_ramsey' : 10e-6,        # qubit dephasing time T2 in [s]
'relax' : 100e-6            # delay time after each measurement for qubit reset (minimum time 1us - signal acquisiton and processing delay of UHFQA) in [s]
}

In the notebook, we also define a dictionary containing settings for local oscillators — the qubit and readout resonator frequencies above are to be understood with respect to these local oscillator frequencies. In our code these numbers are just used for plotting purposes, but in a real experiment these would be relevant for the up/down-conversion of the intermediate frequency (IF) signals generated by the HDAWG and the UHFQA to the microwave range relevant for superconducting qubits.

# up / downconversion settings - to convert between IF and RF frequencies
lo_settings = {
'qb_lo': 5.3e9,               # qubit LO frequency in [Hz]
'ro_lo': 6.4e9                # readout LO frequency in [Hz]
}

We next create a device setup object from the descriptor defined in the python notebook and apply the qubit configuration to it. We apply a calibration, where define_calibration is given in this example notebook. We also define some handy shortcuts for later use when setting the oscillator properties for different experiments.

# create device setup from descriptor and apply calibration
my_setup = DeviceSetup.from_descriptor(
descriptor_mySetup,
server_port="8004",
setup_name="mySetup",
)

# define Calibration object
my_calibration = define_calibration(parameters=qubit_parameters)
# apply calibration to device setup
my_setup.set_calibration(my_calibration)

## define shortcut to logical signals for convenience
lsg_q0 = my_setup.logical_signal_groups["q0"].logical_signals
drive_Oscillator_q0 = lsg_q0['drive_line'].oscillator
acquire_Oscillator_q0 = lsg_q0['acquire_line'].oscillator

lsg_q1 = my_setup.logical_signal_groups["q1"].logical_signals
drive_Oscillator_q1 = lsg_q1['drive_line'].oscillator
acquire_Oscillator_q1 = lsg_q1['acquire_line'].oscillator
In the final initialization step, we create a session, using the configured setup created above, and then connect to it. Here, we can choose if we want to run the experiments on real instruments or as a trial run in emulation mode, by changing the variable emulate to either False (real hardware) or True (emulation only). The emulation mode also creates dummy data instead of providing measurement data.
# perform experiments in emulation mode only? - if True, also generates dummy data for fitting
my_session.connect(do_emulation=emulate)