See also

A Jupyter notebook version of this tutorial can be downloaded here.

Manual Mixer calibration#

The Cluster RF Modules (QCM-RF and QRM-RF) have integrated IQ mixers that handle both upconversion and downconversion of RF signals. These mixers use a local oscillator (LO) with a frequency of \(\omega_{LO}\). During upconversion, they combine signals from the I and Q paths, which have a frequency of \(\omega_{NCO}\), resulting in an output signal at \(\omega_{LO} + \omega_{NCO}\). However, due to the inherent mathematical imperfections of IQ mixers, the output also includes an unwanted signal at \(\omega_{LO}\) (known as leakage) and another at \(\omega_{LO} - \omega_{NCO}\) (called the undesired sideband). Cluster baseband modules (QCM and QRM) can be used with external mixers, which have similar imperfections.

In this tutorial, we are going to look at ways to suppress the LO leakage and undesired sideband. This process is called mixer calibration.

To run this tutorial optimally, you will need:

  • Spectrum analyzer

  • SMA-cables

  • Installation and enabling of ipywidgets:

pip install ipywidgets
jupyter nbextension enable --py widgetsnbextension

Setup#

First, we are going to import the required packages.

[1]:
import json

import ipywidgets as widgets
from ipywidgets import interact
[2]:
from __future__ import annotations

from typing import TYPE_CHECKING, Callable

from qcodes.instrument import find_or_create_instrument

from qblox_instruments import Cluster, ClusterType

if TYPE_CHECKING:
    from qblox_instruments.qcodes_drivers.module import Module

Scan For Clusters#

We scan for the available devices connected via ethernet using the Plug & Play functionality of the Qblox Instruments package (see Plug & Play for more info).

!qblox-pnp list

[3]:
cluster_ip = "10.10.200.42"
cluster_name = "cluster0"

Connect to Cluster#

We now make a connection with the Cluster.

[4]:
cluster = find_or_create_instrument(
    Cluster,
    recreate=True,
    name=cluster_name,
    identifier=cluster_ip,
    dummy_cfg=(
        {
            2: ClusterType.CLUSTER_QCM,
            4: ClusterType.CLUSTER_QRM,
            6: ClusterType.CLUSTER_QCM_RF,
            8: ClusterType.CLUSTER_QRM_RF,
        }
        if cluster_ip is None
        else None
    ),
)

Get connected modules#

[5]:
def get_connected_modules(cluster: Cluster, filter_fn: Callable | None = None) -> dict[int, Module]:
    def checked_filter_fn(mod: ClusterType) -> bool:
        if filter_fn is not None:
            return filter_fn(mod)
        return True

    return {
        mod.slot_idx: mod for mod in cluster.modules if mod.present() and checked_filter_fn(mod)
    }
[6]:
# QCM-RF modules
modules = get_connected_modules(cluster, lambda mod: not mod.is_qrm_type and mod.is_rf_type)
[7]:
# This uses the module of the correct type with the lowest slot index
module = list(modules.values())[0]

Reset the Cluster#

We reset the Cluster to enter a well-defined state. Note that resetting will clear all stored parameters, so resetting between experiments is usually not desirable.

[8]:
cluster.reset()
print(cluster.get_system_status())
Status: OKAY, Flags: NONE, Slot flags: NONE

We upload a simple sequence program that keeps playing the DC waveform at 30 percent IF power (waveform amplitude = 0.3). This will be modulated and upconverted within the QRM-RF before outputting.

[9]:
# Sequence program.
seq_prog = """
      wait_sync 4

loop: play    0,0,1200
      jmp     @loop
"""
waveforms = {"dc": {"data": [0.3 for i in range(0, 1200)], "index": 0}}

# Add sequence to single dictionary and write to JSON file.
sequence = {
    "waveforms": waveforms,
    "weights": {},
    "acquisitions": {},
    "program": seq_prog,
}
with open("sequence.json", "w", encoding="utf-8") as file:
    json.dump(sequence, file, indent=4)
    file.close()

module.sequencer0.sequence("sequence.json")

Let’s configure the sequencer to generate an IF frequency of \(100\) MHz. To get an output frequency of \(5.0\) GHz, we then have to configure the LO to run at \(4.9\) GHz.

[10]:
lo_freq = 4.9e9
module.out0_lo_freq(lo_freq)
[11]:
nco_freq = 100e6
module.sequencer0.marker_ovr_en(True)
module.sequencer0.marker_ovr_value(3)  # Enables output on QRM-RF

# Configure the sequencer
module.sequencer0.mod_en_awg(True)
module.sequencer0.nco_freq(nco_freq)
module.sequencer0.sync_en(True)

