HardwareCompilationConfig migration guide#

The HardwareCompilationConfig replaces the old-style unvalidated JSON/dict hardware configuration, and restructures the contents into "hardware_description", "hardware_options" and "connectivity" (these fields are described in detail in Hardware compilation configuration). Using this new-style class has the advantage that all mutable and backend agnostic parameters for compiling between quantum-device and control-hardware layers are grouped in "hardware_options", separated from static and backend specific parameters for compiling between control-hardware and hardware-instructions layers, which are grouped in "hardware_options" and "connectivity". In addition, the new-style configuration is validated automatically.

Here, we describe how to migrate from the old-style configuration to the new one for the current hardware backends, which each define their own HardwareCompilationConfig datastructure with backend-specific fields (e.g., QbloxHardwareCompilationConfig and ZIHardwareCompilationConfig).

Custom backends

If you have implemented a custom backend, or have added custom instruments and/or options to the Qblox or Zurich Instruments backends, you will need to define your own HardwareCompilationConfig datastructure, as is already done for the Qblox and Zurich Instruments backends.

Qblox#

The QbloxHardwareCompilationConfig inherits from the HardwareCompilationConfig and contains the following backend-specific fields:

  1. The QbloxHardwareDescription, which specifies the instruments that are used in the setup, along with their instrument-specific settings. For the Qblox Cluster, we refer to the Hardware description for clusters section for the allowed instrument types and settings.

  2. The QbloxHardwareOptions, which adds some backend-specific options to the generic HardwareOptions (see Hardware options for more details).

  3. The compilation_passes field, which specifies the compilation passes that are used to compile the schedule. In the example below, we do not specify the compilation passes, which means that the default passes are used.

To show how to migrate, we first load an example old-style hardware configuration for the Qblox backend:

import rich
from quantify_scheduler.backends.qblox.hardware_config_transmon_old_style import hardware_config as hardware_config_transmon_old_style

