Output data formats

Controls and measurement data may be output in multiple formats for use in theoretical analysis or direct integration with experimental hardware. The various file and data formats described below are employed for each of these.

There are two types of files that can be imported or exported - CSV and JSON. Here we give some general advice on how to open and/or create these kinds of files.


JSON is an open-standard, human readable and flexible file type, that is used by as basis for many of Q-CTRLs data formats. For more details on its definition, application and history see JSON on Wikipedia.

Here we provide some practical advice on how to work with this file type and integrate it into a work flow with a quantum technology.

Quick viewing and editing

JSON files can be opened and read in any text editor, some more advanced text editors, like Visual Studio Code, can also provide plug ins for easy viewing and editing of JSON files, with automatic formatting.

You can also go to websites that check validation of JSON files, like JSON Formatter & Validator, then paste the content of a JSON if you want to quickly view the content of a JSON file with friendly formatting and expandable/compression sections.

Advanced viewing and editing

If you want to more seriously edit content from a JSON file in preparation of sending it to a machine that supports a specific file type format, you can also edit the file using most programming languages. JSON is a common format that is widely supported, here we give some examples on how to import, export and manipulate files in Python and MATLAB


If you do not have a python installation we recommend using the Anaconda distribution. Once you have a working installation start you can open and edit files using the JSON Python module.

We provide a quick example of working with a JSON file generated from a noise characterization.

Download a sample noise characterization JSON file

To open and edit this file open a python session and input the commands below. Or execute the following notebook made using Jupyter Notebook.

DDownload a JSON import/export jupyter notebook

First we need to open the file and use the JSON parser provided in python to turn it into a combination of dictionaries and/or lists (depending on the file contents).

import json

with open('example-characterization.json') as file:
    example = json.load(file)

Once you have imported the file you can then extract the data from the dictionary and/or lists like you normally would.

For example we can first recursively goes through the dictionary and lists and prints the keys that are available:

def print_keys(obj, indent=''):
    if isinstance(obj, dict):
        for key in obj:
            print('\n' + indent + key, end='')
            print_keys(obj[key], indent=indent + '  ')
    elif isinstance(obj, list):
        print(' [', end='')
        for elem in obj:
            print_keys(elem, indent=indent + '  ')
        print(']', end='')


This command should produce output that looks like:

sequences [
    detuning_rotations []
    azimuthal_angles []
    offsets []
    rabi_rotations []
    detuning_rotations []
    azimuthal_angles []
    offsets []
    rabi_rotations []
    detuning_rotations []
    azimuthal_angles []
    offsets []
    rabi_rotations []]

Here we can see the a characterization is of a dictionary that contains meta data related to how the characterization was constructed, and it contains a list of controls that can need to be executed on your machine.

You will probably want to then export the controls to a data format suitable for your particular pulse generator.

For example your machine may expect a header-less CSV file with times, rounded to three decimal places, corresponding to each pi pulse. Here we show how this can be achieved using the savetxt command from Numpy:

import numpy as np

