Skip to content

Multiplexed Qubit Readout

Note

This tutorial is applicable to all SHFQC+ Instruments.

Goals and Requirements

The goal of this tutorial is to demonstrate how to use SHFQC+ to perform multiplexed qubit readout using the LabOne User Interface (UI) and 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 section under a specific instrument found in the Online Documentation.

Note

For zhinst-toolkit users, please find the example in https://github.com/zhinst/zhinst-toolkit/blob/main/examples/shfqa_qubit_readout_measurement.md, and the zhinst-toolkit documentation.

For SHFQC+ users, please find the examples in GitHub, https://github.com/zhinst.

Preparation

Please follow the preparation steps in Connecting to the Instrument and connect the instrument in a loopback configuration as shown in Figure 1 or to a signal under test.

Figure 1: SHFQC+ connection.

Tutorial

In this tutorial, the instrument runs a measurement that performs readout of 8 qubits in parallel. The measurement is repeated 100 \(\times\) 100 times and 100 averaged complex-valued results are returned.

This section shows how to use LabOne UI to configure the instrument, run the measurement and monitor the measurement results.

  1. Configure the instrument

    1. Set center frequency and power range of input and output signals

      Configure these parameters on the Input and Output Tab as in Figure 2 and in Table 1.

      Figure 2: Configurations on In/Out Tab.

      Table 1: Settings of QA Channel 1 on In/Out Tab
      Parameter Setting Description
      QA Channel Selection All Select All to display all QA Channels.
      Cent Freq (Hz) 5 GHz Set center frequency of the frequency sweep.
      Signal Input 1 On Enable Enable the Signal Input 1.
      Signal Input 1 Range (dBm) 0 dBm Set power range of Signal Input 1 to 0 dBm. This setting allows the instrument to acquire a input signal with a power up to 0 dBm.
      Signal Input 1 Input Path RF Set input path of Signal Input 1 to RF path.
      Signal Output 1 On Enable Enable the Signal Output 1.
      Signal Output 1 Range 0 dBm Set power range of Signal Output 1 to 0 dBm. This setting allows the instrument to output a signal with a power up to 0 dBm.
      Signal Output 1 Output Path RF Set output path of the Signal Output 1 to RF path.
    2. Upload and compile measurement sequence

      The measurement sequence is defined on the Sequence Sub-Tab of the Readout Pulse Generator Tab, see Figure 3 and Table 2.

      Figure 3: Configurations on Readout Pulse Generator Tab.

      Table 2: Settings of QA Channel 1 on Readout Pulse Generator Tab.
      Parameter Setting Description
      QA Channel Selection 1 Select QA Channel 1.
      Sub-Tab Display Sequence Select Sequence sub-tab and paste the sequence program below. The Waveform Viewer sub-tab displays waveforms saved in Waveform Memory slots and Integration Weight units.
      Compile Click "To Device" Compile the sequence program by clicking "To Device".
      Digital Triggers Digital Trigger 1 Select Digital Trigger 1.
      Digital Trigger 1 Signal Internal Trigger Select Internal Trigger as the trigger source of Digital Trigger 1.
      Return Disable Disable return function.
      Run/Stop Enable Run the sequence.

      Below is the the sequence program for the measurement. In the inner loop, the waitDigTrigger(1) command waits for a digital trigger to continue the sequence, the first playZero command sets the waiting time after receiving a trigger before running the startQA command, the startQA(QA_GEN_ALL, QA_INT_ALL, true) command sends a trigger to generate output waveform and start integration. The measurement is repeated 100 times by the outer loop.

      // repeat sequence 10000 times
      repeat (100) {
          repeat (100) {
              // wait for a trigger over ZSync. Assume the trigger period is longer than the cycle time
              // waitZSyncTrigger();
      
              // alternatively wait for a trigger from digital trigger 1
              waitDigTrigger(1);
      
              // wait for 4096 Samples between the trigger and the first readout pulse
              // Note: this playZero command does not yet block the sequencer
              playZero(4096);
      
              // define how many samples to wait between the two upcoming startQA commands
              // Note: this command blocks the sequencer until the previous playZero command is finished
              playZero(32);
      
              // play all pulses stored in Waveform Memory and read out using all Integration Weights
              startQA(QA_GEN_ALL, QA_INT_ALL);
          }
      }
      

      The digital trigger set on the Trigger sub-tab is the Internal Trigger. The configuration of the Internal Trigger is shown in Figure 4 and Table 3.

      Figure 4: Configurations of Internal Trigger on DIO Tab.

      Table 3: Settings of Internal Trigger on DIO Setup Tab, see details on
      Parameter Setting Description
      Repetitions 10000 Set number of repetitions.
      Holdoff (s) 100u Set holdoff time to 100 \(\mu\)s.
      Synchronization Disable Disable Synchronization.
      Run/Stop Disable Disable the internal trigger.
    3. Configure signal generation and data acquisition

      Signal generation and data acquisition are defined on QA Setup Tab and QA Result logger Tab.

      Figure 5: Configurations on QA Setup Tab.

      The baseband readout waveform is generated by summing up all waveforms saved in the Waveform Memory. The input signal after frequency down-conversion is integrated with 8 integration weights saved in integration weight units for 2048 ns started 224 ns after receiving a digital trigger.

      We use Readout mode for multiplex qubit readout (Table 4) and generate both readout waveforms and integration weights parametrically (Table 5 and Table 6). In this tutorial, the integration weight is simply a conjugate of the readout waveforms. To achieve high readout fidelity optimal weights should be measured and uploaded, see how to measure optimal weights in Integration Weights Measurement. Thresholds need to be uploaded if qubit state discrimination is required.

      Table 4: Application Settings of QA Channel 1 on QA Setup Tab.
      Parameter Setting Description
      QA Channel Selection 1 Select QA Channel 1.
      Application Mode Readout Use Readout mode for multiplex qubit readout. In Readout mode, the output waveform is generated by summing up all readout waveforms in the Waveform Memory slots, thus the instrument is able to readout up to 16 qubits per channel in parallel. In spectroscopy mode, the readout waveform is generated by a digital oscillator. Since there is only 1 digital oscillator per channel, only single qubit readout is possible in Spectroscopy mode.
      Integration Delay (s) 224 n Set the delay time after receiving a trigger before starting integration. This setting ensures that only the expected input signal is integrated. The internal delay from signal generation to integration is about 224 ns. Therefore, an integration delay > 224 ns is necessary if the propagation delay from front panel signal output port to signal input port is not negligible.
      Table 5: Readout Pulse Generation Settings of QA Channel 1 on QA Setup Tab.
      Parameter Setting Description
      QA Channel Selection 1 Select QA Channel 1.
      Clear Waveform Click "Clear" Clear all waveforms saved in Waveform Memory. Clear all waveforms before uploading new ones to avoid incorrect waveform generation or output overflow.
      Waveform Memory \(i\) Set Mode Parametric Generate waveform parametrically saved in Waveform Memory slot \(i\) (\(i\) is from 1 to 8). The parametrically generated waveform is \(Ae^{i (2 \pi f t + \frac{\pi}{180}\phi)}\), where \(A\) is the dimensionless amplitude factor of the waveform, \(f\) is the frequency in units of Hz, \(\phi\) is the phase in units of degree.
      Waveform Memory \(i\) Amplitude 0.1 Set amplitude factor \(A\) of the parametrically generated waveform saved in Waveform Memory slot \(i\) (\(i\) is from 1 to 8) to 0.1. This setting ensures the amplitude factor of sum of all waveforms is \(\le\) 1.
      Waveform Memory \(i\) Frequency (Hz) 10e6\(\times i\) Set readout frequency \(f\) of the parametrically generated waveform saved in Waveform Memory slot \(i\) (\(i\) is from 1 to 8) to 10e6\(\times i\) Hz.
      Waveform Memory \(i\) Phase (Deg) 0 Set phase \(\phi\) of the parametrically generated waveform saved in Waveform Memory slot \(i\) (\(i\) is from 1 to 8) to 0 degree.
      Waveform Memory \(i\) Window Length 4096 Set length of the parametrically generated waveform saved in Waveform Memory slot \(i\) (\(i\) is from 1 to 8) in number of samples.
      Waveform Memory \(i\) Set To Device click "Set To Device" Upload the parametrically generated waveform to Waveform Memory slot \(i\) (\(i\) is from 1 to 8).
      Table 6: Integration Weights Settings of QA Channel 1 on QA Setup Tab.
      Parameter Setting Description
      QA Channel Selection 1 Select QA Channel 1.
      Integration Length 4096 Set the integration length in number of samples.
      Clear Weights Click "Clear" Clear all weights saved in Integration Weight slots. Clear all weights before uploading new ones to avoid incorrect weight generation.
      Integration Weights \(i\) Set Mode Parametric Generate integration weight parametrically saved in Integration Weights unit \(i\) (\(i\) is from 1 to 8). The parametrically generated integration weight is \(A'e^{-i (2 \pi f' t + \frac{\pi}{180}\phi)'}\), where \(A'\) is the dimensionless amplitude factor of the integration weight, \(f'\) is the frequency in units of Hz, \(\phi'\) is the phase in units of degree.
      Integration Weights \(i\) Amplitude 1 Set amplitude factor \('A\) of the parametrically generated integration weight saved in Integration Weights unit \(i\) (\(i\) is from 1 to 8)
      Integration Weights \(i\) Frequency (Hz) 10e6\(\times i\) Set readout frequency \(f'\) of the parametrically generated integration weight saved in Integration Weights unit \(i\) (\(i\) is from 1 to 8) to 10e6\(\times i\) Hz same as the frequency of readout waveform saved in Waveform Memory slot i.
      Integration Weights \(i\) Phase (Deg) 0 Set phase \(\phi'\) of the parametrically generated integration weight saved in Integration Weights unit \(i\) (\(i\) is from 1 to 8) to 0 degree.
      Integration Weights \(i\) Window Length 4096 Set length of the integration weight saved in Integration Weights unit \(i\) (\(i\) is from 1 to 8) in number of samples.
      Integration Weights \(i\) Set To Device Click "Set To Device" Upload the parametrically generated integration weight to Integration Weight unit 1. Use the same setting for 8 integration weights saved in the first 8 Integration Weight Units.

      How the measurement results are averaged and displayed are defined on QA Result Logger Tab, see Figure 6 and Table 7.

      Figure 6: Configurations on QA Result Logger Tab.

      Table 7: Settings of QA Channel 1 on QA Result Logger Tab, see details on
      Parameter Setting Description
      QA Channel Selection 1 Select QA Channel 1.
      Sub-Tab Readout Select Readout sub-tab to monitor measurement result in Readout Mode.
      Display Source Integration Display result after integration to monitor results in IQ plane. Choose "Integration (I, Q, Amp, Phase)" If it is desired. Choose "Threshold" if qubit state discrimination is desired.
      Result Length (Sample) 100 Set result length in number of samples. The number must match what is set in the sequence program.
      Averages 100 Set the number of averages. The number must match what is set in the sequence program.
      Average Mode Cyclic Set the average mode to cyclic. This setting must match how the loop is configured in the sequence program.
      Vertical Axis Groups Add QA 1 Result \(i\) Wave Value (\(i\) is from 1 to 8) Add 8 qubit results to the plot.
      Run/Stop Enable Run the result logger to receive and display measurement results.
  2. Run the measurement

    Click "Run/Stop" icon on the System Settings sub-tab of DIO tab to run the measurement.

  3. Monitor the measurement results

    The measurement result is displayed on QA Result Tab, as shown in Figure 7. The data format of measurement result is complex data. The spread of the readout results indicates that each component of the input signal has a similar amplitude but different phase delay.

    Figure 7: Measurement results on QA Result Logger Tab.

  1. Connect the instrument

    Create a toolkit session to the data server and connect the device with the device ID, e.g. 'DEV12001', see Connecting to the Instrument.

    from zhinst.toolkit import Session, SHFQAChannelMode, Waveforms
    from scipy.signal 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
    
  2. 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.

    # 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, 120e6, 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])
        )
    

    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 120 MHz, and all phases are set to 0. The zhinst-toolkit class Waveforms is for converting waveform data written in Python to data that can be uploaded to the instrument correctly.

    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 SHFQC+ Scope triggered by Sequencer Monitor Trigger.

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

    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
    
    # 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=224e-9
    )
    
    with device.set_transaction():
        # configure inputs and outputs
        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)
    
        # configure sequencer
        device.qachannels[CHANNEL_INDEX].generator.configure_sequencer_triggering(
            aux_trigger=8, # internal trigger
            play_pulse_delay=0, # 0s delay between startQA trigger and the readout pulse
        )
    
        seqc_program = f"""
            repeat({int(NUM_READOUTS * NUM_AVERAGES)}){{
                waitDigTrigger(1);
                startQA(QA_GEN_ALL, QA_INT_ALL, true, 0, 0x0);
            }}
        """
        device.qachannels[CHANNEL_INDEX].generator.load_sequencer_program(seqc_program)
    
        # configure internal trigger
        device.system.internaltrigger.repetitions(int(NUM_READOUTS * NUM_AVERAGES))
        device.system.internaltrigger.holdoff(100e-6)
    
        # 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,
        )
    

    The Readout pulses and integration weights with assigned waveform memory slots are uploaded using generator.write_to_waveform_memory to the waveform memory after clear all waveforms which may saved in the waveform memory previously.

    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. All settings are configured using qachannels[n].configure_channel function. The function configure_sequencer_triggering and load_sequencer_program are used to configure the sequence trigger and upload the sequence program, respectively.

    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 224 ns after receiving a trigger (Internal Trigger). The measurement is repeated 10000 times. These parameters are configured by the function readout.configure_result_logger.

    The result after integration and averaging is 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).

  4. Run the measurement, download and plot the result

    Before starting the measurement, the QA Result Logger is enabled to be ready to get the result, and the Sequencer is enabled by enable_sequencer to be ready to run the sequence once receive an internal trigger. The measurement result is returned by readout.read function, and it is also displayed in QA Result Logger Tab see Figure 8.

    device.qachannels[CHANNEL_INDEX].readout.run() # enable QA Result Logger
    device.qachannels[CHANNEL_INDEX].generator.enable_sequencer(single=True)
    device.system.internaltrigger.enable(1)
    readout_results = device.qachannels[CHANNEL_INDEX].readout.read()
    

    Figure 8: Multiplexed readout of 8 qubits in loopback configuration.

    Use the following code snippet to plot the readout result as seen in Figure 9

    import matplotlib.pyplot as plt
    
    plt.figure()
    for i in range(NUM_QUBITS):
        plt.plot(readout_results[i].real, readout_results[i].imag, '.', label = f'Q{i}')
    plt.legend()
    plt.grid("both")
    plt.axis("equal")
    plt.xlabel("I (Vrms)")
    plt.ylabel("Q (Vrms)")
    plt.tight_layout()
    

    Figure 9: Multiplexed readout of 8 qubits in loopback configuration.