rich.print(hardware_config_transmon_old_style)
Hide code cell output
{
    'backend': 'quantify_scheduler.backends.qblox_backend.hardware_compile',
    'latency_corrections': {'q4:mw-q4.01': 8e-09, 'q5:mw-q5.01': 4e-09},
    'distortion_corrections': {
        'q0:fl-cl0.baseband': {
            'filter_func': 'scipy.signal.lfilter',
            'input_var_name': 'x',
            'kwargs': {'b': [0, 0.25, 0.5], 'a': [1]},
            'clipping_values': [-2.5, 2.5],
            'sampling_rate': 1000000000.0
        }
    },
    'cluster0': {
        'ref': 'internal',
        'instrument_type': 'Cluster',
        'sequence_to_file': False,
        'cluster0_module1': {
            'instrument_type': 'QCM',
            'sequence_to_file': False,
            'complex_output_0': {
                'lo_name': 'lo0',
                'auto_lo_cal': <LoCalEnum.OFF: 'off'>,
                'dc_mixer_offset_I': None,
                'dc_mixer_offset_Q': None,
                'downconverter_freq': None,
                'marker_debug_mode_enable': True,
                'distortion_correction_latency_compensation': <DistortionCorrectionLatencyEnum.NO_DELAY_COMP: 0>,
                'mix_lo': True,
                'portclock_configs': [
                    {
                        'port': 'q4:mw',
                        'clock': 'q4.01',
                        'interm_freq': 200000000.0,
                        'auto_sideband_cal': <SidebandCalEnum.OFF: 'off'>,
                        'mixer_amp_ratio': 0.9999,
                        'mixer_phase_error_deg': -4.2
                    }
                ]
            }
        },
        'cluster0_module2': {
            'instrument_type': 'QCM_RF',
            'sequence_to_file': False,
            'complex_output_0': {
                'lo_freq': None,
                'output_att': 4,
                'portclock_configs': [
                    {'port': 'q0:mw', 'clock': 'q0.01', 'interm_freq': 50000000.0},
                    {'port': 'q5:mw', 'clock': 'q5.01', 'interm_freq': 50000000.0}
                ]
            },
            'complex_output_1': {
                'lo_freq': 5000000000.0,
                'output_att': 6,
                'portclock_configs': [{'port': 'q6:mw', 'clock': 'q6.01', 'interm_freq': None}]
            },
            'digital_output_0': {'portclock_configs': [{'port': 'q0:switch', 'clock': 'digital'}]}
        },
        'cluster0_module3': {
            'instrument_type': 'QRM',
            'sequence_to_file': False,
            'complex_output_0': {
                'lo_name': 'lo1',
                'auto_lo_cal': <LoCalEnum.OFF: 'off'>,
                'dc_mixer_offset_I': -0.054,
                'dc_mixer_offset_Q': -0.034,
                'input_gain_I': 2,
                'input_gain_Q': 3,
                'portclock_configs': [
                    {
                        'auto_sideband_cal': <SidebandCalEnum.OFF: 'off'>,
                        'mixer_amp_ratio': 0.9997,
                        'mixer_phase_error_deg': -4.0,
                        'port': 'q4:res',
                        'clock': 'q4.ro',
                        'interm_freq': None
                    }
                ]
            },
            'complex_input_0': {
                'portclock_configs': [
                    {
                        'port': 'qe0:optical_readout',
                        'clock': 'qe0.ge0',
                        'ttl_acq_threshold': 0.5,
                        'init_gain_awg_path_I': 1.0,
                        'init_gain_awg_path_Q': 1.0,
                        'init_offset_awg_path_I': 0.0,
                        'init_offset_awg_path_Q': 0.0,
                        'qasm_hook_func': None
                    }
                ]
            }
        },
        'cluster0_module4': {
            'instrument_type': 'QRM_RF',
            'sequence_to_file': False,
            'complex_input_0': {
                'lo_freq': None,
                'input_att': 10,
                'portclock_configs': [{'port': 'q5:res', 'clock': 'q5.ro', 'interm_freq': 50000000.0}]
            },
            'complex_output_0': {
                'lo_freq': 7800000000.0,
                'output_att': 12,
                'input_att': 4,
                'portclock_configs': [{'port': 'q0:res', 'clock': 'q0.ro', 'interm_freq': None}]
            }
        },
        'cluster0_module7': {
            'instrument_type': 'QCM',
            'sequence_to_file': False,
            'real_output_0': {
                'lo_name': 'lo_real',
                'portclock_configs': [{'port': 'q7:mw', 'clock': 'q7.01', 'interm_freq': None}]
            }
        },
        'cluster0_module10': {
            'instrument_type': 'QCM',
            'sequence_to_file': False,
            'real_output_0': {'portclock_configs': [{'port': 'q0:fl', 'clock': 'cl0.baseband'}]},
            'real_output_1': {'portclock_configs': [{'port': 'q1:fl', 'clock': 'cl0.baseband'}]},
            'real_output_2': {'portclock_configs': [{'port': 'q2:fl', 'clock': 'cl0.baseband'}]},
            'real_output_3': {'portclock_configs': [{'port': 'q3:fl', 'clock': 'cl0.baseband'}]}
        },
        'cluster0_module12': {
            'instrument_type': 'QCM',
            'sequence_to_file': False,
            'real_output_0': {'portclock_configs': [{'port': 'q4:fl', 'clock': 'cl0.baseband'}]}
        }
    },
    'lo0': {'instrument_type': 'LocalOscillator', 'frequency': None, 'power': 1},
    'lo1': {'instrument_type': 'LocalOscillator', 'frequency': 7200000000.0, 'power': 1},
    'lo_real': {'instrument_type': 'LocalOscillator', 'frequency': 5000000000.0, 'power': 1}
}

This config can be migrated to the new QbloxHardwareCompilationConfig datastructure using the built-in validation method .model_validate, which will recognize the old-style config and convert it to the new-style config:

