Multiplexed Qubit Readout¶
Note
This tutorial is applicable to all SHFQA Instruments.
Goals and Requirements¶
The goal of this tutorial is to demonstrate how to use SHFQA to perform multiplexed qubit readout using Zurich Instruments Toolkit API.
For qubit control with the SHFSG Signal Generator, the SHFQC Qubit Controller and the HDAWG Arbitrary Wave Generator, and instrument synchronization and feedback with the PQSC Programmable Quantum System Controller, see tutorials in the Online Documentation.
Note
Users can download all zhinst-toolkit example files introduced in this tutorial from GitHub, https://github.com/zhinst/zhinst-toolkit/tree/main/examples.
Preparation¶
The tutorial starts with the instrument in the default configuration (e.g., after a power cycle). For an optimal tutorial experience, please follow these preparation steps:
- ensure that the version of the LabOne Python API, LabOne and the Firmware of the SHFQA device, zhinst-toolkit (pip install zhinst-toolkit) and Python (3.7 or newer) are updated and compatible,
- make sure that the Instrument is powered on and connected by Ethernet to your local area network (LAN) where the host computer resides or by USB (Maintenance port) to the host computer,
- start LabOne and open the LabOne Graphical User Interface using the default web browser,
- connect the SHFQA Quantum Analyzer channel channel output (input) to the readout input (output) line, see SHFQA connection.
Tutorial¶
-
Connect the instrument
Create a toolkit session to the data server and connect the device with the device ID, e.g. 'DEV12001', see Using the Python API.
from zhinst.toolkit import Session, SHFQAChannelMode, Waveforms from scipy.signal.windows import gaussian import numpy as np DEVICE_ID = 'DEVXXXXX' SERVER_HOST = 'localhost' session = Session(SERVER_HOST) ## connect to data server device = session.connect_device(DEVICE_ID) ## connect to device
-
Generate readout pulses and integration weights
To readout 8 qubits in parallel, 8 readout pulses with different amplitude, frequency and phase are summed up to generate a single output signal. Please note that the maximum amplitude of the sum of all readout pulses should not exceed 1.
In this tutorial, the envelope of all readout pulses is flat-top Gaussian with pulse length of 500 ns and rise and fall time of 10 ns, all amplitude are equally scaled by a factor of 0.9 and divided by the number of qubits, 8 readout frequencies span from 32 MHz to 100 MHz, and all phases are set to 0.
In Readout mode, the frequency down-converted signal is integrated with the integration weights. Tutorial Integration Weights Measurement. shows how to measure integration weights to improve the SNR. In this tutorial, conjugated readout pulses with the amplitude scaling factor of 1 are used and uploaded to the integration weight memory. The integration delay can be measured with the scope, see Integration Weights Measurement.
# generate readout pulses NUM_QUBITS = 8 RISE_FALL_TIME = 10e-9 # in units of second SAMPLING_RATE = 2e9 # in units of Hz PULSE_DURATION = 500e-9 # in units of second FREQUENCIES = np.linspace(32e6, 150e6, NUM_QUBITS) # in units of Hz SCALING = 0.9 / NUM_QUBITS # amplitude scaling factor rise_fall_len = int(RISE_FALL_TIME * SAMPLING_RATE) pulse_len = int(PULSE_DURATION * SAMPLING_RATE) std_dev = rise_fall_len // 10 gauss = gaussian(2 * rise_fall_len, std_dev) flat_top_gaussian = np.ones(pulse_len) flat_top_gaussian[0:rise_fall_len] = gauss[0:rise_fall_len] flat_top_gaussian[-rise_fall_len:] = gauss[-rise_fall_len:] flat_top_gaussian *= SCALING time_vec = np.linspace(0, PULSE_DURATION, pulse_len) readout_pulses = Waveforms() for i, f in enumerate(FREQUENCIES): readout_pulses.assign_waveform( slot=i, wave1=flat_top_gaussian * np.exp(2j * np.pi * f * time_vec) ) # generate integration weights ROTATION_ANGLE = 0 weights = Waveforms() for waveform_slot, pulse in readout_pulses.items(): weights.assign_waveform( slot=waveform_slot, wave1=np.conj(pulse[0] * np.exp(1j * ROTATION_ANGLE)) / np.abs(pulse[0]) )
-
Configure the Channel
Configure the Channel such that the readout pulses are integrated with different integration weights in parallel, and the measurement is repeated 10000 times.
The input range and output range of the Channel 1 is set to -30 dBm, and the center frequency is 5 GHz. There are 2 application modes see Quantum Analyzer Setup Tab. For multiplex readout, Readout mode is selected in order to use customized integration weights for different qubits.
The Readout pulses and integration weights with assigned waveform memory slots are uploaded to the waveform memory after clear all waveforms which may saved in the waveform memory previously.
The measurement sequence is defined by the SeqC program such that it sends out the readout pulse and integrates the signal for 500 ns with the integration delay of 220 ns after receiving a software trigger. The measurement is repeated 10000 times.
The result after integration and averaging will be saved to the QA Result Logger. This configuration can be used to calibrate control pulses and characterize the qubits, measure thresholds without averaging for state discrimination or readout fidelity if the result source is set to 'result_of_discrimination' and the thresholds are updated using device.qachannels[CHANNEL_INDEX].readout.discriminators[n].threshold (n is the qubit index).
# configure inputs and outputs CHANNEL_INDEX = 0 # physical Channel 1 NUM_READOUTS = 100 NUM_AVERAGES = 100 MODE_AVERAGES = 0 # 0: cyclic; 1: sequential; INTEGRATION_TIME = PULSE_DURATION # in units of second device.qachannels[CHANNEL_INDEX].configure_channel( center_frequency=5e9, # in units of Hz input_range=-30, # in units of dBm output_range=-30, # in units of dBm mode=SHFQAChannelMode.READOUT, # READOUT or SPECTROSCOPY ) device.qachannels[CHANNEL_INDEX].input.on(1) device.qachannels[CHANNEL_INDEX].output.on(1) # upload readout pulses and integration weights to waveform memory device.qachannels[CHANNEL_INDEX].generator.clearwave() # clear all readout waveforms device.qachannels[CHANNEL_INDEX].generator.write_to_waveform_memory(readout_pulses) device.qachannels[CHANNEL_INDEX].readout.integration.clearweight() # clear all integration weights device.qachannels[CHANNEL_INDEX].readout.write_integration_weights( weights=weights, # compensation for the delay between generator output and input of the integration unit integration_delay=220e-9 ) # configure sequencer device.qachannels[CHANNEL_INDEX].generator.configure_sequencer_triggering( aux_trigger="software_trigger0", # chanNtriginM, chanNseqtrigM, chanNrod play_pulse_delay=0, # 0s delay between startQA trigger and the readout pulse ) loop_string = f""" repeat({NUM_AVERAGES}) {{ repeat({NUM_READOUTS}) {{ """ if MODE_AVERAGES == 1: loop_string = f""" repeat({NUM_READOUTS}) {{ repeat({NUM_AVERAGES}) {{ """ seqc_program = f""" {loop_string} waitDigTrigger(1); startQA(QA_GEN_ALL, QA_INT_ALL, true, 0, 0x0); }} }} """ device.qachannels[CHANNEL_INDEX].generator.load_sequencer_program(seqc_program) # configure QA setup and QA result logger device.qachannels[CHANNEL_INDEX].readout.integration.length(int(INTEGRATION_TIME * SAMPLING_RATE)) device.qachannels[CHANNEL_INDEX].readout.configure_result_logger( result_length=NUM_READOUTS, result_source='result_of_integration', # “result_of_integration” or “result_of_discrimination”. num_averages=NUM_AVERAGES, averaging_mode=MODE_AVERAGES, )
-
Run the measurement and download the result
Before starting the measurement, the QA Result Logger is enabled to be ready to get the result, and the Sequencer is enabled to be ready to run the sequence once receive a software trigger. The software trigger is configured to be repeated 100 times with a cycle duration of 2 ms. The measurement result can be downloaded and processed for different purposes, and it can also be displayed in QA Result Logger Tab see Figure 2.
device.qachannels[CHANNEL_INDEX].readout.run() # enable QA Result Logger device.qachannels[CHANNEL_INDEX].generator.enable_sequencer(single=True) device.start_continuous_sw_trigger( num_triggers=NUM_READOUTS * NUM_AVERAGES, wait_time=2e-3 ) readout_results = device.qachannels[CHANNEL_INDEX].readout.read()
Figure 2: Multiplexed readout of 8 qubits in loopback configuration.