TWPA Tune-Up
TWPA Tune-up¶
This guide shows you how to use the experiment workflows in the Applications Library to perform setup and calibration of a Traveling Wave Parametric Amplifier (TWPA)
Getting Started¶
We will start by defining our experimental setup, connecting to the LabOne Q Session, and creating a FolderStore to save our data.
But first, we import numpy and laboneq.simple.
import numpy as np
from laboneq.simple import Session, workflow
Define your experimental setup¶
Let's define our experimental setup. We will need:
nTWPAa set of TWPAOperations
a QPU
Here, we will be brief. We will mainly provide the code to obtain these objects. To learn more, check out these other tutorials:
We will use 1 TWPA in this guide. Change this number to the one describing your setup.
number_of_twpas = 1
DeviceSetup¶
This guide requires a setup that can pump and readout TWPAs. Your setup could contain an SHFPPC, with an SHFQA+ or an SHFQC+ instruments. Here, we will use an SHFPPC with 4 channels to pump the TWPAs and an SHFQA+ with 4 channels to readout the TWPAs.
If you have used LabOne Q before and already had a DeviceSetup for your setup, you can reuse it.
If you do not have a DeviceSetup, you can create one using the code below. Just update the device numbers to the ones in your rack and adjust any other input parameters as needed.
Note: The user must pay special attention to ensure that the Marker A output of the SHFQA+ is properly connected to the corresponding trigger input of the SHFPPC output channel that will be used. Failure to do so may result in improper operation.
Note: The two instruments are synchronized by connecting the reference clock output of the SHFQA+ to the reference clock input of the SHFPPC, thereby locking them to the SHFQA+ reference clock.
from laboneq.dsl.device import DeviceSetup, create_connection
from laboneq.dsl.device.instruments import SHFPPC, SHFQA
twpa_ids = [f"twpa{i}" for i in range(number_of_twpas)]
setup = DeviceSetup(f"tunable_twpas_{number_of_twpas}")
setup.add_dataserver(host="localhost", port="8004")
setup.add_instruments(
SHFQA(uid="device_shfqa", address="dev123"),
)
setup.add_instruments(
SHFPPC(
uid="device_shfppc",
address="dev124",
)
)
for i, twpa in enumerate(twpa_ids):
setup.add_connections(
"device_shfqa",
# each TWPA uses its own measure and acquire lines:
create_connection(
to_signal=f"{twpa}/measure",
ports=f"QACHANNELS/{i}/OUTPUT",
),
create_connection(to_signal=f"{twpa}/acquire", ports=f"QACHANNELS/{i}/INPUT"),
)
setup.add_connections(
"device_shfppc",
# each TWPA uses its own measure and acquire lines:
create_connection(to_signal=f"{twpa}/acquire", ports=f"PPCHANNELS/{i}"),
)
TWPAs¶
We will generate 1 TWPA from the logical signal groups in our DeviceSetup. The names of the logical signal groups, twpa0 will be the UIDs of the twpa. Moreover, the twpa will have the same logical signal lines as the ones of the logical signal groups in the DeviceSetup.
from laboneq_applications.qpu_types.twpa.twpa_types import (
TWPA,
TWPAParameters,
)
twpas = []
for i in range(number_of_twpas):
t = TWPA.from_logical_signal_group(
f"twpa{i}", setup.logical_signal_groups[f"twpa{i}"], parameters=TWPAParameters()
)
twpas.append(t)
Configure the TWPA parameters by using the following code:
for t in twpas:
t.parameters.probe_frequency = 6.5e9
t.parameters.readout_lo_frequency = 6.4e9
t.parameters.readout_length = 1e-6
t.parameters.pump_frequency = 7.9e9
t.parameters.pump_power = 12.5
t.parameters.probe_power = 0
t.parameters.cancellation_phase = 0
t.parameters.cancellation_attenuation = 10
Quantum Operations¶
Define the set of TWPAOperations:
from laboneq_applications.qpu_types.twpa.operations import TWPAOperations
qops = TWPAOperations()
QPU¶
Create the QPU object from the qubits and the quantum operations
from laboneq.dsl.quantum import QPU
qpu = QPU(twpas, quantum_operations=qops)
Alternatively, load from a file¶
If you you already have a DeviceSetup and a QPU stored in .json files, you can simply load them back using the code below:
from laboneq import serializers
setup = serializers.load(full_path_to_device_setup_file)
qpu = serializers.load(full_path_to_qpu_file)
twpas = qpu.twpas
qops = qpu.quantum_operations
Connect to Session¶
session = Session(setup)
session.connect(do_emulation=True) # do_emulation=False when at a real setup
Create a FolderStore for saving data¶
The experiment Workflows can automatically save the inputs and outputs of all their tasks to the folder path we specify when instantiating the FolderStore. Here, we choose the current working directory.
# import FolderStore from the `workflow` namespace of LabOne Q, which was imported
# from `laboneq.simple`
from pathlib import Path
folder_store = workflow.logbook.FolderStore(Path.cwd())
We disable saving in this guide. To enable it, simply run folder_store.activate().
folder_store.deactivate()
Optional: Configure the LoggingStore¶
You can also activate/deactivate the LoggingStore, which is used for displaying the Workflow logging information in the notebook; see again the tutorial on Recording Experiment Workflow Results for details.
Displaying the Workflow logging information is activated by default, but here we deactivate it to shorten the outputs, which are not very meaningful in emulation mode.
We recommend that you do not deactivate the Workflow logging in practice.
from laboneq.workflow.logbook import LoggingStore
logging_store = LoggingStore()
logging_store.deactivate()
TWPA tune-up experiments¶
Let's now proceed to calibrate our twpa using the experiment workflows from the modules imported below:
from laboneq_applications.contrib.experiments import (
calibrate_cancellation,
measure_gain_curve,
scan_pump_parameters,
)
To learn more about what each of these experiments does, check out our experiment how-to guides.
To learn more about experiment Workflows in general and what you can do with them, check out this tutorial.
To learn how to write your own experiment Workflow, check out this tutorial.
To learn more about Workflows, Task and options, look here.
Note: all the analysis results including the plots will be saved into the folder you have passed to the FolderStore (if the FolderStore is activated). You can also configure each experiment Workflow to display the plots in this notebook by setting options.close_figures(False). We do not do this here because the data and the plots are meaningless in emulation mode.
Note: we will run all the experiments in this notebook with the setting options.update(True). This means that the relevant qubit parameters will be updated to the values extracted from the analysis (for example, the pump_frequency parameter in an amplitude Scan pump parameters experiment). If you're not happy with the new values or you've updated by mistake, you can revert to the original values from before the start of the experiment using the code,
experiment_module.update_parametric_amplifiers(qpu, workflow_result.tasks["analysis_workflow"].output["old_parameter_values"])
where experiment_module is one of the experiment modules imported above.
Similarly, in case you've run your experiment with the update option set to False but would still like to update your values, use the code,
experiment_module.update_parametric_amplifiers(qpu, workflow_result.tasks["analysis_workflow"].output["new_parameter_values"])
Scan pump parameters experiment¶
Run characterization measurement of the TWPAs by sweeping the pump power and frequency
Note: To conduct Signal-to-Noise Ratio (SNR) gain measurements, this is achieved by setting options.do_SNR(True).
Note: The probe signal can be generated from either the Quantum Analyzer's output channel or the SHFPPC's output channel. For the latter, this is enabled with the setting. options.use_probe_from_ppc(True)
options = scan_pump_parameters.experiment_workflow.options()
options.close_figures(False)
options.do_snr(True)
options.use_probe_from_ppc(False)
options.update(True)
twpa_to_measure = twpas
temporary_parameters = {twpa_to_measure[0].uid: {"readout_range_out": -30}}
frequencies = np.linspace(6e9, 7e9, 11)
powers = np.linspace(8, 16, 3)
exp_workflow = scan_pump_parameters.experiment_workflow(
session=session,
qpu=qpu,
parametric_amplifier=twpa_to_measure[0],
temporary_parameters=temporary_parameters,
pump_frequency=frequencies,
pump_power=powers,
options=options,
)
workflow_results = exp_workflow.run()
Check the updated value of the twpa parameter:
[(t.parameters.pump_frequency, t.parameters.pump_power) for t in twpa_to_measure]
Measure gain curve¶
Measure the gain of the TWPAs while sweeping across different probe frequencies.
options = measure_gain_curve.experiment_workflow.options()
options.close_figures(False, "analysis_workflow.plot_1D")
options.use_probe_from_ppc(False)
options.update(False)
twpa_to_measure = twpas
frequencies = [6e9, 6.7e9]
exp_workflow = measure_gain_curve.experiment_workflow(
session=session,
qpu=qpu,
parametric_amplifier=twpa_to_measure[0],
probe_frequency=frequencies,
pump_power=[twpa_to_measure[0].parameters.pump_power],
selected_indexes=[0],
options=options,
)
workflow_results = exp_workflow.run()
Calibrate cancellation experiment¶
Sweep the phase and attunation of the cancellation circuit while measuring the residual pump tone signal.
Note: It is important to consider the readout local oscillator frequency twpas[0].parameters.readout_lo_frequency, which should be set appropriately in relation to the pump frequency.
options = calibrate_cancellation.experiment_workflow.options()
options.close_figures(False)
options.update(True)
twpa_to_measure = twpas
cancel_phase = np.linspace(1.5 * np.pi, 2 * np.pi, 11)
cancel_attenuation = np.linspace(10, 20, 11)
exp_workflow = calibrate_cancellation.experiment_workflow(
session=session,
qpu=qpu,
parametric_amplifier=twpa_to_measure[0],
cancel_phase=cancel_phase,
cancel_attenuation=cancel_attenuation,
options=options,
)
workflow_results = exp_workflow.run()
Check the updated value of the twpa parameter:
[
(t.parameters.cancellation_phase, t.parameters.cancellation_attenuation)
for t in twpas
]