Experiment¶
In this chapter, we provide a brief overview of the functionality of the
Experiment
class. Conceptual chapters for gaining an in-depth
understanding of how to program your experiments can be found at the
following links:
- Logical and Experimental Signals
- Sections and Pulses
- Calibrating Signals
- Experiment Calibration
- Averaging and sweeping
- Results
- Callback Functions and 3rd-Party Devices
Additionally, a comprehensive list of arguments and details of the
Experiment
class can be found in the API
documentation.
The Experiment
class is the main interface to define your experiments
in LabOne Q. It allows you to define your pulse sequence using pulses,
sections and real- and near-time loops, tell LabOne Q which experimental
signal lines the pulses should be played on, set experiment-specific
calibrations, determine how you sweep parameters, average over results,
set and get arbitrary instrument nodes, and use callback functions.
Experiment Definition¶
Experiments are defined with a unique ID, “uid”, and with the signal lines to be used in the experiment:
exp = Experiment(
uid="Experiment_Name",
signals=[
ExperimentSignal("Signal_Name_0"),
ExperimentSignal("Signal_Name_1")
],
)
Note
Any number of ExperimentSignal
lines can be given, and their names,
like the uid, are defined by the user. All experimental signal lines
must be mapped to logical lines
before the experiment can be compiled.
Once you have defined the Experiment
object, a pulse sequence is
defined using near-time sweeps (optional), real-time acquisition loops
and real-time sweeps, sections, and pulse commands. A minimum of one
outer acquire_loop_rt
, one section, and one pulse is required for a
valid experiment:
## Experiment definition
exp = Experiment(
uid="Minimum",
signals=[
ExperimentSignal("drive"),
],
)
## Real time acquisition loop
with exp.acquire_loop_rt(
uid="shots",
count=1
):
## The Section
with exp.section(uid="Section_name"):
## Section contents
exp.play(
signal="drive",
pulse=pulse_library.gaussian(
uid = "pulse_name",
length=100e-9,
amplitude=0.5),
)
Note
Near-time sweeps cannot be nested within real-time acquisition loops as discussed here.
Experiment Calibration¶
Experiments may, but are not required to, have their own Calibration
applied to them. An experiment
calibration is valid only for the
experiment it is defined for and overrides the global calibration for
the time the experiment runs. The global calibration is not changed and
will stay valid through the entire session.
exp.set_calibration(experiment_calibration)
Experimental Signal Map¶
A map from the ExperimentSignal
lines to logical signal
lines must be made before the
experiment can be compiled and run. A valid map definition for the above
minimal sequence might be:
map = {
"drive": device_setup.logical_signal_groups["q0"].logical_signals["drive_line"]
}
The signal map must be set before compiling or running the experiment:
exp.set_signal_map(map)
Compiling and Running Experiments¶
To compile or run the experiment, users must create a
Session and connect to it. This requires a
DeviceSetup
:
session = Session(device_setup=device_setup)
The Session can be connected either to the instruments themselves (the default) or through an emulator (which does not require any connected hardware).
## To connect to an emulator:
session.connect(do_emulation=True)
## To connect to the data sever defined in the `DeviceSetup`
## and, through it, to the instruments:
session.connect(do_emulation=False)
Compiling Experiments¶
Users have a choice to compile experiments before running them or to compile and run all at once. Compiling an experiment before the execution can make sense to inspect pulse sequences and timings. An experiment may be compiled without running it:
compiled_exp = session.compile(exp)
Simulation of Output Signals¶
Compiled experiments can also be simulated to determine the time trace
of all involved signals. The simulation of the output signals can be
triggered by using the compiled experiment with the
laboneq.simulator.output_simulator.OutputSimulator
class. The
output_simulator
example notebook shows how to simulate and plot the signals.
Compiler Options¶
Users can access advanced compiler options, which modify the compiler’s default behavior via a dictionary of compiler settings. All compiler settings have default values, which support a wide range of experiments. However, specific use cases, such as randomized benchmarking, benefit from optimized settings.
Available compiler settings and their default settings are:
Setting | Default value |
---|---|
HDAWG_MIN_PLAYWAVE_HINT |
128 |
HDAWG_MIN_PLAYZERO_HINT |
128 |
UHFQA_MIN_PLAYWAVE_HINT |
64 |
UHFQA_MIN_PLAYZERO_HINT |
64 |
SHFQA_MIN_PLAYWAVE_HINT |
64 |
SHFQA_MIN_PLAYZERO_HINT |
64 |
SHFSG_MIN_PLAYWAVE_HINT |
64 |
SHFSG_MIN_PLAYZERO_HINT |
64 |
PHASE_RESOLUTION_BITS |
16 |
HDAWG_FORCE_COMMAND_TABLE |
False |
SHFSG_FORCE_COMMAND_TABLE |
True |
To change the settings, the following syntax can be used:
compiler_settings = {
"SHFSG_MIN_PLAYWAVE_HINT": 128,
"SHFSG_MIN_PLAYZERO_HINT": 256
}
compiled_experiment = my_session.compile(
experiment,
compiler_settings=compiler_settings
)
Running Experiments¶
To run the experiment, the user has various options:
## Most general, compiles and runs
exp_results = session.run(exp)
## If the experiment has been compiled before
exp_results = session.run(compiled_exp)
## To run the last compiled experiment
exp_results = session.run()
Further information about results access and data handling is covered here.
Note
LabOne Q provides an estimate of the real-time execution time when the experiment is run. If the actual execution time exceeds the estimate by more than 10%, the real-time step is skipped.
Setting Arbitrary Instrument Node Values¶
LabOne Q allows the user to set instrument node values on Zurich Instruments devices in the near-time loops of experiments. This can be used to sweep particular nodes on QCCS instruments which would otherwise not be directly accessible in LabOne Q.
The syntax for sweeping an instrument node is similar to the callback function, with the node path and the value (which can also be a sweep parameter) as input arguments:
exp.set_node(path=f'/dev8000/sigouts/0/offset', value=sweep_parameter)
An example experiment is a resonator spectroscopy with different output power levels of the SHFQA. While the frequency sweep is done in a real-time acquisition loop, a near-time sweep is added where the output power node is stepped through the available ranges.
An alternative way is to use the Zurich Instruments Toolkit.