module.arm_sequencer(0)
module.start_sequencer(0)

print(module.get_sequencer_status(0))
Status: OKAY, State: RUNNING, Info Flags: NONE, Warning Flags: NONE, Error Flags: NONE, Log: []

Connect the output of the QRM-RF (O1) to the spectrum analyzer. This is what the output looks like on the spectrum analyzer (center frequency at 4.85 GHz with 600 MHz bandwidth). We see three peaks which correspond to (from the right) 5 GHz (desired signal), 4.9 GHz (LO Leakage) and 4.8 GHz (unwanted sideband).

IQ_Mixer_Calib_before.png

To get better spurious free dynamic range (SFDR) and better suppression, we can manually calibrate the mixer by:

  • Using DC offsets we can lower the LO leakage.

  • By changing the gain ratio and phase of the IF signal we can cancel the unwanted sideband.

Create control sliders for thes parameters. Each time the value of a parameter is updated, the sequencer is automatically stopped from the embedded firmware for safety reasons and has to be manually restarted. The sliders cover the valid parameter range. If the code below is modified to input invalid values, the Cluster QRM-RF firmware will not program the values.

Execute the code below, move the sliders and observe the result on the spectrum analyzer.

[12]:
def set_offset0(offset0: float) -> None:
    module.out0_offset_path0(offset0)
[13]:
def set_offset1(offset1: float) -> None:
    module.out0_offset_path1(offset1)
[14]:
def set_gain_ratio(gain_ratio: float) -> None:
    module.sequencer0.mixer_corr_gain_ratio(gain_ratio)
    # Start
    module.arm_sequencer(0)
    module.start_sequencer(0)


def set_phase_offset(phase_offset: float) -> None:
    module.sequencer0.mixer_corr_phase_offset_degree(phase_offset)
    # Start
    module.arm_sequencer(0)
    module.start_sequencer(0)


interact(
    set_offset0,
    offset0=widgets.FloatSlider(
        min=-14.0,
        max=14.0,
        step=0.001,
        start=0.0,
        layout=widgets.Layout(width="1200px"),
    ),
)
interact(
    set_offset1,
    offset1=widgets.FloatSlider(
        min=-14.0,
        max=14.0,
        step=0.001,
        start=0.0,
        layout=widgets.Layout(width="1200px"),
    ),
)
interact(
    set_gain_ratio,
    gain_ratio=widgets.FloatSlider(
        min=0.9, max=1.1, step=0.001, start=1.0, layout=widgets.Layout(width="1200px")
    ),
)
interact(
    set_phase_offset,
    phase_offset=widgets.FloatSlider(
        min=-45.0,
        max=45.0,
        step=0.001,
        start=0.0,
        layout=widgets.Layout(width="1200px"),
    ),
)
[14]:
<function __main__.set_phase_offset(phase_offset: 'float') -> 'None'>

IQ_Mixer_Calib_after.png

Stop#

Finally, let’s stop the sequencers if they haven’t already and close the instrument connection.

[15]:
# Stop sequencer.
module.stop_sequencer()

# Print status of sequencer.
print(module.get_sequencer_status(0))
Status: OKAY, State: STOPPED, Info Flags: FORCED_STOP, Warning Flags: NONE, Error Flags: NONE, Log: []

Stop#

Finally, let’s stop the sequencers if they haven’t already and close the instrument connection. One can also display a detailed snapshot containing the instrument parameters before closing the connection by uncommenting the corresponding lines.

[16]:
# Stop both sequencers.
module.stop_sequencer()

# Print status of both sequencers (should now say it is stopped).
print(module.get_sequencer_status(0))
print(module.get_sequencer_status(1))
print()

# Print an overview of the instrument parameters.
print("Snapshot:")
module.print_readable_snapshot(update=True)

# Reset the cluster
cluster.reset()
print(cluster.get_system_status())
Status: OKAY, State: STOPPED, Info Flags: FORCED_STOP, Warning Flags: NONE, Error Flags: NONE, Log: []
Status: OKAY, State: STOPPED, Info Flags: NONE, Warning Flags: NONE, Error Flags: NONE, Log: []

Snapshot:
cluster0_module6:
        parameter                    value