from quantify_scheduler.backends.qblox_backend import QbloxHardwareCompilationConfig

hardware_config_transmon_new_style = QbloxHardwareCompilationConfig.model_validate(
    hardware_config_transmon_old_style
)
rich.print(hardware_config_transmon_new_style)
Hide code cell output
/usr/local/lib/python3.9/site-packages/quantify_scheduler/backends/qblox/helpers.py:1932: FutureWarning: The hardware configuration dictionary is deprecated and will not be supported in quantify-scheduler >= 1.0.0. Please use a `HardwareCompilationConfig` instead. For more information on how to migrate from old- to new-style hardware specification, please visit https://quantify-os.org/docs/quantify-scheduler/dev/examples/hardware_config_migration.html in the documentation.
  warnings.warn(
QbloxHardwareCompilationConfig(
    config_type=<class 'quantify_scheduler.backends.qblox_backend.QbloxHardwareCompilationConfig'>,
    hardware_description={
        'cluster0': ClusterDescription(
            instrument_type='Cluster',
            ref='internal',
            sequence_to_file=False,
            modules={
                1: QCMDescription(
                    instrument_type='QCM',
                    sequence_to_file=False,
                    complex_output_0=ComplexChannelDescription(
                        marker_debug_mode_enable=True,
                        mix_lo=True,
                        downconverter_freq=None,
                        distortion_correction_latency_compensation=<DistortionCorrectionLatencyEnum.NO_DELAY_COMP: 
0>
                    ),
                    complex_output_1=None,
                    real_output_0=None,
                    real_output_1=None,
                    real_output_2=None,
                    real_output_3=None,
                    digital_output_0=None,
                    digital_output_1=None,
                    digital_output_2=None,
                    digital_output_3=None
                ),
                2: QCMRFDescription(
                    instrument_type='QCM_RF',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_output_1=None,
                    digital_output_0=None,
                    digital_output_1=None
                ),
                3: QRMDescription(
                    instrument_type='QRM',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_input_0=None,
                    real_output_0=None,
                    real_output_1=None,
                    real_input_0=None,
                    real_input_1=None,
                    digital_output_0=None,
                    digital_output_1=None,
                    digital_output_2=None,
                    digital_output_3=None
                ),
                4: QRMRFDescription(
                    instrument_type='QRM_RF',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_input_0=None,
                    digital_output_0=None,
                    digital_output_1=None
                ),
                7: QCMDescription(
                    instrument_type='QCM',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_output_1=None,
                    real_output_0=None,
                    real_output_1=None,
                    real_output_2=None,
                    real_output_3=None,
                    digital_output_0=None,
                    digital_output_1=None,
                    digital_output_2=None,
                    digital_output_3=None
                ),
                10: QCMDescription(
                    instrument_type='QCM',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_output_1=None,
                    real_output_0=None,
                    real_output_1=None,
                    real_output_2=None,
                    real_output_3=None,
                    digital_output_0=None,
                    digital_output_1=None,
                    digital_output_2=None,
                    digital_output_3=None
                ),
                12: QCMDescription(
                    instrument_type='QCM',
                    sequence_to_file=False,
                    complex_output_0=None,
                    complex_output_1=None,
                    real_output_0=None,
                    real_output_1=None,
                    real_output_2=None,
                    real_output_3=None,
                    digital_output_0=None,
                    digital_output_1=None,
                    digital_output_2=None,
                    digital_output_3=None
                )
            }
        ),
        'iq_mixer_lo0': IQMixerDescription(instrument_type='IQMixer'),
        'iq_mixer_lo1': IQMixerDescription(instrument_type='IQMixer'),
        'iq_mixer_lo_real': IQMixerDescription(instrument_type='IQMixer'),
        'lo0': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name=None,
            generic_icc_name=None,
            frequency_param='frequency',
            power_param='power',
            power=1
        ),
        'lo1': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name=None,
            generic_icc_name=None,
            frequency_param='frequency',
            power_param='power',
            power=1
        ),
        'lo_real': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name=None,
            generic_icc_name=None,
            frequency_param='frequency',
            power_param='power',
            power=1
        )
    },
    hardware_options=QbloxHardwareOptions(
        latency_corrections={'q4:mw-q4.01': 8e-09, 'q5:mw-q5.01': 4e-09},
        distortion_corrections={
            'q0:fl-cl0.baseband': SoftwareDistortionCorrection(
                filter_func='scipy.signal.lfilter',
                input_var_name='x',
                kwargs={'b': [0, 0.25, 0.5], 'a': [1]},
                clipping_values=[-2.5, 2.5],
                sampling_rate=1000000000.0
            )
        },
        modulation_frequencies={
            'q4:mw-q4.01': ModulationFrequencies(interm_freq=200000000.0, lo_freq=None),
            'q0:mw-q0.01': ModulationFrequencies(interm_freq=50000000.0, lo_freq=None),
            'q5:mw-q5.01': ModulationFrequencies(interm_freq=50000000.0, lo_freq=None),
            'q6:mw-q6.01': ModulationFrequencies(interm_freq=None, lo_freq=5000000000.0),
            'q4:res-q4.ro': ModulationFrequencies(interm_freq=None, lo_freq=7200000000.0),
            'q5:res-q5.ro': ModulationFrequencies(interm_freq=50000000.0, lo_freq=None),
            'q0:res-q0.ro': ModulationFrequencies(interm_freq=None, lo_freq=7800000000.0),
            'q7:mw-q7.01': ModulationFrequencies(interm_freq=None, lo_freq=5000000000.0)
        },
        mixer_corrections={
            'q4:mw-q4.01': QbloxMixerCorrections(
                dc_offset_i=None,
                dc_offset_q=None,
                amp_ratio=0.9999,
                phase_error=-4.2,
                auto_lo_cal=<LoCalEnum.OFF: 'off'>,
                auto_sideband_cal=<SidebandCalEnum.OFF: 'off'>
            ),
            'q4:res-q4.ro': QbloxMixerCorrections(
                dc_offset_i=-0.054,
                dc_offset_q=-0.034,
                amp_ratio=0.9997,
                phase_error=-4.0,
                auto_lo_cal=<LoCalEnum.OFF: 'off'>,
                auto_sideband_cal=<SidebandCalEnum.OFF: 'off'>
            )
        },
        input_gain={'q4:res-q4.ro': ComplexInputGain(gain_I=2, gain_Q=3)},
        output_att={'q0:mw-q0.01': 4, 'q5:mw-q5.01': 4, 'q6:mw-q6.01': 6, 'q0:res-q0.ro': 12},
        input_att={'q5:res-q5.ro': 10, 'q0:res-q0.ro': 4},
        sequencer_options={
            'qe0:optical_readout-qe0.ge0': SequencerOptions(
                init_offset_awg_path_I=0.0,
                init_offset_awg_path_Q=0.0,
                init_gain_awg_path_I=1.0,
                init_gain_awg_path_Q=1.0,
                ttl_acq_threshold=0.5,
                qasm_hook_func=None
            )
        },
        digitization_thresholds=None
    ),
    connectivity=Connectivity(graph=<quantify_scheduler.structure.types.Graph object at 0x7ccb783849a0>),
    compilation_passes=[
        SimpleNodeConfig(
            name='compile_long_square_pulses_to_awg_offsets',
            compilation_func=<function compile_long_square_pulses_to_awg_offsets at 0x7ccb578d5550>
        ),
        SimpleNodeConfig(
            name='qblox_compile_conditional_playback',
            compilation_func=<function compile_conditional_playback at 0x7ccb578d54c0>
        ),
        SimpleNodeConfig(
            name='qblox_hardware_compile',
            compilation_func=<function hardware_compile at 0x7ccb578d55e0>
        )
    ]
)

