Skip to content

Octave

Introduction

The octave is a complementary solution for enhancing the OPX capabilities by up- and down-converting its analog outputs, creating a seamless RF front-end OPX. With the octave, one can have up to five RF outputs and two combined RF inputs operating in a frequency band of 2GHz to 18GHz. The following page serves as a user manual for the octave. For port specifications and block diagram, see the octave hardware section

octopx

See octave front panel for more information.

Getting Started

In order to work with the octave one needs to configure the device and set the connectivity between the OPX and the octave.

Note

Install the latest QUA package by typing pip install -U qm-qua.

Initiate Octave Config

Create a new instance of QmOctaveConfig and add the specific device to the instance.

from qm.octave import QmOctaveConfig

octave_config = QmOctaveConfig()
octave_config.add_device_info(octave_name, octave_ip, octave_port)
  • octave_name is the name of the specific octave device as defined by the user. For example octave_name = 'my_octave'.
  • octave_ip needs to be specified.
  • octave_port needs to be specified.

Info

When using more than one octave in the cluster, one needs to use add_device_info() for each octave.

Create File for Calibration Parameters

By using the set_calibration_db() command

octave_config.set_calibration_db(path)
a file calibraion_db.json is created at the given path. This file will be used for saving the calibration parameters. See Calibration for more information.

Tip

  • One can save calibraion_db.json file at the current working directory by setting path=os.getcwd()
  • Different users of the same octave can have different calibration databases.
  • Multiple users can share the same calibration database file by either using the same path for it or simply sharing it with each other after calibration.

Open Quantum Machine Manager

When opening a qmm, one needs to pass the octave configuration instance.

qmm = QuantumMachinesManager(host=opx_ip, port=opx_port, octave=octave_config)

Set the OPX-Octave Connectivity

It is needed to set the connectivity between the OPX's analog outputs and the octave's I,Q ports. (See octave front panel for more information)

The default connectivity is:

OCTAVE_connectivity_diagram

Note

The default connectivity is related to the connections between the OPX's analog outputs and the Octave's IQ pairs.

This is done by using the set_opx_octave_mapping() command

octave_config.set_opx_octave_mapping([(controller_name, octave_name)])

  • octave_name is the name of the specific octave device as defined by the user. For example octave_name = 'my_octave'.
  • controller_name is the name of the OPX device that is connected to this specific octave. For example controller_name = 'con1'

If the user wants to set a different port mapping, there is a need to specify the port mapping and use the add_opx_octave_port_mapping() command

octave_config.set_opx_octave_mapping(portmap)

For example, if one wants to connect

  • Analog Output 1 -> I2
  • Analog Output 2 -> Q2
  • Analog Output 3 -> I4
  • Analog Output 4 -> Q4

it can be done by:

portmap = {
    ('con1',  1) : ('octave1', 'I2'),
    ('con1',  2) : ('octave1', 'Q2'),
    ('con1',  3) : ('octave1', 'I4'),
    ('con1',  4) : ('octave1', 'Q4'),
}
octave_config.set_opx_octave_mapping(portmap)

Clock Settings

The user can work with octave's internal clock or input an external clock at the octave's back panel.

Setting the clock is done by the set_clock() command.

Internal Clock

If one wants to work with internal clock, use the command

from qm.octave.octave_manager import ClockMode

qm.octave.set_clock(octave_name, clock_mode=ClockMode.Internal)
Note

octave_name is the name of the specific octave device as defined by the user. For example octave_name = 'my_octave'.

External Clock

When working with External clock, the user needs to specify the clock frequency, which can be either 10MHz, 100MHz or 1GHz.

For example, in order to define a 10MHz external clock use the command

from qm.octave.octave_manager import ClockMode

qm.octave.set_clock(octave_name, clock_mode=ClockMode.External_10MHz)
Note

octave_name is the name of the specific octave device as defined by the user. For example octave_name = 'my_octave'.

Important

The output clock of the octave is always 1GHz.

Up Conversion Chain

There are five up converter modules in the octave. Each one of them is associated with an I,Q pair. For example, I1 Q1 pair is associated with up converter number 1 and the RF signal will be outputted from RF1 port. (See octave front panel)

Moreover, there are four internal synthesizers inside the octave. Three of them are used for up converting the signal (as can be seen in the octave block diagram), while the fourth one is used for calibration purposes.

Furthermore, it is possible to use an external LO instead of the internal one. This can be used, for example, if one wants to have five different LO frequencies simultaneously.

In order to set the up-conversion chain, one needs to configure the following:

LO Signal

Setting the LO Source is done by the set_lo_source() command.

Internal LO

qm.octave.set_lo_source(element, OctaveLOSource.Internal) 
qm.octave.set_lo_frequency(element, LO) 