for sequence in example['sequences']:
    np.savetxt(sequence['name'] + '.csv',

Here we simply perform a loop over all the sequences in the sequences list, then we use the name attribute. This will produce a set of CSV files called:


Where each files has content like:


Whatever data format you happen to need you can quickly and easily use python to convert a JSON file into whatever format you need.


CSV is a common data format that Q-CTRL uses for files to are expected to be used on control devices, such as microwave pulse generators. For more details on its definition, application and history see CSV on Wikipedia. We typically expect CSV files to be appropriately customized for your hardware device, but if you also have the following options if you want to open and edit a CSV file.

Viewing and editing

CSV can be viewed and edited with any text editor. As it is a tabular format it can also be opened and exported from Excel. Proprietary numerical packages like MATLAB support importing and exporting. As do open source alternatives like Numpy.

Q-CTRL analytic

In many cases controls may be represented simply in an analytic form. For instance, most dynamic decoupling sequences may be simply defined by the times at which a control operation is applied rather than providing a hardware-compatible sampled waveform. For such occasions Q-CTRL Analytic provides simple definitions of controls which are easily human readable.

Q-CTRL hardware

The Q-CTRL expanded format is designed for direct integration of control solutions into experimental hardware. In general controls are output as vectors defined for the relevant operators sampled in time at a rate consistent with typical experimental conditions.

All control amplitudes are scaled to a maximum value of unity consistent with saturation of the maximum Rabi rate may be scaled by a user-specific factor to produce compatibility with hardware requirements.

Single-qubit driven control

Controls for single qubits can be represented in Q-CTRL Expanded format. The Q-CTRL Expanded format is available in both Cartesian and Cylindrical representations.

maximum_rabi_rate The maximum Rabi rate of the control in rad Hz which all other amplitudes and Rabi rates are proportional to
amplitude_x The amplitude of the X quadrature of the qubit drive (proportional to the maximum Rabi rate)
amplitude_y The amplitude of the Y quadrature of the qubit drive (proportional to the maximum Rabi rate)
detuning The detuning of the qubit in rad Hz
durations The duration of a segment
maximum_rabi_rate The maximum Rabi rate of the control in rad Hz which all other amplitudes and Rabi rates are proportional to
rabi_rate The Rabi rate of the qubit drive (proportional to the maximum Rabi rate)
azimuthal_angle The phase of the Rabi rate drive - aligned such that a zero value corresponds to a rotation about the x axis on the Bloch sphere
detuning The detuning of the qubit in rad Hz
durations The duration of a segment

Controls defined using shaped control segments will always be discretized at the sample rate in this format.

If a control with a gaussian shape is saved in an expanded format and later used to create a custom control, it will not exactly match the original control.

Multi-qubit controls

Current multi-qubit controls employ the same general file structure as single-qubit controls, appropriately expanded to include all relevant control parameters as described in control Hamiltonian.


IBM has authored an IBM OpenPulse format for specifying time varying controls of qubit in a quantum computer. Controls developed in Q-CTRL products can be output in this format.

The OpenPulse format makes certain assumptions about the structure of a control used in a quantum computer. It assumes that each segment that makes up the control has an equal duration and it assumes that only control over the $\sigma_x$ and $\sigma_y$ operators is permitted. These assumptions are stronger than what Q-CTRL uses when defining a control for a qubit. Q-CTRL allows for arbitrary durations and detuning control as well. Nevertheless, in many cases we can do an exact transformation between the control and what is output in the OpenPulse format. When this is not possible an approximation must be performed that is described below.

The OpenPulse format has the following keys:

dt is the discretization durations, the time between the amplitude points defined in “samples”
name is the control name. If not provided, it is an empty string
samples list of complex values describing the amplitude points for the control envelope

Each element in the list is \(\begin{align} [ \cos(\tilde{\alpha}_{i}), &\hspace{0.25cm} \sin(\hat{\alpha}_{i}) ] \end{align}\) where $\hat{\alpha}_{i}$ is the amplitude of the $i$th segment of the discretized pulse.

The amplitudes \(\hat{\alpha}_{i}\) and the discretization time $dt$ are derived from the amplitudes $\alpha_{i}$ and segment durations $\tau_{i}$ of a Q-CTRL control solution. See Control Segments for the Q-CTRL control solution format. For a square control, we have the following three cases.

  • If the segment durations are the same, that is for all $i, j$, $\tau_{i} = \tau_{j}$, then no discretization is performed. For all $i$, \(\hat{\alpha}_{i} = \alpha_{i}\) and \(dt = \tau_{i}\).
  • If the segment durations are integer multiples of the minimum segment duration, then $dt = \min_{i} \tau_{i}$. If the $j^{\rm th}$ segment has a duration $\tau_{j} > dt$, then this segment is evenly divided into $\frac{\tau_{j}}{dt} \in \mathbb{Z}^{+}$ segments, each with duration $dt$ and amplitude $\alpha_{j}$.
  • If the segment durations are not integer multiples of the minimum segment duration, then the control solution is evenly divided into 100 segments. Each segment thus has a segment duration $dt = \frac{\tau}{100} = t_{i+1} - t_{i}$, where $\tau$ is the total duration. Each segment has a constant amplitude defined as the amplitude of the original control evaluated at the midpoint $\frac{t_{i+1} - t_{i}}{2}$. For example, the amplitude of the first segment \(\hat{\alpha}_{1} = \alpha\rvert_{\frac{t_{i+1} - t_{i}}{2}}\). If the midpoint coincides with the boundary between two segments in the original control, the amplitude is defined to be the amplitude of the left segment.