This new-style config can then be passed to the QuantumDevice in order to compile a schedule for the Qblox backend, as is shown in the Compilation section of the Tutorial: Compiling to Hardware.

The config can also be JSON serialized and deserialized using the built-in methods .model_dump_json and .model_validate_json, respectively, to make storing, visualization and modification easier.

serialized_config = hardware_config_transmon_new_style.model_dump_json(exclude_unset=True)

deserialized_config = QbloxHardwareCompilationConfig.model_validate_json(serialized_config)

Here we passed exclude_unset=True to .model_dump_json to prevent unnecessary clutter in the json (e.g. None and default settings).

Zurich Instruments#

The ZIHardwareCompilationConfig inherits from the HardwareCompilationConfig and contains the following backend-specific fields:

  1. The QbloxHardwareDescription, which specifies the instruments that are used in the setup, along with their instrument-specific settings. We refer to the Zurich Instruments Hardware Description section for the allowed instrument types and settings.

  2. The ZIHardwareOptions, which adds backend-specific options to the generic HardwareOptions, see Hardware Options for more details.

  3. The compilation_passes field, which specifies the compilation passes that are used to compile the schedule. In the example below, we do not specify the compilation passes, which means that the default passes are used.

To show how to migrate, we first load an example old-style hardware configuration for the Zurich Instruments backend:

import rich
from quantify_scheduler.backends.zhinst.zhinst_hardware_config_old_style import hardware_config as zhinst_hardware_config_old_style

rich.print(zhinst_hardware_config_old_style)
Hide code cell output
{
    'backend': 'quantify_scheduler.backends.zhinst_backend.compile_backend',
    'latency_corrections': {
        'q0:mw-q0.01': 9.5e-08,
        'q1:mw-q1.01': 9.5e-08,
        'q0:res-q0.ro': -9.5e-08,
        'q1:res-q1.ro': -9.5e-08
    },
    'distortion_corrections': {
        'q0:fl-cl0.baseband': {
            'filter_func': 'scipy.signal.lfilter',
            'input_var_name': 'x',
            'kwargs': {'b': [0, 0.25, 0.5], 'a': [1]},
            'clipping_values': [-2.5, 2.5],
            'sampling_rate': 1000000000.0
        }
    },
    'local_oscillators': [
        {
            'unique_name': 'lo0_ch1',
            'instrument_name': 'lo0',
            'frequency': {'ch1.frequency': None},
            'frequency_param': 'ch1.frequency',
            'power': {'power': 13}
        },
        {
            'unique_name': 'lo0_ch2',
            'instrument_name': 'lo0',
            'frequency': {'ch2.frequency': None},
            'frequency_param': 'ch2.frequency',
            'power': {'ch2.power': 10}
        },
        {
            'unique_name': 'lo1',
            'instrument_name': 'lo1',
            'frequency': {'frequency': None},
            'frequency_param': 'frequency',
            'power': {'power': 16}
        }
    ],
    'devices': [
        {
            'name': 'ic_hdawg0',
            'type': 'HDAWG8',
            'clock_select': 0,
            'ref': 'int',
            'channelgrouping': 0,
            'channel_0': {
                'port': 'q0:mw',
                'clock': 'q0.01',
                'mode': 'complex',
                'modulation': {'type': 'premod', 'interm_freq': -100000000.0},
                'local_oscillator': 'lo0_ch1',
                'markers': ['AWG_MARKER1', 'AWG_MARKER2'],
                'gain1': 1.0,
                'gain2': 1.0,
                'mixer_corrections': {
                    'amp_ratio': 0.95,
                    'phase_error': 0.07,
                    'dc_offset_i': -0.0542,
                    'dc_offset_q': -0.0328
                },
                'trigger': None
            },
            'channel_1': {
                'port': 'q1:mw',
                'clock': 'q1.01',
                'mode': 'complex',
                'modulation': {'type': 'premod', 'interm_freq': -100000000.0},
                'local_oscillator': 'lo0_ch2',
                'markers': ['AWG_MARKER1', 'AWG_MARKER2'],
                'gain1': 1.0,
                'gain2': 1.0,
                'mixer_corrections': {
                    'amp_ratio': 0.95,
                    'phase_error': 0.07,
                    'dc_offset_i': 0.042,
                    'dc_offset_q': 0.028
                },
                'trigger': None
            },
            'channel_2': {
                'port': 'q2:mw',
                'clock': 'q2.01',
                'mode': 'complex',
                'modulation': {'type': 'premod', 'interm_freq': -100000000.0},
                'local_oscillator': 'lo0_ch2',
                'markers': ['AWG_MARKER1', 'AWG_MARKER2'],
                'gain1': 1.0,
                'gain2': 1.0,
                'mixer_corrections': {
                    'amp_ratio': 0.95,
                    'phase_error': 0.07,
                    'dc_offset_i': 0.042,
                    'dc_offset_q': 0.028
                },
                'trigger': None
            },
            'channel_3': {
                'port': 'q3:mw',
                'clock': 'q3.01',
                'mode': 'complex',
                'modulation': {'type': 'premod', 'interm_freq': -100000000.0},
                'local_oscillator': 'lo0_ch2',
                'markers': ['AWG_MARKER1', 'AWG_MARKER2'],
                'gain1': 1.0,
                'gain2': 1.0,
                'mixer_corrections': {
                    'amp_ratio': 0.95,
                    'phase_error': 0.07,
                    'dc_offset_i': 0.042,
                    'dc_offset_q': 0.028
                },
                'trigger': None
            }
        },
        {
            'name': 'ic_uhfqa0',
            'type': 'UHFQA',
            'ref': 'ext',
            'channel_0': {
                'port': 'q0:res',
                'clock': 'q0.ro',
                'mode': 'real',
                'modulation': {'type': 'premod', 'interm_freq': 200000000.0},
                'local_oscillator': 'lo1',
                'trigger': 2,
                'markers': []
            }
        }
    ]
}