--------------------------------------------------------------------------------
marker0_exp0_config           : bypassed
marker0_exp1_config           : bypassed
marker0_exp2_config           : bypassed
marker0_exp3_config           : bypassed
marker0_fir_config            : bypassed
marker0_inv_en                : False
marker1_exp0_config           : bypassed
marker1_exp1_config           : bypassed
marker1_exp2_config           : bypassed
marker1_exp3_config           : bypassed
marker1_fir_config            : bypassed
marker1_inv_en                : False
marker2_exp0_config           : bypassed
marker2_exp1_config           : bypassed
marker2_exp2_config           : bypassed
marker2_exp3_config           : bypassed
marker2_fir_config            : bypassed
marker3_exp0_config           : bypassed
marker3_exp1_config           : bypassed
marker3_exp2_config           : bypassed
marker3_exp3_config           : bypassed
marker3_fir_config            : bypassed
out0_att                      : 0 (dB)
out0_exp0_config              : bypassed
out0_exp1_config              : bypassed
out0_exp2_config              : bypassed
out0_exp3_config              : bypassed
out0_fir_config               : bypassed
out0_latency                  : 0 (s)
out0_lo_en                    : True
out0_lo_freq                  : 4900000000 (Hz)
out0_lo_freq_cal_type_default : off (Hz)
out0_offset_path0             : 0 (mV)
out0_offset_path1             : 0 (mV)
out1_att                      : 0 (dB)
out1_exp0_config              : bypassed
out1_exp1_config              : bypassed
out1_exp2_config              : bypassed
out1_exp3_config              : bypassed
out1_fir_config               : bypassed
out1_latency                  : 0 (s)
out1_lo_en                    : True
out1_lo_freq                  : 6000000000 (Hz)
out1_lo_freq_cal_type_default : off (Hz)
out1_offset_path0             : 7.625 (mV)
out1_offset_path1             : 7.625 (mV)
present                       : True
cluster0_module6_sequencer0:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      True
marker_ovr_value                 :      3
mixer_corr_gain_ratio            :      0.89999
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      True
nco_freq                         :      1e+08 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      True
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
cluster0_module6_sequencer1:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      False
marker_ovr_value                 :      0
mixer_corr_gain_ratio            :      1
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      False
nco_freq                         :      0 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      False
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
cluster0_module6_sequencer2:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      False
marker_ovr_value                 :      0
mixer_corr_gain_ratio            :      1
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      False
nco_freq                         :      0 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      False
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
cluster0_module6_sequencer3:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      False
marker_ovr_value                 :      0
mixer_corr_gain_ratio            :      1
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      False
nco_freq                         :      0 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      False
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
cluster0_module6_sequencer4:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      False
marker_ovr_value                 :      0
mixer_corr_gain_ratio            :      1
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      False
nco_freq                         :      0 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      False
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
cluster0_module6_sequencer5:
        parameter                       value
--------------------------------------------------------------------------------
connect_out0                     :      IQ
connect_out1                     :      IQ
cont_mode_en_awg_path0           :      False
cont_mode_en_awg_path1           :      False
cont_mode_waveform_idx_awg_path0 :      0
cont_mode_waveform_idx_awg_path1 :      0
gain_awg_path0                   :      1
gain_awg_path1                   :      1
marker_ovr_en                    :      False
marker_ovr_value                 :      0
mixer_corr_gain_ratio            :      1
mixer_corr_phase_offset_degree   :      -0
mod_en_awg                       :      False
nco_freq                         :      0 (Hz)
nco_freq_cal_type_default        :      off (Hz)
nco_phase_offs                   :      0 (Degrees)
nco_prop_delay_comp              :      0 (ns)
nco_prop_delay_comp_en           :      False (ns)
offset_awg_path0                 :      0
offset_awg_path1                 :      0
sync_en                          :      False
trigger10_count_threshold        :      1
trigger10_threshold_invert       :      False
trigger11_count_threshold        :      1
trigger11_threshold_invert       :      False
trigger12_count_threshold        :      1
trigger12_threshold_invert       :      False
trigger13_count_threshold        :      1
trigger13_threshold_invert       :      False
trigger14_count_threshold        :      1
trigger14_threshold_invert       :      False
trigger15_count_threshold        :      1
trigger15_threshold_invert       :      False
trigger1_count_threshold         :      1
trigger1_threshold_invert        :      False
trigger2_count_threshold         :      1
trigger2_threshold_invert        :      False
trigger3_count_threshold         :      1
trigger3_threshold_invert        :      False
trigger4_count_threshold         :      1
trigger4_threshold_invert        :      False
trigger5_count_threshold         :      1
trigger5_threshold_invert        :      False
trigger6_count_threshold         :      1
trigger6_threshold_invert        :      False
trigger7_count_threshold         :      1
trigger7_threshold_invert        :      False
trigger8_count_threshold         :      1
trigger8_threshold_invert        :      False
trigger9_count_threshold         :      1
trigger9_threshold_invert        :      False
upsample_rate_awg_path0          :      0
upsample_rate_awg_path1          :      0
Status: OKAY, Flags: NONE, Slot flags: NONE