Pulsar QCM/QRM

Each device in the setup can be individually configured using the entry in the config. For instance:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
mapping_config = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM",
        "ref": "internal",
        "complex_output_0": {
            "line_gain_db": 0,
            "lo_name": "lo0",
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
                "interm_freq": 50e6
            }
        },
        "complex_output_1": {
            "line_gain_db": 0,
            "lo_name": "lo1",
            "seq1": {
                "port": "q1:mw",
                "clock": "q1.01",
                "interm_freq": None
            }
        }
    },
    "lo0": {"instrument_type": "LocalOscillator", "frequency": None, "power": 20},
    "lo1": {"instrument_type": "LocalOscillator", "frequency": 7.2e9, "power": 20}
}

Here we specify a setup containing only a Pulsar QCM, with both outputs connected to a local oscillator sources.

The first few entries in the dictionary contain settings and information for the entire device. "type": "Pulsar_QCM" specifies that this device is a Pulsar QCM, and "ref": "internal" sets the reference source to internal (as opposed to "external"). Under the entries complex_output_0 (corresponding to O1/2) and complex_output_1 (corresponding to O3/4), we set all the parameters that are configurable per output.

The examples given below will be for a single Pulsar QCM, but the other devices can be configured similarly. In order to use a Pulsar QRM, QCM-RF or QRM-RF, change the "instrument_type" entry to "Pulsar_QRM", "Pulsar_QCM_RF" or "Pulsar_QRM_RF" respectively. Multiple devices can be added to the config, similar to how we added the local oscillators in the example given above.

Output settings

Most notably under the complex_output_0, we specify the sequencer settings.

1
2
3
4
5
"seq0": {
    "port": "q0:mw",
    "clock": "q0.01",
    "interm_freq": 50e6
}

Here we describe which port and clock the sequencer is associated with (see the User guide for more information on the role of ports and clocks within the Quantify-Scheduler). The other entry, interm_freq, specifies the intermediate frequency to use for I/Q modulation (in Hz).

I/Q modulation

To perform upconversion using an I/Q mixer and an external local oscillator, simply specify a local oscillator in the config using the lo_name entry. complex_output_0 is connected to a local oscillator instrument named lo0 and complex_output_1 to lo1. Since the Quantify-Scheduler aim is to only specify the final RF frequency when the signal arrives at the chip, rather than any parameters related to I/Q modulation, we specify this information here.

The backend assumes that upconversion happens according to the relation

\[f_{RF} = f_{IF} + f_{LO}\]

This means that in order to generate a certain \(f_{RF}\), we need to specify either an IF or an LO frequency. In the dictionary, we therefore either set the lo_freq or the interm_freq and leave the other to be calculated by the backend by specifying it as None. Specifying both will raise an error if it violates \(f_{RF} = f_{IF} + f_{LO}\).

Downconverter

Some users may have a custom Qblox downconverter module operating at 4.4 GHz. In order to use it with this backend, we should specify a "downconverter": True entry in the outputs that are connected to this module, as exemplified below. The result is that the downconversion stage will be taken into account when calculating the IF or LO frequency (whichever was undefined) during compilation, such that the signal reaching the target port is at the desired clock frequency.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
mapping_config_rf = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM_RF",
        "ref": "internal",
        "complex_output_0": {
            "downconverter": True,
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
                "interm_freq": 50000000.0
            }
        }
    }
}
hardware_compile(test_sched, mapping_config_rf)

Mixer corrections

The backend also supports setting the parameters that are used by the hardware to correct for mixer imperfections in real-time.

We configure this by adding the lines

1
2
"dc_mixer_offset_I": -0.054,
"dc_mixer_offset_Q": -0.034,

to complex_output_0 (or complex_output_1) in order to add a DC offset to the outputs to correct for feed-through of the local oscillator signal. And we add

1
2
"mixer_amp_ratio": 0.9997,
"mixer_phase_error_deg": -4.0,

To the sequencer configuration in order to correct to set the amplitude and phase correction to correct for imperfect rejection of the unwanted sideband.

Usage without an LO

In order to use the backend without an LO, we simply remove the "lo_name" and all other related parameters. This includes the mixer correction parameters as well as the frequencies.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
mapping_config = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM",
        "ref": "internal",
        "complex_output_0": {
            "line_gain_db": 0,
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
            }
        },
        "complex_output_1": {
            "line_gain_db": 0,
            "seq1": {
                "port": "q1:mw",
                "clock": "q1.01",
            }
        }
    },
}

Frequency multiplexing

It is possible to do frequency multiplexing of the signals by adding multiple sequencers to the same output.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
mapping_config = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM",
        "ref": "internal",
        "complex_output_0": {
            "line_gain_db": 0,
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
            },
            "seq1": {
                "port": "q0:mw",
                "clock": "some_other_clock",
            }
        },
        "complex_output_1": {
            "line_gain_db": 0,
            "seq2": {
                "port": "q1:mw",
                "clock": "q1.01",
            }
        }
    },
}

In the given example, we added a second sequencer to output 0. Now any signal on port "q0:mw" with clock "some_other_clock" will be added digitally to the signal with the same port but clock "q0.01". The Qblox modules currently have six sequencers available, which sets the upper limit to our multiplexing capabilities.

Note

We note that it is a requirement of the backend that each combination of a port and a clock is unique, i.e. it is possible to use the same port or clock multiple times in the hardware config but the combination of a port with a certain clock can only occur once.

Real mode

For the baseband modules, it is also possible to use the backend to generate signals for the outputs individually rather than using IQ pairs.

In order to do this, instead of "complex_output_X", we use "real_output_X". In case of a QCM, we have four of those outputs. The QRM has two available.

The resulting config looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mapping_config = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM",
        "ref": "internal",
        "real_output_0": {
            "line_gain_db": 0,
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
            }
        },
        "real_output_1": {
            "line_gain_db": 0,
            "seq1": {
                "port": "q1:mw",
                "clock": "q1.01",
            }
        },
        "real_output_2": {
            "line_gain_db": 0,
            "seq2": {
                "port": "q2:mw",
                "clock": "q2.01",
            }
        }
    },
}

When using real outputs, the backend automatically maps the signals to the correct output paths. We note that for real outputs, it is not allowed to use any pulses that have an imaginary component i.e. only real valued pulses are allowed. If you were to use a complex pulse, the backend will produce an error, e.g. square and ramp pulses are allowed but DRAG pulses not.

Warning

When using real mode, we highly recommend using it in combination with the instrument coordinator as the outputs need to be configured correctly in order for this to function.

Experimental features

The Qblox backend contains some intelligence that allows it to generate certain specific waveforms from the pulse library using a more complicated series of sequencer instructions, which helps conserve waveform memory. Though in order to keep the backend fully transparent, all such advanced capabilities are disabled by default.

In order to enable the advanced capabilities we need to add line "instruction_generated_pulses_enabled": True to the sequencer configuration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
mapping_config = {
    "backend": "quantify_scheduler.backends.qblox_backend.hardware_compile",
    "qcm0": {
        "instrument_type": "Pulsar_QCM",
        "ref": "internal",
        "complex_output_0": {
            "line_gain_db": 0,
            "seq0": {
                "port": "q0:mw",
                "clock": "q0.01",
                "instruction_generated_pulses_enabled": True
            }
        },
    },
}

Currently this has the following effects:

  • Long square pulses get broken up into separate pulses with durations <= 1 us, which allows the modules to play square pulses longer than the waveform memory normally allows.

  • Staircase pulses are generated using offset instructions instead of using waveform memory