Frequency Sweep Examples in LabOne Q¶
This notebook demonstrates various types of frequency sweeps in LabOne Q, including linear and non-linear sweeps.
In [ ]:
Copied!
import matplotlib.pyplot as plt
import numpy as np
from laboneq.contrib.example_helpers.generate_device_setup import (
generate_device_setup_qubits,
)
from laboneq.contrib.example_helpers.plotting.plot_helpers import plot_simulation
from laboneq.core.types.enums import ModulationType
from laboneq.dsl.calibration import Oscillator, SignalCalibration
from laboneq.dsl.experiment import pulse_library
from laboneq.simple import *
import matplotlib.pyplot as plt
import numpy as np
from laboneq.contrib.example_helpers.generate_device_setup import (
generate_device_setup_qubits,
)
from laboneq.contrib.example_helpers.plotting.plot_helpers import plot_simulation
from laboneq.core.types.enums import ModulationType
from laboneq.dsl.calibration import Oscillator, SignalCalibration
from laboneq.dsl.experiment import pulse_library
from laboneq.simple import *
In [ ]:
Copied!
device_setup, qubits = generate_device_setup_qubits(
number_qubits=1,
shfqc=[
{
"serial": "DEV12001",
"number_of_channels": 6,
"readout_multiplex": 6,
"options": None,
}
],
include_flux_lines=False,
server_host="localhost",
setup_name="one_qubit_setup",
)
def compile_and_simulate_experiment(freq_sweep):
logical_signals = [
ls
for lsg in device_setup.logical_signal_groups.values()
for ls in lsg.logical_signals.values()
]
exp = Experiment(
signals=[ExperimentSignal(sig.uid.replace("/", "_")) for sig in logical_signals]
)
for ls, es in zip(logical_signals, exp.signals):
exp.map_signal(es, ls)
pulse = pulse_library.const(uid="pulse", length=100e-9) # 100 ns per pulse
# Calibrate drive line with swept software oscillator
exp.signals["q0_drive"].calibration = SignalCalibration(
oscillator=Oscillator(
uid="osc_f1", frequency=freq_sweep, modulation_type=ModulationType.SOFTWARE
)
)
# Sequence: single pulse for each sweep step
with exp.acquire_loop_rt(1):
with exp.sweep(uid="sweep", parameter=freq_sweep):
with exp.section():
exp.play("q0_drive", pulse)
# Compile and simulate
session = Session(device_setup)
session.connect(do_emulation=True)
compiled = session.compile(exp, compiler_settings={"OUTPUT_EXTRAS": True})
plot_simulation(
compiled,
start_time=0,
length=len(freq_sweep.values) * pulse.length,
signals=["q0_drive"],
)
device_setup, qubits = generate_device_setup_qubits(
number_qubits=1,
shfqc=[
{
"serial": "DEV12001",
"number_of_channels": 6,
"readout_multiplex": 6,
"options": None,
}
],
include_flux_lines=False,
server_host="localhost",
setup_name="one_qubit_setup",
)
def compile_and_simulate_experiment(freq_sweep):
logical_signals = [
ls
for lsg in device_setup.logical_signal_groups.values()
for ls in lsg.logical_signals.values()
]
exp = Experiment(
signals=[ExperimentSignal(sig.uid.replace("/", "_")) for sig in logical_signals]
)
for ls, es in zip(logical_signals, exp.signals):
exp.map_signal(es, ls)
pulse = pulse_library.const(uid="pulse", length=100e-9) # 100 ns per pulse
# Calibrate drive line with swept software oscillator
exp.signals["q0_drive"].calibration = SignalCalibration(
oscillator=Oscillator(
uid="osc_f1", frequency=freq_sweep, modulation_type=ModulationType.SOFTWARE
)
)
# Sequence: single pulse for each sweep step
with exp.acquire_loop_rt(1):
with exp.sweep(uid="sweep", parameter=freq_sweep):
with exp.section():
exp.play("q0_drive", pulse)
# Compile and simulate
session = Session(device_setup)
session.connect(do_emulation=True)
compiled = session.compile(exp, compiler_settings={"OUTPUT_EXTRAS": True})
plot_simulation(
compiled,
start_time=0,
length=len(freq_sweep.values) * pulse.length,
signals=["q0_drive"],
)
In [ ]:
Copied!
# Linear frequency sweep parameters
freq_sweep_linear = LinearSweepParameter(
uid="linear_frequency",
start=50e6, # -50 MHz relative to LO (6.95 GHz)
stop=100e6, # +50 MHz relative to LO (7.05 GHz)
count=5, # 101 frequency points (1 MHz steps)
)
compile_and_simulate_experiment(freq_sweep_linear)
# Linear frequency sweep parameters
freq_sweep_linear = LinearSweepParameter(
uid="linear_frequency",
start=50e6, # -50 MHz relative to LO (6.95 GHz)
stop=100e6, # +50 MHz relative to LO (7.05 GHz)
count=5, # 101 frequency points (1 MHz steps)
)
compile_and_simulate_experiment(freq_sweep_linear)
Example 2: Non-linear Frequency Sweep — Logarithmic¶
In [ ]:
Copied!
# Create logarithmic frequency sweep
log_frequencies = np.logspace(np.log10(50e6), np.log10(500e6), 11)
freq_sweep_log = SweepParameter(uid="log_frequency", values=log_frequencies)
compile_and_simulate_experiment(freq_sweep_log)
# Create logarithmic frequency sweep
log_frequencies = np.logspace(np.log10(50e6), np.log10(500e6), 11)
freq_sweep_log = SweepParameter(uid="log_frequency", values=log_frequencies)
compile_and_simulate_experiment(freq_sweep_log)
Example 3: Custom Non-Linear Sweep with Dense Sampling¶
This example shows how to create custom frequency patterns with higher resolution around features of interest.
In [ ]:
Copied!
# Create custom frequency pattern with dense sampling around center frequency
center_freq = 300e6 # 300 MHz
frequencies = np.concatenate(
[
np.linspace(100e6, center_freq - 10e6, 3), # 100, 200, 290 MHz
np.linspace(
center_freq - 10e6, center_freq + 10e6, 5
), # 290, 295, 300, 305, 310 MHz
np.linspace(center_freq + 10e6, 500e6, 3), # 310, 405, 500 MHz
]
)
freq_sweep_dense = SweepParameter(uid="dense_frequency", values=frequencies)
compile_and_simulate_experiment(freq_sweep_dense)
# Summary plots for the frequency list
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.plot(np.arange(len(frequencies)), frequencies / 1e9, ".-", markersize=4)
plt.xlabel("Step")
plt.ylabel("Frequency (GHz)")
plt.title("Frequency Points")
plt.grid(True)
plt.subplot(1, 3, 2)
freq_diffs = np.diff(frequencies) / 1e6
plt.plot(np.arange(len(freq_diffs)), freq_diffs, ".-", markersize=4)
plt.xlabel("Step")
plt.ylabel("Step Size (MHz)")
plt.title("Frequency Step Sizes")
plt.grid(True)
plt.subplot(1, 3, 3)
plt.hist(frequencies / 1e9, bins=min(20, max(5, len(frequencies) // 3)))
plt.xlabel("Frequency (GHz)")
plt.ylabel("Count")
plt.title("Frequency Distribution")
plt.tight_layout()
plt.show()
# Create custom frequency pattern with dense sampling around center frequency
center_freq = 300e6 # 300 MHz
frequencies = np.concatenate(
[
np.linspace(100e6, center_freq - 10e6, 3), # 100, 200, 290 MHz
np.linspace(
center_freq - 10e6, center_freq + 10e6, 5
), # 290, 295, 300, 305, 310 MHz
np.linspace(center_freq + 10e6, 500e6, 3), # 310, 405, 500 MHz
]
)
freq_sweep_dense = SweepParameter(uid="dense_frequency", values=frequencies)
compile_and_simulate_experiment(freq_sweep_dense)
# Summary plots for the frequency list
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.plot(np.arange(len(frequencies)), frequencies / 1e9, ".-", markersize=4)
plt.xlabel("Step")
plt.ylabel("Frequency (GHz)")
plt.title("Frequency Points")
plt.grid(True)
plt.subplot(1, 3, 2)
freq_diffs = np.diff(frequencies) / 1e6
plt.plot(np.arange(len(freq_diffs)), freq_diffs, ".-", markersize=4)
plt.xlabel("Step")
plt.ylabel("Step Size (MHz)")
plt.title("Frequency Step Sizes")
plt.grid(True)
plt.subplot(1, 3, 3)
plt.hist(frequencies / 1e9, bins=min(20, max(5, len(frequencies) // 3)))
plt.xlabel("Frequency (GHz)")
plt.ylabel("Count")
plt.title("Frequency Distribution")
plt.tight_layout()
plt.show()
Example 4: Arbitrary Frequency Sequence¶
Sometimes you need completely arbitrary frequency patterns, for example following theoretical predictions or measurement-driven sequences.
In [ ]:
Copied!
# Create arbitrary frequency sequence (could come from theory, previous measurements, etc.)
arbitrary_freqs = np.array(
[272e6, 285e6, 279e6, 291e6, 300e6, 276e6, 288e6, 295e6, 282e6, 274e6, 297e6]
)
freq_sweep_arbitrary = SweepParameter(uid="arbitrary_sequence", values=arbitrary_freqs)
compile_and_simulate_experiment(freq_sweep_arbitrary)
# Show the arbitrary sequence pattern
plt.figure(figsize=(10, 6))
plt.subplot(2, 1, 1)
plt.plot(arbitrary_freqs / 1e9, "o-", markersize=8, linewidth=2)
plt.xlabel("Sequence Step")
plt.ylabel("Frequency (GHz)")
plt.title("Arbitrary Frequency Sequence")
plt.grid(True)
plt.subplot(2, 1, 2)
# Show the order in frequency space
sorted_indices = np.argsort(arbitrary_freqs)
plt.plot(arbitrary_freqs / 1e9, np.arange(len(arbitrary_freqs)), "o", markersize=8)
for _i, (freq, step) in enumerate(
zip(arbitrary_freqs / 1e9, range(len(arbitrary_freqs)))
):
plt.annotate(f"{step}", (freq, step), xytext=(5, 0), textcoords="offset points")
plt.xlabel("Frequency (GHz)")
plt.ylabel("Sequence Step")
plt.title("Sequence Order vs Frequency")
plt.grid(True)
plt.tight_layout()
plt.show()
# Create arbitrary frequency sequence (could come from theory, previous measurements, etc.)
arbitrary_freqs = np.array(
[272e6, 285e6, 279e6, 291e6, 300e6, 276e6, 288e6, 295e6, 282e6, 274e6, 297e6]
)
freq_sweep_arbitrary = SweepParameter(uid="arbitrary_sequence", values=arbitrary_freqs)
compile_and_simulate_experiment(freq_sweep_arbitrary)
# Show the arbitrary sequence pattern
plt.figure(figsize=(10, 6))
plt.subplot(2, 1, 1)
plt.plot(arbitrary_freqs / 1e9, "o-", markersize=8, linewidth=2)
plt.xlabel("Sequence Step")
plt.ylabel("Frequency (GHz)")
plt.title("Arbitrary Frequency Sequence")
plt.grid(True)
plt.subplot(2, 1, 2)
# Show the order in frequency space
sorted_indices = np.argsort(arbitrary_freqs)
plt.plot(arbitrary_freqs / 1e9, np.arange(len(arbitrary_freqs)), "o", markersize=8)
for _i, (freq, step) in enumerate(
zip(arbitrary_freqs / 1e9, range(len(arbitrary_freqs)))
):
plt.annotate(f"{step}", (freq, step), xytext=(5, 0), textcoords="offset points")
plt.xlabel("Frequency (GHz)")
plt.ylabel("Sequence Step")
plt.title("Sequence Order vs Frequency")
plt.grid(True)
plt.tight_layout()
plt.show()