Logical and Experimental Signals¶
LabOne Q abstracts the real, physical channels in your system into logical signal lines, which are grouped in logical signal groups. Logical signal lines abstract instruments, physical channels, and hardware calibration settings into a single Python object. This separates the hardware from the quantum experiments — which you can define freely, and whose experimental signal lines are mapped only later to the logical signal lines. This allows for instrumentation-agnostic experiment definitions, which can be re-used later.
In this chapter, we will explain the concept of logical signals,
experimental signals, and how they are related to, but differ, from
physical instrument lines. First, logical signals and how they are
defined in the Descriptor
are
introduced. Then, it is shown how they are linked to experimental
signals.
Logical Signals¶
In a qubit experiment, you need to both control and measure your qubits. To control your qubits, you need a combination of drive lines and flux lines, and to measure, you need to send a pulse down a measurement line and evaluate the response in an acquire line. For our example experiment, we have four logical signal types: drive, flux, measure, and acquire, which form a logical signal group for each qubit.
Note
The signal type names, as well as the group names, are entirely
arbitrary and determined by the user. However, the associated type of
signal on the device is not arbitrary and will be either
acquire_signal
, rf_signal
, or iq_signal
, see details
here.
Within a logical signal group, we can have more than one line of a
single type, two drive lines, for example. Each group will have its own
sets of signal lines, and they are programmatically distinct from one
another. Logical signal lines retain this distinction even if the
physical lines used are the same. For example, if we have our first
qubit, q0
, and our second qubit, q1
, on the same physical
multiplexed acquisition line, they will still have separate logical
measure and acquire lines associated with them.
Defining Logical Signals¶
Logical signal lines are defined in the
Descriptor of the DeviceSetup
object. Let’s dissect a more complex Descriptor example than was
previously discussed to understand how we can use logical signal lines.
my_descriptor = """\
instrument_list:
HDAWG:
- address: DEV8xyz
uid: device_hdawg
SHFQA:
- address: DEV12yxz
uid: device_shfqa
SHFSG:
- address: DEV12xyz
uid: device_shfsg
PQSC:
- address: DEV10xyz
uid: device_pqsc
connections:
device_hdawg:
- iq_signal: q0/drive_line
ports: [SIGOUTS/0, SIGOUTS/1]
- rf_signal: q0/flux_line
ports: [SIGOUTS/4]
- rf_signal: q1/flux_line
ports: [SIGOUTS/6]
device_shfsg:
- iq_signal: q1/drive_line
ports: SGCHANNELS/0/OUTPUT
device_shfqa:
- iq_signal: q0/measure_line
ports: QACHANNELS/0/OUTPUT
- acquire_signal: q0/acquire_line
ports: QACHANNELS/0/INPUT
- iq_signal: q1/measure_line
ports: QACHANNELS/0/OUTPUT
- acquire_signal: q1/acquire_line
ports: QACHANNELS/0/INPUT
device_pqsc:
- to: device_hdawg
port: ZSYNCS/0
- to: device_shfsg
port: ZSYNCS/1
- to: device_shfqa
port: ZSYNCS/2
"""
In our Descriptor
, we first listed the instruments used and specified
their serial numbers. We also have given them a user-defined uid
.
In the connections part of our Descriptor
, for each uid
, we defined
the type of signal (acquire_signal
, rf_signal
, iq_signal
, or
to
), the corresponding logical signal group and line, and the
associated physical ports of the device.
For our HDAWG, we have three logical signal lines. Let’s take a look at the first one:
device_hdawg:
- iq_signal: q0/drive_line
ports: [SIGOUTS/0, SIGOUTS/1]
This logical signal line is named drive_line
. It is in the q0
logical signal group, and it has an iq_signal
type. To specify both
the I and Q components of the signal, we need two physical outputs of
the HDAWG, given by the first (SIGOUTS/0
) and second (SIGOUTS/1
)
wave outputs on the HDAWG.
The other two logical signal lines both have the same name:
flux_line
, but they are located in different logical signal groups,
q0
and q1
. Names of logical signal lines must only be unique if
they are located in the same group. Both of these lines have the signal
type rf_signal
and, therefore, only need a single physical wave
output:
device_hdawg:
- rf_signal: q0/flux_line
ports: [SIGOUTS/4]
- rf_signal: q1/flux_line
ports: [SIGOUTS/6]
The next device, the SHFSG, is straight forward: The logical_signal
q1/drive_line
is mapped to the SHFSG’s first physical output channel:
device_shfsg:
- iq_signal: q1/drive_line
ports: SGCHANNELS/0/OUTPUT
To measure our qubits, we need to specify some more logical signal
lines, which we do for the next instrument in our Descriptor
:
device_shfqa:
- iq_signal: q0/measure_line
ports: QACHANNELS/0/OUTPUT
- acquire_signal: q0/acquire_line
ports: QACHANNELS/0/INPUT
- iq_signal: q1/measure_line
ports: QACHANNELS/0/OUTPUT
- acquire_signal: q1/acquire_line
ports: QACHANNELS/0/INPUT
Here, we have four logical signal lines, two named measure_line
, which
are iq_signal
types for sending qubit readout pulses, and two named
acquire_line
, for data acquisition on the input of SHFQA. Two of the
measure and acquire lines are in the logical group q0
and the others
are in q1
. As both line pairs use the same physical channel on the
instrument, the output signals are added, resulting in a frequency
multiplexing. On the input side, each logical signal line has its own
integration weights.
The PQSC has no logical signals associated with it.
Experimental Signals¶
In every Experiment
definition, the signals used are defined within
the Experiment
itself, with no reference to either logical signals or
physical device channels. This allows experiments to be reused and
adapted quickly and independently of the hardware itself. For a qubit
spectroscopy experiment, the definition of the experiment might look
like:
exp_qubit_spec = Experiment(
uid="Qubit Spectroscopy",
signals=[
ExperimentSignal("drive"),
ExperimentSignal("measure"),
ExperimentSignal("acquire"),
]
)
Signal Maps¶
Within the experiment definition, all pulses of the sequence are played
on ExperimentSignals
. Later, these experimental signals must be
mapped to logical signals, and it is easy to repeat the same
Experiment
by creating multiple maps with the same Experiment
signals but different logical signal lines.
## signal map for qubit 0
q0_map = {"drive": "/logical_signal_groups/q0/drive_line",
"measure": "/logical_signal_groups/q0/measure_line",
"acquire": "/logical_signal_groups/q0/acquire_line",
}
## signal map for qubit 1
q1_map = {"drive": "/logical_signal_groups/q1/drive_line_ge",
"measure": "/logical_signal_groups/q1/measure_line",
"acquire": "/logical_signal_groups/q1/acquire_line",
}
Once a signal map is defined, setting the mapping and running your experiment is straightforward:
## apply qubit 0 signal map and run the experiment
exp_qubit_spec.set_signal_map(q0_map)
my_results_q0 = my_session.run(exp_qubit_spec)
## apply qubit 1 signal map and run the experiment
exp_qubit_spec.set_signal_map(q1_map)
my_results_q1 = my_session.run(exp_qubit_spec)
Note
The experiment definition is agnostic of the fact that the q0/drive
signal is coming from an HDAWG and the q1/drive_ge
signal is coming
from an SHFSG.
By keeping instrumentation, logical signals, and experimental signals separate, it is easy to modify, reuse, and adapt your code for any hardware or qubit configuration, with very little to rewrite or modify.