Measure Integration Weights

In this tutorial, the Monitor Scope of the SHFQA is used to measure integration weights by acquiring readout signals while qubit in ground and excited state using the Python API. The readout pulse is generated by the SHFQA Readout Pulse Generator, and the signal acquisition is done by the SHFQA Monitor Scope. The integration weights are derived from the difference of the acquired readout signals.

Goals and Requirements

This tutorial will show users how to

  • configure input and output parameters,

  • configure Monitor Scope,

  • configure readout pulses,

  • configure the SHFQA Readout Pulse Generator,

  • run the experiment and calculate the integration weights.

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

Users can download all LabOne API Python example files introduced in this tutorial from GitHub, https://github.com/zhinst/labone-api-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 ziPython, LabOne and the Firmware of the SHFQA device 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,

  • start LabOne and open the LabOne graphical user interface using the default web browser,

  • prepare an empty python script,

  • connect the SHFQA channel 1 output (input) to the readout input (output) line.

Tutorial

Users can use the Python program below to perform integration weights measurement of 8 qubits sequentially, and each step is explained as the following.

  1. Connect the SHFQA to a host computer

    Open a daq-session to the dev-instrument using this code from the tutorial "Connecting to the instrument" and replace devXXXXX with the ID of the SHFQA instrument, e.g. dev12024).

  2. Import packages

    There a few packages are used in this tutorial. The numpy is the fundamental package for scientific computing with Python. The shf_utils is the Zurich Instruments LabOne Python API utility class for the SHF-series instrument. The helper_qubit_readout includes helper functions for qubit readout examples. The helper_commons includes common helper functions for SHFQA examples. The ziDAQServer is used to create an API session (connect to a Data Server).

    import numpy as np
    import shf_utils
    import helper_qubit_readout as helper
    import helper_commons
    from zhinst.ziPython import ziDAQServer
  3. Define measurement parameters

    In this tutorial, integration weights of 8 qubits are sequentially measured using channel 1. The readout pulses with a duration of 600 ns are repeated 100 times for each qubit, and the Monitor Scope records all readout pulses and stores 2 averaged waveforms from the first, and the second 50 pulses. Here assume that the qubits are prepared in ground state when applying the first 50 readout pulses, and in excited state when applying the second 50 readout pulses. Each recording is triggered by QA Monitor 0 set by channel0_sequencer_monitor0. The trigger delay is set to 200 ns to compensate for the delay between the Readout Pulse Generator output and the input of the integration unit.

    # define parameters
    channel_index = 0
    num_qubits = 8
    readout_duration = 600e-9
    num_segments = 2
    num_averages = 50
    num_measurements = num_segments * num_averages
    scope_channel = 0
  4. Configure input and output of the SHFQA channel 1

    The input and output settings, e.g., center frequency and power range, are defined in this step. Channel index 0 is used for this measurement, which is corresponding to channel 1 in the front panel. The center frequency is set to 5 GHz, the valid setting is from 1 GHz to 8 GHz with a granularity of 100 MHz. The input and output power are set to 0 dBm and -5 dBm, respectively. The input power range is from -50 dBm to +10 dBm and the output power range is from -30 dBm to +10 dBm. The granularity of the power range for both input and output is 5 dB. There are two integration modes, one is the spectroscopy mode which uses digital oscillators to generate the modulation, and it is generally used for resonator and qubit spectroscopy, another is the readout mode which uses the Readout Pulse Generator to generate readout sequence for standard readout with known qubit readout frequencies. The readout mode is used in this tutorial. The input and output parameters are uploaded to the instrument using function configure_channel.

    # configure inputs and outputs
    shfqa.configure_channel(
        channel_index,
        center_frequency=5e9,
        input_range=0,
        output_range=-5,
        mode="readout",
    )
  5. Configure the SHFQA Monitor Scope

    The Monitor Scope of channel 1 is configured to record readout pulses. The recorded length is 600 ns, the number of averages is 50, and 2 segments in total for each qubit. The Monitor Scope is triggered by the "sequencer_monitor0", which can be enabled using the SeqC command startQA. The trigger delay setting is to compensate for the delay between generator output and input of the integration unit.

    # configure scope
    shfqa.configure_scope(
        input_select={scope_channel: f"channel{channel_index}_signal_input"},
        num_samples=int(readout_duration * shf_utils.Shfqa.SAMPLING_FREQUENCY),
        trigger_input=f"channel{channel_index}_sequencer_monitor0",
        num_segments=num_segments,
        num_averages=num_averages,
        # compensation for the delay between generator output and input of the integration unit
        trigger_delay=200e-9,
    )
  6. Generate and upload readout pulses

    The readout pulses can be defined sample-by-sample by users. They are uploaded to the waveform memory and then used by the Readout Pulse Generator.

    The offset frequencies are defined from 2 MHz to 32 MHz for 8 qubits. The frequency of each readout pulse is the sum of the center frequency and the offset frequency. The flat-top Gaussian readout pulses with pulse duration of 500 ns and rise and fall time of 10 ns are generated using the helper function generate_flat_top_gaussian. They are then uploaded to the waveform memory of channel 1.

    excitation_pulses = helper_commons.generate_flat_top_gaussian(
        frequencies=np.linspace(2e6, 32e6, num_qubits),
        pulse_duration=500e-9,
        rise_fall_time=10e-9,
        sampling_rate=shf_utils.Shfqa.SAMPLING_FREQUENCY,
    )
    shfqa.write_to_waveform_memory(channel_index, waveforms=excitation_pulses)
  7. Configure the Readout Pulse Generator and run the experiment

    A for loop is used to measure the integration weights of 8 qubits sequentially. For each qubit, a new SeqC program is generated and uploaded according to the task "dig_trigger_play_single". Depends on the index of the qubits, the SeqC program plays readout pulses from different waveform memory blocks set by the first argument of the command startQA. The third argument of this command true means that a monitor trigger is enabled. This trigger is then used for triggering the Monitor Scope.

    repeat({num_measurements}) {{
        waitDigTrigger(1);
        startQA(QA_GEN_{waveform_slot}, 0x0, true,  0, 0x0);
    }}

    Before the measurement begins, the scope and the Readout Pulse generator have to be enabled, so that they are ready to receive triggers. By turn on a continuous software trigger, the Readout Pulse Generator is triggered, and the measurement starts. The continuous software trigger is configured such that it generates 100 triggers with a duration of 600 ns for each loop.

    The integration weights including real and imaginary parts are calculated from the difference of 2 averaged data acquired by the Monitor Scope. Here the assumption is that the qubit is prepared in ground state in the first 50 measurements and in excited state in the second 50 measurements. With the helper function, the real and imaginary part of the readout pulse and the calculated integration weights can be plotted, as shown in Figure 1 and Figure 2.

    # configure sequencer
    shfqa.configure_sequencer_triggering(channel_index, aux_trigger="software_trigger0")
    
    # run experiment measurement loop
    weights = {}
    for i in range(num_qubits):
    
    print(f"Measuring qubit {i}.")
    
    # upload sequencer program
    seqc_program = helper.generate_sequencer_program(
        num_measurements=num_measurements,
        task="dig_trigger_play_single",
        waveform_slot=i,
    )
    shfqa.load_sequencer_program(channel_index, sequencer_program=seqc_program)
    
    # start a measurement
    shfqa.enable_scope()
    shfqa.enable_sequencer(channel_index)
    shfqa.start_continuous_sw_trigger(
        num_triggers=num_measurements, wait_time=readout_duration
    )
    
    # get results to calculate weights and plot data
    scope_data, *_ = shfqa.get_scope_data(time_out=5)
    
    weights[i] = helper.calculate_readout_weights(scope_data[scope_channel])
    
    if plot:
        helper.plot_scope_data_for_weights(
            scope_data[scope_channel],
            sampling_rate=shf_utils.Shfqa.SAMPLING_FREQUENCY,
        )
        helper.plot_readout_weights(
            weights[i], sampling_rate=shf_utils.Shfqa.SAMPLING_FREQUENCY
        )
    scope data for weights
    Figure 1. Readout pulses acquired by the SHFQA monitor scope.
readout weigths
Figure 2. Integration weights calculated from Figure 1.