Note

When using an internal LO, one needs to set_lo_frequency() as well.

External LO

When working with External LO, the user needs to specify the specific LO port on the octave's back panel.

For example, if one wants to input an external LO to the first up converting module, use the command:

qm.octave.set_lo_source(element, OctaveLOSource.LO1)

Warning

LO source number must correspond to the up converter module number.

Note

Due to the internal connectivity between the modules, the following requirements should be considered when using external LO:

  • If both up-converters 2 and 3 are being utilized, with one using an internal LO and the other using an external LO, the configuration must be set up as follows: up-converter 2 will utilize the external LO, and up-converter 3 will use the internal LO.

  • If both up-converters 4 and 5 are being utilized, with one using an internal LO and the other using an external LO, the configuration must be set up as follows: up-converter 4 will utilize the external LO, and up-converter 5 will use the internal LO.

Output Gain

There is a variable attenuator and amplifier inside each up converter module. That means that one can change the gain of the outputted signal.

This is done using the set_rf_output_gain() command

qm.octave.set_rf_output_gain(element, gain_dB)  
Note

gain_dB should be in the range \([-20:0.5:20]dB\).

Info

When changing the LO frequency, either the external LO or the internal one, there is a need to run this command again in order get the desired gain.

i.e. for internal LO,

qm.octave.set_lo_source(element, OctaveLOSource.Internal) 
qm.octave.set_lo_frequency(element, LO) 
qm.octave.set_rf_output_gain(element, gain_dB) 

and for external LO

qm.octave.set_lo_source(element, OctaveLOSource.LO1)
qm.octave.set_rf_output_gain(element, gain_dB) 

Output Mode

At the output of each up converter module, a fast switch sets the output mode. The user can change the mode of the fast switch using the command set_rf_output_mode() to one of the following:

  • on - Output is always on
  • off - Output is always off
  • trig_normal - The output will play when rising edge is detected in the octave's digital port.
  • trig_inverse - The output will play when falling edge is detected in the octave's digital port.

For example, if one wants to output a signal only when a rising edge is detected in the octave's digital port, use the following command

qm.octave.set_rf_output_mode(element, RFOutputMode.trig_normal)

Warning

Don't forget to connect the OPX's digital output to the relevant Trig port (as can be seen in the octave front panel). Moreover, it's important to calibrate the digital output's delay and buffer parameters.

Calibrating the Digital Pulse

There is an intrinsic delay between the time that the digital pulse arrives at the octave and the time that the RF pulse outputs from the octave. This time depends on the path of the digital signal inside the octave, computation time, and the time it takes for the digital switch to open. Hence, it's important to calibrate the delay and buffer parameters. The suggested parameters are: delay = 87 ns, buffer = 15 ns.

Note

These parameters may vary between different ports due to small intrinsic cable differences inside the octave and different external cables between the octave and the OPX.

Down Conversion Chain

There are two down converters inside the octave.

In order to down convert the signal, one needs to specify two things:

  1. RFin port using the command set_qua_element_octave_rf_in_port()

    For example, if using RF1in port:

    qm.octave.set_qua_element_octave_rf_in_port(element, octave_name, 1)
    
  2. LO signal using the command set_downconversion()

    Internal LO

    qm.octave.set_downconversion(element, lo_source=RFInputLOSource.Internal)
    

    External LO

    qm.octave.set_downconversion(element, lo_source=RFInputLOSource.Dmd2LO) 
    
Note

After the down converter module, the signal passes through an IF module. The IF module mode can be changed using the command set_downconversion() with three possible modes:

  • direct - the signal bypasses the IF module (default)

  • envelope - the signal passes through an envelope detector

  • mixer - the signal passes through a low frequency mixer

Info

After the down converter modules, I1 and I2 are combined, pass through a bias Tee and outputted from IFOUT1. While Q1 and Q2 are combined, pass through a bias Tee and outputted from IFOUT2. The lower IF frequency cutoff after downconversion is around 10 MHz.

Warning

In order to use down converter 2 one needs to input an LO signal to the Dmd2LO port on the octave's back panel. It is possible to loop back the signal from the relevant Synth on the octave's back panel.

Automatic Calibration

It is possible to run an automatic calibration in order to calibrate the IQ mixers inside each up converter module. To do so:

  • Connect the OPX's analog outputs to the octave's I,Q pairs.
  • Connect the OPX's analog inputs to the IFOUT1, IFOUT2 octave's ports.

Then calibrate using the calibrate_element() command:

 qm.octave.calibrate_element(element, [(LO, IF)])
Note
  • (LO, IF) is the LO and IF frequency as written in the mixer section associated with this element.
  • The user can provide a list of pairs of (LO, IF) as long as all the LOs are the same for one calibration command.
