CW Acquisition with HDAWG and MFLI¶
In this notebook, you'll perform a CW experiment using a HDAWG and an MFLI. On the HDAWG, you'll play a Ramsey sequence in sequential mode, where each iteration of the sweep will play for a certain time (the integration time). You'll send the trigger from the HDAWG to the MFLI DAQ module to trigger the data acquisition.
0. General Imports¶
In [ ]:
Copied!
%config IPCompleter.greedy=True
import matplotlib.pyplot as plt
import numpy as np
import time
from laboneq.simple import *
%config IPCompleter.greedy=True
import matplotlib.pyplot as plt
import numpy as np
import time
from laboneq.simple import *
1. Device Setup¶
1.1 Calibration¶
In [ ]:
Copied!
def calibrate_devices(device_setup):
device_setup.logical_signal_groups["q0"].logical_signals[
"drive_line"
].calibration = SignalCalibration(
oscillator=Oscillator(
uid="drive_q0_osc", frequency=1e6, modulation_type=ModulationType.HARDWARE
)
)
def calibrate_devices(device_setup):
device_setup.logical_signal_groups["q0"].logical_signals[
"drive_line"
].calibration = SignalCalibration(
oscillator=Oscillator(
uid="drive_q0_osc", frequency=1e6, modulation_type=ModulationType.HARDWARE
)
)
1.2 Create device setup¶
In [ ]:
Copied!
descriptor = f"""\
instruments:
MFLI:
- address: DEV5534
uid: device_mfli
HDAWG:
- address: DEV8434
uid: device_hdawg
interface: usb
connections:
device_hdawg:
- iq_signal: q0/drive_line
ports: [SIGOUTS/4, SIGOUTS/5]
- rf_signal: q0/coulomb_line_1
ports: [SIGOUTS/0]
- rf_signal: q0/coulomb_line_2
ports: [SIGOUTS/1]
# - external_clock_signal
"""
device_setup = DeviceSetup.from_descriptor(
descriptor,
server_host="your_ip_address",
server_port=8004,
setup_name="MySetup",
)
calibrate_devices(device_setup)
descriptor = f"""\
instruments:
MFLI:
- address: DEV5534
uid: device_mfli
HDAWG:
- address: DEV8434
uid: device_hdawg
interface: usb
connections:
device_hdawg:
- iq_signal: q0/drive_line
ports: [SIGOUTS/4, SIGOUTS/5]
- rf_signal: q0/coulomb_line_1
ports: [SIGOUTS/0]
- rf_signal: q0/coulomb_line_2
ports: [SIGOUTS/1]
# - external_clock_signal
"""
device_setup = DeviceSetup.from_descriptor(
descriptor,
server_host="your_ip_address",
server_port=8004,
setup_name="MySetup",
)
calibrate_devices(device_setup)
2. Connect session¶
In [ ]:
Copied!
# create and connect to session
session = Session(device_setup=device_setup)
session.connect(do_emulation=True)
# create and connect to session
session = Session(device_setup=device_setup)
session.connect(do_emulation=True)
3. MFLI example¶
3.1 Connect to instrument in session¶
In [ ]:
Copied!
mfli = session.devices["device_mfli"]
mfli = session.devices["device_mfli"]
3.2 Experiment (Ramsey with marker sent to MFLI)¶
In [ ]:
Copied!
## constant definition
LEN_COULOMB_CYCLE = 400e-9
TAU_X90_TIME = 75e-9 # [s]
INT_TIME = 30e-3
# define three stages of gate pulses
coulomb_pulse = pulse_library.const(
uid="coulomb_manipulate", length=LEN_COULOMB_CYCLE / 2, amplitude=0.5
)
# define drive pulse
drive_pulse = pulse_library.const(uid="pihalf", length=TAU_X90_TIME, amplitude=1)
START = 0
STOP = 50e-9
STEPS = 10
NUM_REP = INT_TIME / LEN_COULOMB_CYCLE
sweep_delay = LinearSweepParameter(
uid="Ramsey_delay", start=START, stop=STOP, count=STEPS
)
readout_parameter = LinearSweepParameter(uid="readoutparam", start=0, stop=1, count=1)
## Create Experiment
exp = Experiment(
"MFLI experiment",
signals=[
ExperimentSignal("drive"),
ExperimentSignal("coulomb_1"),
ExperimentSignal("coulomb_2"),
],
)
# define experiment
with exp.acquire_loop_rt(
uid="shots", count=NUM_REP, averaging_mode=AveragingMode.SEQUENTIAL
):
with exp.section(
uid="triggersection",
trigger={"drive": {"state": 3}},
):
with exp.sweep(
uid="sweep", parameter=[sweep_delay], reset_oscillator_phase=True
):
with exp.section(
uid=("empty"),
length=LEN_COULOMB_CYCLE / 2,
alignment=SectionAlignment.RIGHT,
):
exp.play(signal="coulomb_1", pulse=coulomb_pulse, amplitude=0.5)
exp.play(signal="coulomb_2", pulse=coulomb_pulse, amplitude=0.5)
with exp.section(
uid=("manipulation"),
length=LEN_COULOMB_CYCLE / 2,
alignment=SectionAlignment.RIGHT,
):
exp.play(signal="coulomb_1", pulse=coulomb_pulse, amplitude=0.75)
exp.play(signal="coulomb_2", pulse=coulomb_pulse, amplitude=0.75)
exp.play(signal="drive", pulse=drive_pulse)
exp.delay(signal="drive", time=sweep_delay)
exp.play(signal="drive", pulse=drive_pulse)
with exp.section(uid="relax", play_after="triggersection"):
exp.delay(signal="drive", time=100e-6)
## constant definition
LEN_COULOMB_CYCLE = 400e-9
TAU_X90_TIME = 75e-9 # [s]
INT_TIME = 30e-3
# define three stages of gate pulses
coulomb_pulse = pulse_library.const(
uid="coulomb_manipulate", length=LEN_COULOMB_CYCLE / 2, amplitude=0.5
)
# define drive pulse
drive_pulse = pulse_library.const(uid="pihalf", length=TAU_X90_TIME, amplitude=1)
START = 0
STOP = 50e-9
STEPS = 10
NUM_REP = INT_TIME / LEN_COULOMB_CYCLE
sweep_delay = LinearSweepParameter(
uid="Ramsey_delay", start=START, stop=STOP, count=STEPS
)
readout_parameter = LinearSweepParameter(uid="readoutparam", start=0, stop=1, count=1)
## Create Experiment
exp = Experiment(
"MFLI experiment",
signals=[
ExperimentSignal("drive"),
ExperimentSignal("coulomb_1"),
ExperimentSignal("coulomb_2"),
],
)
# define experiment
with exp.acquire_loop_rt(
uid="shots", count=NUM_REP, averaging_mode=AveragingMode.SEQUENTIAL
):
with exp.section(
uid="triggersection",
trigger={"drive": {"state": 3}},
):
with exp.sweep(
uid="sweep", parameter=[sweep_delay], reset_oscillator_phase=True
):
with exp.section(
uid=("empty"),
length=LEN_COULOMB_CYCLE / 2,
alignment=SectionAlignment.RIGHT,
):
exp.play(signal="coulomb_1", pulse=coulomb_pulse, amplitude=0.5)
exp.play(signal="coulomb_2", pulse=coulomb_pulse, amplitude=0.5)
with exp.section(
uid=("manipulation"),
length=LEN_COULOMB_CYCLE / 2,
alignment=SectionAlignment.RIGHT,
):
exp.play(signal="coulomb_1", pulse=coulomb_pulse, amplitude=0.75)
exp.play(signal="coulomb_2", pulse=coulomb_pulse, amplitude=0.75)
exp.play(signal="drive", pulse=drive_pulse)
exp.delay(signal="drive", time=sweep_delay)
exp.play(signal="drive", pulse=drive_pulse)
with exp.section(uid="relax", play_after="triggersection"):
exp.delay(signal="drive", time=100e-6)
3.3 Configure MFLI and DAQ module¶
In [ ]:
Copied!
# configure MFLI
demod = mfli.demods[0] # which demodulator to use (depends on MF option)
with mfli.set_transaction():
mfli.demods["*"].enable(False)
mfli.oscs[0].freq(1e6)
mfli.sigouts[0].enable(True)
demod.order(3)
demod.rate(10e3)
demod.trigger("continuous")
demod.timeconstant(10e-6)
demod.enable(True)
# Parameters
DEMOD_RATE_MFLI = demod.rate() # read the value from the instrument
NUM_COLS = int(
np.ceil(DEMOD_RATE_MFLI * INT_TIME)
) # Number of samples per burst. Corresponds to length of time trace in units of sampling rate.
# Nodes to read
sample_nodes = [demod.sample.x.avg, demod.sample.y.avg]
# Module creation
daq_module = mfli._session.modules.daq
daq_module.device(mfli)
daq_module.type("hardware_trigger")
daq_module.endless(False)
# Shape of my grid
daq_module.grid.mode(
4
) # Specify how the acquired data is sampled onto the matrix’s horizontal axis
daq_module.count(1)
daq_module.grid.cols(NUM_COLS)
daq_module.grid.rows(STEPS)
daq_module.grid.repetitions(1)
daq_module.grid.rowrepetition(
False
) # True: First average each row, then fill the next row -> sequential averaging
# False: First fill each row, then average the rows -> cyclic averaging
# Acquisition using Digital Triggering
node_trigger = demod.sample.TrigIn1
daq_module.triggernode(node_trigger)
daq_module.edge("rising")
daq_module.delay(0)
daq_module.holdoff.time(0)
daq_module.holdoff.count(0)
daq_module.clearhistory(1)
# print(f"Columns: {daq_module.grid.cols()}")
# print(f"Rows: {daq_module.grid.rows()}")
# print(f"Repetitions: {daq_module.grid.repetitions()}")
# print(f"Holdoff: {daq_module.holdoff.time()}")
# print(f"Delay: {daq_module.delay()}")
# configure MFLI
demod = mfli.demods[0] # which demodulator to use (depends on MF option)
with mfli.set_transaction():
mfli.demods["*"].enable(False)
mfli.oscs[0].freq(1e6)
mfli.sigouts[0].enable(True)
demod.order(3)
demod.rate(10e3)
demod.trigger("continuous")
demod.timeconstant(10e-6)
demod.enable(True)
# Parameters
DEMOD_RATE_MFLI = demod.rate() # read the value from the instrument
NUM_COLS = int(
np.ceil(DEMOD_RATE_MFLI * INT_TIME)
) # Number of samples per burst. Corresponds to length of time trace in units of sampling rate.
# Nodes to read
sample_nodes = [demod.sample.x.avg, demod.sample.y.avg]
# Module creation
daq_module = mfli._session.modules.daq
daq_module.device(mfli)
daq_module.type("hardware_trigger")
daq_module.endless(False)
# Shape of my grid
daq_module.grid.mode(
4
) # Specify how the acquired data is sampled onto the matrix’s horizontal axis
daq_module.count(1)
daq_module.grid.cols(NUM_COLS)
daq_module.grid.rows(STEPS)
daq_module.grid.repetitions(1)
daq_module.grid.rowrepetition(
False
) # True: First average each row, then fill the next row -> sequential averaging
# False: First fill each row, then average the rows -> cyclic averaging
# Acquisition using Digital Triggering
node_trigger = demod.sample.TrigIn1
daq_module.triggernode(node_trigger)
daq_module.edge("rising")
daq_module.delay(0)
daq_module.holdoff.time(0)
daq_module.holdoff.count(0)
daq_module.clearhistory(1)
# print(f"Columns: {daq_module.grid.cols()}")
# print(f"Rows: {daq_module.grid.rows()}")
# print(f"Repetitions: {daq_module.grid.repetitions()}")
# print(f"Holdoff: {daq_module.holdoff.time()}")
# print(f"Delay: {daq_module.delay()}")
3.4 Define user functions for arming MFLI and reading results¶
In [ ]:
Copied!
def armMFLI():
for node in sample_nodes:
daq_module.subscribe(node)
daq_module.execute()
def readMFLI(session):
if session.connection_state.emulated:
return "Emulation running"
clockbase = mfli.clockbase()
timeout = 5 # s
# Retrieve data from UHFLI DAQ module
start_time = time.time()
while time.time() - start_time < timeout:
time.sleep(INT_TIME)
if daq_module.raw_module.finished() == True:
progress = daq_module.raw_module.finished()
print(f"Progress of data acquisition: {100 * progress:.2f}%.")
break
progress = daq_module.raw_module.finished()
if not (time.time() - start_time < timeout):
print(
f"Data acquisition timed out. Not all results collected, data is corrupted."
)
# Get data
daq_data = daq_module.read(raw=False, clk_rate=clockbase)
return daq_data
def clearDAQmodule():
for node in sample_nodes:
daq_module.subscribe(node)
def armMFLI():
for node in sample_nodes:
daq_module.subscribe(node)
daq_module.execute()
def readMFLI(session):
if session.connection_state.emulated:
return "Emulation running"
clockbase = mfli.clockbase()
timeout = 5 # s
# Retrieve data from UHFLI DAQ module
start_time = time.time()
while time.time() - start_time < timeout:
time.sleep(INT_TIME)
if daq_module.raw_module.finished() == True:
progress = daq_module.raw_module.finished()
print(f"Progress of data acquisition: {100 * progress:.2f}%.")
break
progress = daq_module.raw_module.finished()
if not (time.time() - start_time < timeout):
print(
f"Data acquisition timed out. Not all results collected, data is corrupted."
)
# Get data
daq_data = daq_module.read(raw=False, clk_rate=clockbase)
return daq_data
def clearDAQmodule():
for node in sample_nodes:
daq_module.subscribe(node)
3.5 Signal mapping¶
In [ ]:
Copied!
# define signal maps for different qubits
map_q0 = {
"drive": "/logical_signal_groups/q0/drive_line",
"coulomb_1": "/logical_signal_groups/q0/coulomb_line_1",
"coulomb_2": "/logical_signal_groups/q0/coulomb_line_2",
}
# calibration for qubit 0
calib_q0 = Calibration()
calib_q0["drive"] = SignalCalibration(
oscillator=Oscillator(
frequency=111e6,
modulation_type=ModulationType.SOFTWARE,
)
)
# define signal maps for different qubits
map_q0 = {
"drive": "/logical_signal_groups/q0/drive_line",
"coulomb_1": "/logical_signal_groups/q0/coulomb_line_1",
"coulomb_2": "/logical_signal_groups/q0/coulomb_line_2",
}
# calibration for qubit 0
calib_q0 = Calibration()
calib_q0["drive"] = SignalCalibration(
oscillator=Oscillator(
frequency=111e6,
modulation_type=ModulationType.SOFTWARE,
)
)
3.6 Set calibration and signal map¶
In [ ]:
Copied!
# set experiment calibration and signal map
exp.set_calibration(calib_q0)
exp.set_signal_map(map_q0)
# set experiment calibration and signal map
exp.set_calibration(calib_q0)
exp.set_signal_map(map_q0)
3.7 Run experiment¶
In [ ]:
Copied!
exp_compiled = session.compile(exp)
# print(exp_compiled.src[1]['text'])
# exp_compiled.src[1]['text'] = session.compiled_experiment.src[1]['text'].replace('while(repeat_count_shots);\n', 'while(repeat_count_shots);\nsetTrigger(0b0);\n')
exp_compiled = session.compile(exp)
# print(exp_compiled.src[1]['text'])
# exp_compiled.src[1]['text'] = session.compiled_experiment.src[1]['text'].replace('while(repeat_count_shots);\n', 'while(repeat_count_shots);\nsetTrigger(0b0);\n')
In [ ]:
Copied!
armMFLI()
time.sleep(0.1)
session.run(experiment=exp_compiled)
armMFLI()
time.sleep(0.1)
session.run(experiment=exp_compiled)
In [ ]:
Copied!
data = readMFLI(session)
clearDAQmodule()
data = readMFLI(session)
clearDAQmodule()
4. Plot results¶
In [ ]:
Copied!
if not session.connection_state.emulated:
results = []
ts0 = np.nan
plt.figure()
plt.xlabel("Time [s]")
clockbase = mfli.clockbase()
for node in sample_nodes:
plt.ylabel(str(node))
for sig_burst in data[node]:
results.append(sig_burst.value) # Results
if np.any(np.isnan(ts0)):
ts0 = sig_burst.header["createdtimestamp"][0] / clockbase
# Convert from device ticks to time in seconds.
t0_burst = sig_burst.header["createdtimestamp"][0] / clockbase
t = (sig_burst.time + t0_burst) - ts0
for ii, value in enumerate(results[0]):
plt.plot(t, value, label="readout step " + str(ii + 1))
# plt.legend(loc='upper right', fontsize=8)
plt.title("Time traces MFLI")
else:
print("Emulation - nothing to plot")
if not session.connection_state.emulated:
results = []
ts0 = np.nan
plt.figure()
plt.xlabel("Time [s]")
clockbase = mfli.clockbase()
for node in sample_nodes:
plt.ylabel(str(node))
for sig_burst in data[node]:
results.append(sig_burst.value) # Results
if np.any(np.isnan(ts0)):
ts0 = sig_burst.header["createdtimestamp"][0] / clockbase
# Convert from device ticks to time in seconds.
t0_burst = sig_burst.header["createdtimestamp"][0] / clockbase
t = (sig_burst.time + t0_burst) - ts0
for ii, value in enumerate(results[0]):
plt.plot(t, value, label="readout step " + str(ii + 1))
# plt.legend(loc='upper right', fontsize=8)
plt.title("Time traces MFLI")
else:
print("Emulation - nothing to plot")
5. Pulse sheet¶
In [ ]:
Copied!
show_pulse_sheet("MFLI integration", session.compiled_experiment)
show_pulse_sheet("MFLI integration", session.compiled_experiment)