Acquisition protocols
The dataset returned by
InstrumentCoordinator.retrieve_acquisition()
consists of a number of DataArray
s containing data for every
acquisition channel.
This document specifies the format of these data arrays.
Imports and auxiliary definitions
import numpy as np
import xarray as xr
import hvplot.xarray
intermodulation_freq = 1e8 # 100 MHz
voltage_iq = 0.32 + 0.25j
sampling_rate = 1.8e9 # 1.8 GSa/s
readout_duration = 1e-7 # 100 ns
time_grid = xr.DataArray(
np.arange(0, readout_duration, sampling_rate**-1), dims="trace_index"
)
(Demodulated) Trace Acquisition Protocol
Referred to as
"Trace"
.Supported by
Qblox
andZurich Instruments
backends.
Readout equipment digitizes a \(V(t)\), where \(V = V_I + i V_Q\) is a complex voltage on inputs of a readout module (up/down conversion of a signal with an IQ mixer is assumed). The signal is demodulated with an intermodulation frequency configured for a readout port.
For example, if we have a readout module (like Qblox QRM or Zurich Instruments UHFQA) that is perfect, and connect its outputs to its inputs directly, raw input on a readout port will look like this:
Show code cell source
raw_trace = (
voltage_iq * np.exp(2j * np.pi * intermodulation_freq * time_grid)
).assign_coords({"trace_time": time_grid})
xr.Dataset({"I": raw_trace.real, "Q": raw_trace.imag}).hvplot(
x="trace_time", xlabel="t [s]", ylabel="V", group_label="Channel"
)
/home/rsoko/.anaconda3/envs/tmp/lib/python3.9/site-packages/holoviews/core/data/pandas.py:39: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
return dataset.data.dtypes[idx].type
/home/rsoko/.anaconda3/envs/tmp/lib/python3.9/site-packages/holoviews/core/data/pandas.py:39: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
return dataset.data.dtypes[idx].type
Demodulated trace will unroll this data with respect to the intermodulation frequency, so the resulting I and Q readouts will look like this:
Show code cell source
demodulated_trace = raw_trace * np.exp(-2j * np.pi * intermodulation_freq * time_grid)
xr.Dataset({"I": demodulated_trace.real, "Q": demodulated_trace.imag}).hvplot(
x="trace_time", xlabel="t [s]", ylabel="V", group_label="Channel"
)
/home/rsoko/.anaconda3/envs/tmp/lib/python3.9/site-packages/holoviews/core/data/pandas.py:39: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
return dataset.data.dtypes[idx].type
/home/rsoko/.anaconda3/envs/tmp/lib/python3.9/site-packages/holoviews/core/data/pandas.py:39: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
return dataset.data.dtypes[idx].type
This acquisition protocol is currently supported only in BinMode.AVERAGE
binning mode.
The resulting dataset must contain data arrays with two dimensions for each acquisition
channel: acquisition index (number of an acquisition in a schedule) and trace index
(that corresponds to time from the start of the acquisition).
All the dimension names should be suffixed with the acquisition channel to avoid
conflicts while merging the datasets.
It is recommended to annotate the trace index dimension with a coordinate that describes
time since the start of the acquisition.
For example, if two acquisition channels read out once, the resulting dataset should have
the following structure:
Show code cell source
xr.Dataset(
{
0: demodulated_trace.expand_dims("acq_index_0", 0).rename(
{"trace_index": "trace_index_0", "trace_time": "trace_time_0"}
),
1: demodulated_trace.expand_dims("acq_index_1", 0).rename(
{"trace_index": "trace_index_1", "trace_time": "trace_time_1"}
),
}
)
<xarray.Dataset> Dimensions: (trace_index_0: 180, acq_index_0: 1, trace_index_1: 180, acq_index_1: 1) Coordinates: trace_time_0 (trace_index_0) float64 0.0 5.556e-10 ... 9.889e-08 9.944e-08 trace_time_1 (trace_index_1) float64 0.0 5.556e-10 ... 9.889e-08 9.944e-08 Dimensions without coordinates: trace_index_0, acq_index_0, trace_index_1, acq_index_1 Data variables: 0 (acq_index_0, trace_index_0) complex128 (0.32+0.25j) ... (0... 1 (acq_index_1, trace_index_1) complex128 (0.32+0.25j) ... (0...
Single-sideband Complex Integration
Referred to as
"SSBIntegrationComplex"
.Supported by
Qblox
andZurich Instruments
backends.
In this acquisition protocol acquired voltage trace gets demodulated and averaged. For each acquisition, a single complex voltage value is returned (\(V_I + i V_Q\)).
This acquisition protocol supports BinMode.APPEND
binning mode for single-shot readout
and BinMode.AVERAGE
binning mode for returning data averaged for several
executions of a schedule.
In the first case data arrays for each acquisition channel will have two dimensions:
repetition and acquisition index.
All the dimension names except repetition should be suffixed with the acquisition
channel to avoid conflicts while merging the datasets, the repetition dimension must be
named "repetition"
.
For example two acquisition channels of which acquisition channel 0 read out three
times and acquisition channel two read out two times, the resulting dataset should have
the following structure in BinMode.APPEND
:
Show code cell source
xr.Dataset(
{
0: demodulated_trace.reduce(np.average, "trace_index").expand_dims(
{"repetition": 5, "acq_index_0": 3}
),
2: demodulated_trace.reduce(np.average, "trace_index").expand_dims(
{"repetition": 5, "acq_index_2": 2}
),
}
)
<xarray.Dataset> Dimensions: (repetition: 5, acq_index_0: 3, acq_index_2: 2) Dimensions without coordinates: repetition, acq_index_0, acq_index_2 Data variables: 0 (repetition, acq_index_0) complex128 (0.32+0.25j) ... (0.32+0.25j) 2 (repetition, acq_index_2) complex128 (0.32+0.25j) ... (0.32+0.25j)
In BinMode.AVERAGE
repetition dimension gets reduced and only the acquisition index
dimension is left for each channel:
Show code cell source
xr.Dataset(
{
0: demodulated_trace.reduce(np.average, "trace_index").expand_dims(
{"acq_index_0": 3}
),
2: demodulated_trace.reduce(np.average, "trace_index").expand_dims(
{"acq_index_2": 2}
),
}
)
<xarray.Dataset> Dimensions: (acq_index_0: 3, acq_index_2: 2) Dimensions without coordinates: acq_index_0, acq_index_2 Data variables: 0 (acq_index_0) complex128 (0.32+0.25j) (0.32+0.25j) (0.32+0.25j) 2 (acq_index_2) complex128 (0.32+0.25j) (0.32+0.25j)
Numerical Weighted Complex Integration
Referred to as
"NumericalWeightedIntegrationComplex"
.Supported by
Qblox
.
Equivalent to SSB complex integration, but instead of a simple average of a demodulated signal weighted average is taken. The dataset format is also the same.
Integration weights should normally be calibrated in a separate experiment (see, for example, Magesan et al. [MGCorcolesC15]).