ex4_update_in_place


In-Place Waveform Library Updates

This example notebook shows how one can update pulses data in-place without recompiling.

© Raytheon BBN Technologies 2020

Set the SAVE_WF_OFFSETS flag in order that QGL will output a map of the waveform data within the compiled binary waveform library.


In [8]:
from QGL import *
import QGL
import os.path
import pickle
QGL.drivers.APS2Pattern.SAVE_WF_OFFSETS = True

Create the usual channel library with a couple of AWGs.


In [3]:
cl = ChannelLibrary(db_resource_name=":memory:")
q1 = cl.new_qubit("q1")
aps2_1 = cl.new_APS2("BBNAPS1", address="192.168.5.101") 
aps2_2 = cl.new_APS2("BBNAPS2", address="192.168.5.102")
dig_1  = cl.new_X6("X6_1", address=0)
h1 = cl.new_source("Holz1", "HolzworthHS9000", "HS9004A-009-1", power=-30)
h2 = cl.new_source("Holz2", "HolzworthHS9000", "HS9004A-009-2", power=-30) 
cl.set_control(q1, aps2_1, generator=h1)
cl.set_measure(q1, aps2_2, dig_1.ch(1), generator=h2)
cl.set_master(aps2_1, aps2_1.ch("m2"))
cl["q1"].measure_chan.frequency = 0e6
cl.commit()


Creating engine...

Compile a simple sequence.


In [6]:
mf = RabiAmp(cl["q1"], np.linspace(-1, 1, 11))
plot_pulse_files(mf, time=True)


Compiled 11 sequences.
<module 'QGL.drivers.APS2Pattern' from '/Users/growland/workspace/QGL/QGL/drivers/APS2Pattern.py'>
<module 'QGL.drivers.APS2Pattern' from '/Users/growland/workspace/QGL/QGL/drivers/APS2Pattern.py'>

Open the offsets file (in the same directory as the .aps2 files, one per AWG slice.)


In [13]:
offset_f = os.path.join(os.path.dirname(mf), "Rabi-BBNAPS1.offsets")
with open(offset_f, "rb") as FID:
    offsets = pickle.load(FID)
offsets


Out[13]:
{'Waveform(Utheta, 122815, 24)_0x2e0defb474f06986': ([0], 24),
 'Waveform-TA(LOW, 96)_-0xf824eec18a1ee52': ([24], 4),
 'Waveform(Utheta, 122815, 24)_-0x37af64bdef1017bf': ([28], 24),
 'Waveform(Utheta, 122815, 24)_0x17bffe1abeb2c360': ([52], 24),
 'Waveform(Utheta, 122815, 24)_0x30d81103120ed2bd': ([76], 24),
 'Waveform(Utheta, 122815, 24)_0x455274f4ee41ba32': ([100], 24),
 'Waveform(Utheta, 122815, 24)_-0x6218db19881971aa': ([124], 24),
 'Waveform(Utheta, 122815, 24)_-0x274e23c9beffce37': ([148], 24),
 'Waveform(Utheta, 122815, 24)_-0x1b783f0cedf12d43': ([172], 24),
 'Waveform(Utheta, 122815, 24)_-0x51d0ae3b11be45ce': ([196], 24),
 'Waveform(Utheta, 122815, 24)_-0x20b43f5ea9db1e21': ([220], 24)}

Let's replace every single pulse with a fixed amplitude Utheta


In [17]:
pulses = {l: Utheta(q1, amp=0.1, phase=0) for l in offsets}
wfm_f = os.path.join(os.path.dirname(mf), "Rabi-BBNAPS1.aps2")
QGL.drivers.APS2Pattern.update_wf_library(wfm_f, pulses, offsets)

We see that the data in the file has been updated.


In [19]:
plot_pulse_files(mf, time=True)


<module 'QGL.drivers.APS2Pattern' from '/Users/growland/workspace/QGL/QGL/drivers/APS2Pattern.py'>
<module 'QGL.drivers.APS2Pattern' from '/Users/growland/workspace/QGL/QGL/drivers/APS2Pattern.py'>

Profiling

How long does this take?


In [20]:
%timeit mf = RabiAmp(cl["q1"], np.linspace(-1, 1, 100))


Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
Compiled 100 sequences.
317 ms ± 6.15 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Getting the offsets is fast, and only needs to be done once


In [25]:
def get_offsets():
    offset_f = os.path.join(os.path.dirname(mf), "Rabi-BBNAPS1.offsets")
    with open(offset_f, "rb") as FID:
        offsets = pickle.load(FID)
    return offsets
%timeit offsets = get_offsets()


61.1 µs ± 638 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [24]:
%timeit pulses =  {l: Utheta(q1, amp=0.1, phase=0) for l in offsets}


39.3 µs ± 1.17 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [26]:
wfm_f = os.path.join(os.path.dirname(mf), "Rabi-BBNAPS1.aps2")
%timeit QGL.drivers.APS2Pattern.update_wf_library(wfm_f, pulses, offsets)
# %timeit QGL.drivers.APS2Pattern.update_wf_library("/Users/growland/workspace/AWG/Rabi/Rabi-BBNAPS1.aps2", pulses, offsets)


1.25 ms ± 19.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Moral of the story: 300 ms for initial compilation, and roughly 1.3 ms for update_in_place.


In [ ]: