Skip to content

Continuous Resonator Spectroscopy


This tutorial is applicable to all SHFQA Instruments.

Goals and Requirements

The goal of this tutorial is to demonstrate how to use the SHFQA to perform continuous resonator spectroscopy measurement using

Zurich Instrument Toolkit API.


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, 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

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

Figure 1: SHFQA connection.


The tutorial starts with configuring the Sweeper, and is followed by sending out continuous wave and integrating the frequency down-converted signal, and is finished with power and phase plots calculated from integration results.

Users can use the Python code below to connect the instrument, perform continuous wave resonator spectroscopy, and each step is explained as the following.

  1. Connect the Instrument

    Create a toolkit session to the data server and connect the Instrument 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
    SERVER_HOST = 'localhost'
    session = Session(SERVER_HOST)              ## connect to data server
    device = session.connect_device(DEVICE_ID)  ## connect to device
  2. Create a Sweeper and configure it

    Python API SHFSweeper class is the core of the spectroscopy measurements. It defines all relevant parameters for frequency sweeping and sequencing. Toolkit wraps around the SHFSweeper and exposes an interface that is similar to the LabOne modules, meaning the parameters are exposed in a node tree like structure. The sweep parameters are configured such that the offset frequency of output signal is linearly swept over 1000 points from -1 GHz to 1 GHz around the center frequency of 5 GHz with the input and output power range of 0 dBm and the oscillator gain of 0.8, the input signal is integrated for 100 μs after receiving an internal triggered, and the measurement is repeated 200 times at each offset frequency.

    There are 2 sweeping modes, sequencer-based mode (default) and host-driven mode. The sequencer-based mode is recommended to achieve the highest sweep speed. In the sequencer-based mode, the frequency sweep is done by updating the frequency of the digital oscillator via the SeqC commands configFreqSweep and setSweepStep. This mode allows a fast resonator spectroscopy measurement with predicted cycle time of \(t_{\mathrm{settling\ time}} + t_{\mathrm{integration\ delay}} + t_{\mathrm{integration\ time}} + t_{\mathrm{wait\ after\ integration}}\), see . In the host-driven mode, the frequency sweep is done by updating the frequency of the digital oscillator via software, therefore measurement speed is limited by communication between instrument and host computer. Logarithmic or other non-linear frequency sweep is supported by the host-driven sweep mode only.

    To get a better signal-to-noise ratio (SNR), the measurement is repeated, and the result is averaged. There are 2 ways for averaging, sequential and cyclic. In the sequential mode, measurement is repeated after each frequency step. In the cyclic mode, measurement is repeated after sweeping through all frequencies.

    The output frequency of the signal is the sum of the center frequency and the offset frequency. The output power of the signal is determined by the output power range and the oscillator gain, see Inputs/Outputs Tab. The input range should be set properly to avoid input overflow and to reach the best SNR.

    sweeper = session.modules.shfqa_sweeper
    CHANNEL_INDEX = 0 # physical Channel 1
    sweeper.sweep.start_freq(-1000e6) # in units of Hz
    sweeper.sweep.stop_freq(1000e6) # in units of Hz
    sweeper.sweep.oscillator_gain(0.8) # amplitude scaling factor, 0 to 1
    sweeper.sweep.use_sequencer = True # True (recommended): sequencer-based sweep; False: host-driven sweep
    sweeper.average.integration_time(100e-6) # in units of second
    sweeper.average.mode("sequential") # "sequential" or "cyclic" averaging
    sweeper.rf.center_freq(5e9) # in units of Hz
    sweeper.rf.input_range(0) # in units of dBm
    sweeper.rf.output_range(0) # in units of dBm
    with device.set_transaction():

    Please note that default values of Sweeper parameters listed in depend on the zhinst version. Descriptions of other parameters can be found using the following code.


    Table: Default values of Sweeper parameters. {id=shfqa_tab_tutorial_sweeper_parameters_default_value}

    Parameter Description Default Value for zhinst < 22.08 Default Value for zhinst >= 23.02
    settling time Waiting time after having set the new frequency until issuing the setTrigger command, which triggers the spectroscopy unit. 200 ns 80 ns
    integration delay Delay after the internal trigger arrives at the spectroscopy unit until the integration of the input signal starts. 0 ns 224 ns
    (zhinst-utils version ≥ 0.1.5)
    envelope delay Delay After the internal trigger arrives at the spectroscopy unit until the playback of the envelope waveform starts. 0 ns 0 ns
    integration time Time to integrate the input data. 1 ms 1 ms
    wait after integration Wait time after the end of the integration until the start of the next cycle. 72 ns 0 ns
    predicted cycle time Calculated duration of each cycle of the spectroscopy loop. Note that this property only applies in self-triggered mode, which is active when the trigger source is set to None and use_sequencer is True. - "settling time" + "integration delay" + "integration time" + "wait after integration"
  3. Run the measurement and plot the data

    After executing, all above parameters are updated, and a SeqC program is automatically generated, uploaded and compiled based on the sweep parameters, see in Figure 2. In the program, ConfigFreqSweep sets the start frequency and the frequency increment in units of Hz for a chosen oscillator, and setSweepStep sets the oscillator frequency. The oscillator phase is reset by resetOscPhase before each measurement. The trigger generated in the sequencer is used to start the integration, and the playZero sets the cycle duration. The measurement is repeated using the nested for loop according to the averaging mode. The measurement starts after enabling the sequencer.

    The result returned from is complex data \(E_{\mathrm{sweeper}}\) in units of Vrms. It is averaged and normalized by the integration length. The power \(P\) and phase \(\phi\) can be calculated as,

    \[ \begin{equation}\tag{1} \begin{aligned} P & = 10\lg(\frac{|E_{\mathrm{sweeper}}|^2}{R}1000), \newline \phi & = \arctan\frac{\Im(E_{\mathrm{sweeper}})}{\Re(E_{\mathrm{sweeper}})}, \end{aligned} \end{equation} \]

    where \(R\) is 50 \(\Omega\), 1000 is the conversion factor from W to mW. With sweeper.plot(), the power and phase are calculated and plotted, see Figure 3.

    result =
    num_points_result = len(result["vector"])
    print(f"Measured at {num_points_result} frequency points.")

    Figure 2: Continuous spectroscopy measurement seqc program in the Readout Pulse Generator Tab.

    Figure 3: Continuous spectroscopy measurement results in loopback configuration.