This config can be migrated to the new ZIHardwareCompilationConfig datastructure using the built-in validation, which will recognize the old-style config and convert it to the new-style config:

from quantify_scheduler.backends.zhinst_backend import ZIHardwareCompilationConfig

zhinst_hardware_config_new_style = ZIHardwareCompilationConfig.model_validate(
    zhinst_hardware_config_old_style
)
rich.print(zhinst_hardware_config_new_style)
Hide code cell output
ZIHardwareCompilationConfig(
    config_type=<class 'quantify_scheduler.backends.zhinst_backend.ZIHardwareCompilationConfig'>,
    hardware_description={
        'lo0_ch1': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name='lo0',
            generic_icc_name=None,
            frequency_param='ch1.frequency',
            power_param='power',
            power=13
        ),
        'lo0_ch2': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name='lo0',
            generic_icc_name=None,
            frequency_param='ch2.frequency',
            power_param='ch2.power',
            power=10
        ),
        'lo1': LocalOscillatorDescription(
            instrument_type='LocalOscillator',
            instrument_name='lo1',
            generic_icc_name=None,
            frequency_param='frequency',
            power_param='power',
            power=16
        ),
        'ic_hdawg0': ZIHDAWG8Description(
            instrument_type='HDAWG8',
            ref='int',
            channelgrouping=0,
            clock_select=0,
            channel_0=ZIChannelDescription(mode='complex', markers=['AWG_MARKER1', 'AWG_MARKER2'], trigger=None),
            channel_1=ZIChannelDescription(mode='complex', markers=['AWG_MARKER1', 'AWG_MARKER2'], trigger=None),
            channel_2=ZIChannelDescription(mode='complex', markers=['AWG_MARKER1', 'AWG_MARKER2'], trigger=None),
            channel_3=ZIChannelDescription(mode='complex', markers=['AWG_MARKER1', 'AWG_MARKER2'], trigger=None)
        ),
        'iqm_ic_hdawg0_ch0': IQMixerDescription(instrument_type='IQMixer'),
        'iqm_ic_hdawg0_ch1': IQMixerDescription(instrument_type='IQMixer'),
        'iqm_ic_hdawg0_ch2': IQMixerDescription(instrument_type='IQMixer'),
        'iqm_ic_hdawg0_ch3': IQMixerDescription(instrument_type='IQMixer'),
        'ic_uhfqa0': ZIUHFQADescription(
            instrument_type='UHFQA',
            ref='ext',
            channel_0=ZIChannelDescription(mode='real', markers=[], trigger=2)
        ),
        'iqm_ic_uhfqa0_ch0': IQMixerDescription(instrument_type='IQMixer')
    },
    hardware_options=ZIHardwareOptions(
        latency_corrections={
            'q0:mw-q0.01': 9.5e-08,
            'q1:mw-q1.01': 9.5e-08,
            'q0:res-q0.ro': -9.5e-08,
            'q1:res-q1.ro': -9.5e-08
        },
        distortion_corrections={
            'q0:fl-cl0.baseband': SoftwareDistortionCorrection(
                filter_func='scipy.signal.lfilter',
                input_var_name='x',
                kwargs={'b': [0, 0.25, 0.5], 'a': [1]},
                clipping_values=[-2.5, 2.5],
                sampling_rate=1000000000.0
            )
        },
        modulation_frequencies={
            'q0:mw-q0.01': ModulationFrequencies(interm_freq=-100000000.0, lo_freq=None),
            'q1:mw-q1.01': ModulationFrequencies(interm_freq=-100000000.0, lo_freq=None),
            'q2:mw-q2.01': ModulationFrequencies(interm_freq=-100000000.0, lo_freq=None),
            'q3:mw-q3.01': ModulationFrequencies(interm_freq=-100000000.0, lo_freq=None),
            'q0:res-q0.ro': ModulationFrequencies(interm_freq=200000000.0, lo_freq=None)
        },
        mixer_corrections={
            'q0:mw-q0.01': MixerCorrections(
                dc_offset_i=-0.0542,
                dc_offset_q=-0.0328,
                amp_ratio=0.95,
                phase_error=0.07
            ),
            'q1:mw-q1.01': MixerCorrections(
                dc_offset_i=0.042,
                dc_offset_q=0.028,
                amp_ratio=0.95,
                phase_error=0.07
            ),
            'q2:mw-q2.01': MixerCorrections(
                dc_offset_i=0.042,
                dc_offset_q=0.028,
                amp_ratio=0.95,
                phase_error=0.07
            ),
            'q3:mw-q3.01': MixerCorrections(
                dc_offset_i=0.042,
                dc_offset_q=0.028,
                amp_ratio=0.95,
                phase_error=0.07
            )
        },
        output_gain={
            'q0:mw-q0.01': OutputGain(gain_I=1.0, gain_Q=1.0),
            'q1:mw-q1.01': OutputGain(gain_I=1.0, gain_Q=1.0),
            'q2:mw-q2.01': OutputGain(gain_I=1.0, gain_Q=1.0),
            'q3:mw-q3.01': OutputGain(gain_I=1.0, gain_Q=1.0)
        }
    ),
    connectivity=Connectivity(graph=<quantify_scheduler.structure.types.Graph object at 0x7ccb78384ac0>),
    compilation_passes=[
        SimpleNodeConfig(name='flatten_schedule', compilation_func=<function flatten_schedule at 0x7ccb55b803a0>),
        SimpleNodeConfig(
            name='zhinst_hardware_compile',
            compilation_func=<function compile_backend at 0x7ccb55b804c0>
        )
    ]
)

This new-style config can then be passed to the QuantumDevice in order to compile a schedule for the Zurich Instruments backend, as is shown in the Compilation section of the Tutorial: Compiling to Hardware.