Skip to content

Integration Weights Measurement


This tutorial is applicable to all SHFQA Instruments and no additional instrumentation is needed.

Goals and Requirements

The goal of this tutorial is to demonstrate how to use the SHFQA Scope to measure integration weights that are needed for high-fidelity single-shot 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.


Users can download all zhinst-toolkit example files introduced in this tutorial from GitHub,


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

output (input) to the readout input (output) line, see SHFQA connection.

Figure 1: SHFQA connection.


In the tutorial, readout signals are acquired while the qubit is in ground and excited state. The readout pulse is generated by the SHFQA Readout Pulse Generator, and the signal acquisition is done by the SHFQA Scope. The integration weights are derived from the difference of the acquired readout signals.

  1. 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.

    # Load the LabOne API and other necessary packages
    from zhinst.toolkit import Session, SHFQAChannelMode, Waveforms
    from import gaussian
    import numpy as np
    SERVER_HOST = 'localhost'
    session = Session(SERVER_HOST)              ## connect to data server
    device = session.connect_device(DEVICE_ID)  ## connect to device
  2. Generate readout pulses

    Generate a flat-top Gaussian readout pulses with 8 offset frequencies, see Multiplexed Qubit Readout.

    NUM_QUBITS = 8
    RISE_FALL_TIME = 10e-9
    PULSE_DURATION = 500e-9
    rise_fall_len = int(RISE_FALL_TIME * SAMPLING_FREQUENCY)
    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:]
    # Scaling
    flat_top_gaussian *= 0.9
    readout_pulses = Waveforms()
    time_vec = np.linspace(0, PULSE_DURATION, pulse_len)
    for i, f in enumerate(np.linspace(2e6, 32e6, NUM_QUBITS)):
            wave1=flat_top_gaussian * np.exp(2j * np.pi * f * time_vec)
  3. Configure the channel

    Configure the channel to run in Readout mode, upload and send 100 readout pulses in which 50 of them to readout qubit in excited state and the rest for qubit in ground state, see Multiplexed Qubit Readout.

    # configure inputs and outputs
    CHANNEL_INDEX = 0 # physical Channel 1
        center_frequency=5e9, # in units of Hz
        input_range=0, # in units of dBm
        output_range=-5, # in units of dBm
        mode=SHFQAChannelMode.READOUT, # SHFQAChannelMode.READOUT or SHFQAChannelMode.SPECTROSCOPY
    # configure Generator
        aux_trigger="software_trigger0",# chanNtriginM, chanNseqtrigM, chanNrod
        play_pulse_delay=0, # 0s delay between startQA trigger and the readout pulse
  4. Configure the Scope

    Configure the Scope to record 2 segments of data which are averaged 50 times. The trigger of the Scope is the Channel 1 Sequencer monitor Trigger which is enabled by the startQA command.

    RECORD_DURATION = 600e-9 # in units of second
    SAMPLING_FREQUENCY = 2e9 # in units of Hz
        input_select={SCOPE_CHANNEL: f"channel{CHANNEL_INDEX}_signal_input"},
        num_samples=int(RECORD_DURATION * SAMPLING_FREQUENCY),
        trigger_input=f"channel{CHANNEL_INDEX}_sequencer_monitor0", # Sequencer 1 monitor trigger
        trigger_delay=200e-9, # in units of second, record the data 200 ns later after receiving a trigger
  5. Run the measurement and calculate the integration weights

    The integration weights for different qubits are measured sequentially with the for loop. In each loop, the Generator sends 100 pulses to readout 1 of the qubits prepared in ground and excited state, and the Scope acquires 2 segments of data which are averaged 50 times (see Figure 2), and the integration weights are calculated and plotted from the downloaded data (see Figure 3).

    results = []
    for i in range(NUM_QUBITS):
        qubit_result = {
            'weights': None,
            'ground_states': None,
            'excited_states': None
        print(f"Measuring qubit {i}.")
        # upload sequencer program
        seqc_program = f"""
            repeat({NUM_MEASUREMENTS}) {{
                startQA(QA_GEN_{i}, 0x0, true,  0, 0x0); // only QA_GEN_{i} matters for this measurement
        # Start a measurement
            num_triggers=NUM_MEASUREMENTS, wait_time=RECORD_DURATION
        # get results to calculate weights and plot data
        scope_data, *_ = device.scopes[0].read()
        # Calculates the weights from scope measurements
        # for the excited and ground states
        split_data = np.split(scope_data[SCOPE_CHANNEL], 2)
        ground_state_data = split_data[0]
        excited_state_data = split_data[1]
        qubit_result['ground_state_data'] = ground_state_data
        qubit_result['excited_state_data'] = excited_state_data
        qubit_result['weights'] = np.conj(excited_state_data - ground_state_data)

    Figure 2: Readout pulses recorded by the Scope in loopback configuration

    Figure 3: Integration weights calculated from the readout pulses


In order to achieve the highest possible resolution in the signal after integration, it’s advised to scale the dimensionless readout integration weights with a factor so that their maximum absolute value is equal to 1.