Info
  • When running this command, the OPX sends pulses through the analog outputs to the octave. Those pulses gets up converted and are sent internally to the down converters modules. Then, the down converted signal is sent to the OPX through the IFOUT1, IFOUT2 ports. The calculation is done on the OPX's FPGA and the calibrated parameters and saved in the calibration_db.json file.
  • By default, this command closes all running quantum machines. Hence, one needs to open a quantum machine after calibration.
  • When the user opens a quantum machine, the calibrated parameters are taken automatically from the calibraion_db.json file.

Example

In the following example you can see how to use the octave in order to up-convert and down-convert the resonator element.

The relevant parts in the configuration are

"resonator": {
    "mixInputs": {
        "I": ("con1", 1),
        "Q": ("con1", 2),
        "lo_frequency": resonator_LO,
        "mixer": "octave_my_octave_1",  
    },
    "outputs": {
        "out1": ("con1", 1),
        "out2": ("con1", 2),
    },
    ...
    }
...
"mixers": {
    "octave_my_octave_1": [
        {
            "intermediate_frequency": resonator_IF,
            "lo_frequency": resonator_LO,
            "correction": (1, 0, 0, 1),
        }
    ],
    },

Info

The name of the mixer that is used within an element that is associated to the octave in the configuration should be "octave_octave_name_RFportnumber".

  • octave_name is the name of the specific octave device as defined by the user.
  • RFportnumber can be 1 to 5.
  • An example for the mixer name "octave_my_octave_1".

Then the API commands are

from qm.octave.octave_manager import ClockMode

octave_config = QmOctaveConfig()
octave_config.set_calibration_db(os.getcwd())
octave_config.add_device_info("my_octave", octave_ip, octave_port)
octave_config.set_opx_octave_mapping([("con1", "my_octave")])

qmm = QuantumMachinesManager(host=opx_ip, port=opx_port, octave=octave_config)
qm = qmm.open_qm(config)

# clock settings #
qm.octave.set_clock("my_octave", clock_mode=ClockMode.Internal)

# up-conversion chain #
qm.octave.set_lo_source("resonator", OctaveLOSource.Internal)  
qm.octave.set_lo_frequency("resonator", resonator_LO) 
qm.octave.set_rf_output_gain("resonator", 0)  
qm.octave.set_rf_output_mode("resonator", RFOutputMode.on)

# down-conversion chain #
qm.octave.set_qua_element_octave_rf_in_port("resonator", "my_octave", 1)
qm.octave.set_downconversion("resonator", lo_source=RFInputLOSource.Internal)

# automatic calibration # 
qm.octave.calibrate_element("resonator", [(resonator_LO, resonator_IF)])  
qm = qmm.open_qm(config)

Note

The octave settings in the case are:

  • Using an internal clock
  • Using the default port mapping
  • The up-converter is using an internal LO synthesizer, with gain 0 and output mode "on"
  • The down converter chain is using an internal LO synthesizer and RF1in port

Batch Octave Commands for Quick Setting

Since qm-qua version 1.1 it is possible to send many octave configuration commands in one message for a faster octave configuration. This is done using what we call Batch Mode. In order to use it one must add [start_batch_mode()][qm.octave.qm_octave.QmOctave.start_batch_mode] before writing all the configuration commands and after the commands add a new line with [end_batch_mode()][qm.octave.qm_octave.QmOctave.end_batch_mode]. for example:

qm.octave.start_batch_mode()
qm.octave.set_lo_source("resonator", OctaveLOSource.Internal)  
qm.octave.set_lo_frequency("resonator", resonator_LO) 
qm.octave.set_rf_output_gain("resonator", 0)  
qm.octave.set_rf_output_mode("resonator", RFOutputMode.on)
qm.octave.set_qua_element_octave_rf_in_port("resonator", "my_octave", 1)
qm.octave.set_downconversion("resonator", lo_source=RFInputLOSource.Internal)
qm.octave.end_batch_mode()
It can also be done with context manager in the following way:
with qm.octave.batch_mode():
    qm.octave.set_lo_source("resonator", OctaveLOSource.Internal)  
    qm.octave.set_lo_frequency("resonator", resonator_LO) 
    qm.octave.set_rf_output_gain("resonator", 0)  
    qm.octave.set_rf_output_mode("resonator", RFOutputMode.on)
    qm.octave.set_qua_element_octave_rf_in_port("resonator", "my_octave", 1)
    qm.octave.set_downconversion("resonator", lo_source=RFInputLOSource.Internal)
This code snippet sends all the commands in one message and can at some cases, especially for more than 4 octaves in one cluster, be much faster than sending each command separately.

Examples and Usage Tutorials

Take a look at the octave tutorial in our GitHub repository, where you can find a template for integrating the octave within your experiments!