e-f transition spectroscopy¶
In this reference notebook, you'll learn how to use LabOne Q's logical signals lines to perform spectroscopy of higher qubit levels. This functionality requires an SHFSG or SHFQC and relies on using the command table instead of playWave commands.
0. General Imports and Definitions¶
0.1 Python Imports¶
In [ ]:
Copied!
# Helpers:
from laboneq.contrib.example_helpers.generate_device_setup import (
generate_device_setup_qubits,
)
from laboneq.contrib.example_helpers.plotting.plot_helpers import plot_simulation
# LabOne Q:
from laboneq.simple import *
# Helpers:
from laboneq.contrib.example_helpers.generate_device_setup import (
generate_device_setup_qubits,
)
from laboneq.contrib.example_helpers.plotting.plot_helpers import plot_simulation
# LabOne Q:
from laboneq.simple import *
1. Define Device Setup and Calibration¶
1.1 Define a Device Setup¶
We'll generate a device setup and some qubit objects using a set of pre-defined parameters in a helper function.
In [ ]:
Copied!
# specify the number of qubits you want to use
number_of_qubits = 2
# generate the device setup and the qubit objects using a helper function
device_setup, qubits = generate_device_setup_qubits(
number_qubits=number_of_qubits,
pqsc=[{"serial": "DEV10001"}],
hdawg=[
{
"serial": "DEV8001",
"number_of_channels": 8,
"options": None,
}
],
shfqc=[
{
"serial": "DEV12001",
"number_of_channels": 6,
"readout_multiplex": 6,
"options": None,
}
],
multiplex_drive_lines=True,
include_flux_lines=True,
server_host="localhost",
setup_name=f"my_{number_of_qubits}_tunable_qubit_setup",
)
q0, q1 = qubits[:2]
# specify the number of qubits you want to use
number_of_qubits = 2
# generate the device setup and the qubit objects using a helper function
device_setup, qubits = generate_device_setup_qubits(
number_qubits=number_of_qubits,
pqsc=[{"serial": "DEV10001"}],
hdawg=[
{
"serial": "DEV8001",
"number_of_channels": 8,
"options": None,
}
],
shfqc=[
{
"serial": "DEV12001",
"number_of_channels": 6,
"readout_multiplex": 6,
"options": None,
}
],
multiplex_drive_lines=True,
include_flux_lines=True,
server_host="localhost",
setup_name=f"my_{number_of_qubits}_tunable_qubit_setup",
)
q0, q1 = qubits[:2]
In [ ]:
Copied!
# use emulation mode - no connection to instruments
use_emulation = True
# create and connect to a session
session = Session(device_setup=device_setup)
session.connect(do_emulation=use_emulation)
# use emulation mode - no connection to instruments
use_emulation = True
# create and connect to a session
session = Session(device_setup=device_setup)
session.connect(do_emulation=use_emulation)
2. e-f Transition Spectroscopy¶
Sweep the pulse frequency of a qubit drive pulse to determine the frequency of the e-f transition. This assumes that a pi-pulse for the first excited state is already calibrated.
2.1 Define the Experiment¶
In [ ]:
Copied!
## define pulses
# qubit pi-pulse for first excited state
x180 = pulse_library.drag(uid="x180", length=24e-9, amplitude=0.5, sigma=0.3, beta=0.2)
# long spectroscopy pulse for e-f transition - frequency will be swept
ef_spec_pulse = pulse_library.const(uid="ef_pulse", length=10e-6, amplitude=1.0)
# readout drive pulse
readout_pulse = pulse_library.const(uid="readout_pulse", length=400e-9, amplitude=0.2)
# readout integration weights
readout_weighting_function = pulse_library.const(
uid="readout_weighting_function", length=400e-9, amplitude=0.8
)
## define pulses
# qubit pi-pulse for first excited state
x180 = pulse_library.drag(uid="x180", length=24e-9, amplitude=0.5, sigma=0.3, beta=0.2)
# long spectroscopy pulse for e-f transition - frequency will be swept
ef_spec_pulse = pulse_library.const(uid="ef_pulse", length=10e-6, amplitude=1.0)
# readout drive pulse
readout_pulse = pulse_library.const(uid="readout_pulse", length=400e-9, amplitude=0.2)
# readout integration weights
readout_weighting_function = pulse_library.const(
uid="readout_weighting_function", length=400e-9, amplitude=0.8
)
In [ ]:
Copied!
# set up sweep parameter - drive amplitude
start = 25e6
stop = 250e6
count = 25
frequency_sweep = LinearSweepParameter(
uid="frequency", start=start, stop=stop, count=count
)
# number of averages
average_exponent = 10 # used for 2^n averages, n=average_exponent, maximum: n = 17
# Create Experiment
exp_ef_spec = Experiment(
uid="e-f spectroscopy",
signals=[
ExperimentSignal("drive"),
ExperimentSignal("drive_ef"),
ExperimentSignal("measure"),
ExperimentSignal("acquire"),
],
)
## experimental pulse sequence
# outer loop - real-time, cyclic averaging in standard integration mode
with exp_ef_spec.acquire_loop_rt(
uid="shots",
count=pow(2, average_exponent),
averaging_mode=AveragingMode.CYCLIC,
acquisition_type=AcquisitionType.INTEGRATION,
):
# inner loop - real-time frequency sweep of qubit e-f drive pulse
with exp_ef_spec.sweep(uid="sweep", parameter=frequency_sweep):
# qubit excitation - pulse amplitude will be swept
with exp_ef_spec.section(
uid="qubit_excitation",
on_system_grid=True,
alignment=SectionAlignment.RIGHT,
):
exp_ef_spec.play(signal="drive", pulse=x180)
with exp_ef_spec.section(
uid="qubit_ef_excitation",
play_after="qubit_excitation",
on_system_grid=True,
alignment=SectionAlignment.RIGHT,
):
exp_ef_spec.play(signal="drive_ef", pulse=ef_spec_pulse)
# qubit readout pulse and data acquisition
with exp_ef_spec.section(uid="qubit_readout", play_after="qubit_ef_excitation"):
# play readout pulse
exp_ef_spec.play(signal="measure", pulse=readout_pulse)
# signal data acquisition
exp_ef_spec.acquire(
signal="acquire",
handle="ac_0",
kernel=readout_weighting_function,
)
# relax time after readout - for signal processing and qubit relaxation to groundstate
with exp_ef_spec.section(uid="relax", length=100e-9):
exp_ef_spec.reserve(signal="measure")
# set up sweep parameter - drive amplitude
start = 25e6
stop = 250e6
count = 25
frequency_sweep = LinearSweepParameter(
uid="frequency", start=start, stop=stop, count=count
)
# number of averages
average_exponent = 10 # used for 2^n averages, n=average_exponent, maximum: n = 17
# Create Experiment
exp_ef_spec = Experiment(
uid="e-f spectroscopy",
signals=[
ExperimentSignal("drive"),
ExperimentSignal("drive_ef"),
ExperimentSignal("measure"),
ExperimentSignal("acquire"),
],
)
## experimental pulse sequence
# outer loop - real-time, cyclic averaging in standard integration mode
with exp_ef_spec.acquire_loop_rt(
uid="shots",
count=pow(2, average_exponent),
averaging_mode=AveragingMode.CYCLIC,
acquisition_type=AcquisitionType.INTEGRATION,
):
# inner loop - real-time frequency sweep of qubit e-f drive pulse
with exp_ef_spec.sweep(uid="sweep", parameter=frequency_sweep):
# qubit excitation - pulse amplitude will be swept
with exp_ef_spec.section(
uid="qubit_excitation",
on_system_grid=True,
alignment=SectionAlignment.RIGHT,
):
exp_ef_spec.play(signal="drive", pulse=x180)
with exp_ef_spec.section(
uid="qubit_ef_excitation",
play_after="qubit_excitation",
on_system_grid=True,
alignment=SectionAlignment.RIGHT,
):
exp_ef_spec.play(signal="drive_ef", pulse=ef_spec_pulse)
# qubit readout pulse and data acquisition
with exp_ef_spec.section(uid="qubit_readout", play_after="qubit_ef_excitation"):
# play readout pulse
exp_ef_spec.play(signal="measure", pulse=readout_pulse)
# signal data acquisition
exp_ef_spec.acquire(
signal="acquire",
handle="ac_0",
kernel=readout_weighting_function,
)
# relax time after readout - for signal processing and qubit relaxation to groundstate
with exp_ef_spec.section(uid="relax", length=100e-9):
exp_ef_spec.reserve(signal="measure")
In [ ]:
Copied!
# define signal maps for qubit 0
map_q0 = {
"drive": q0.signals["drive"],
"drive_ef": q0.signals["drive_ef"],
"measure": q0.signals["measure"],
"acquire": q0.signals["acquire"],
}
# ... - and qubit 1
map_q1 = {
"drive": q1.signals["drive"],
"drive_ef": q1.signals["drive_ef"],
"measure": q1.signals["measure"],
"acquire": q1.signals["acquire"],
}
# define signal maps for qubit 0
map_q0 = {
"drive": q0.signals["drive"],
"drive_ef": q0.signals["drive_ef"],
"measure": q0.signals["measure"],
"acquire": q0.signals["acquire"],
}
# ... - and qubit 1
map_q1 = {
"drive": q1.signals["drive"],
"drive_ef": q1.signals["drive_ef"],
"measure": q1.signals["measure"],
"acquire": q1.signals["acquire"],
}
In [ ]:
Copied!
# define experiment calibration
exp_calibration = Calibration(
{
"drive_ef": SignalCalibration(
oscillator=Oscillator(
# WORKAROUND: when sweeping an oscillator on a logical line using the oscillator switching feature, need to ensure that the uid of the swept oscillator is sorted() first
uid="ef_drive_osc",
frequency=frequency_sweep,
modulation_type=ModulationType.HARDWARE,
)
)
}
)
# define experiment calibration
exp_calibration = Calibration(
{
"drive_ef": SignalCalibration(
oscillator=Oscillator(
# WORKAROUND: when sweeping an oscillator on a logical line using the oscillator switching feature, need to ensure that the uid of the swept oscillator is sorted() first
uid="ef_drive_osc",
frequency=frequency_sweep,
modulation_type=ModulationType.HARDWARE,
)
)
}
)
2.2 Run the Experiment and Plot the Measurement Results and Pulse Sequence¶
In [ ]:
Copied!
# set signal map to qubit 0
exp_ef_spec.set_signal_map(map_q0)
exp_ef_spec.set_calibration(exp_calibration)
# run experiment on qubit 0
compiled_exp_ef_spec = session.compile(exp_ef_spec)
ef_espec_results = session.run(compiled_exp_ef_spec)
# set signal map to qubit 0
exp_ef_spec.set_signal_map(map_q0)
exp_ef_spec.set_calibration(exp_calibration)
# run experiment on qubit 0
compiled_exp_ef_spec = session.compile(exp_ef_spec)
ef_espec_results = session.run(compiled_exp_ef_spec)
In [ ]:
Copied!
# show_pulse_sheet("ef_spectroscopy", compiled_exp_ef_spec)
# show_pulse_sheet("ef_spectroscopy", compiled_exp_ef_spec)
In [ ]:
Copied!
# Plot simulated output signals
plot_simulation(compiled_exp_ef_spec, start_time=0, length=0.25e-6)
# Plot simulated output signals
plot_simulation(compiled_exp_ef_spec, start_time=0, length=0.25e-6)
In [ ]:
Copied!