2.1. Modelling a Simple TablePulseTemplate¶
This example demonstrates how to set up a simple TablePulseTemplate(or short TablePT).
Assume we want to model a pulse as depicted by the figure above. Since
the structure is relatively simple and relies only on a few critical
points between which the values are interpolated (indicated by the
crosses in the figure), we will do so by using a TablePulseTemplate
and setting values at appropriate times.
For our first try, let’s just fix some values for the parameters. Let us set \(t_a\) = 2, \(v_a\) = 2, \(t_b\) = 4, \(v_b\) = 3, \(t_{end}\) = 6. Our pulse then holds a value of 0 for 2 units of time, then jumps to 2 and subsequently ramps to 3 over the next 2 units of time. Finally, it returns to holding 0 for another 2 units of time. The supporting points for the table are thus (0,0), (2,2), (4,3), (6,0).
Let us first put these entries into a list with the correct interpolation strategies:
In [1]:
entry_list = [(0, 0),
(2, 2, 'hold'),
(4, 3, 'linear'),
(6, 0, 'jump')]
The interpolation set for an entry always applies to the range from the previous entry to the new entry. Thus, the value for the first entry is always ignored. The default value for interpolation is ‘hold’. ‘hold’ and ‘jump’ differ in that ‘hold’ will hold the previous value until the new entry is reached while ‘jump’ will immediately assume the value of the new entry.
Now, we must decide on which channel the TablePulseTemplate
is
defined on. As a TablePulseTemplate
can contain multiple channels it
takes a python dict
whose keys are the channel identifiers and whose
values are lists of entries like the one above. Channel identifiers can
be either strings like ‘channel_A’ or integers. For this example we
choose the channel ID ‘0’ for our pulse and create the
TablePulseTemplate
object template
:
In [2]:
from qctoolkit.pulses import TablePT
entries = {0: entry_list}
template = TablePT(entries)
Notice that we used the alias TablePT
. We plot template
to see
if everything is correct:
In [3]:
%matplotlib notebook
from qctoolkit.pulses.plotting import plot
_ = plot(template, sample_rate=100, show=True)
Alright, we got what we wanted.
Note that the time domain in pulse defintions does not correspond to any fixed real world time unit. The mapping from a single time unit in a pulse definition to real time in execution is made by setting a sample rate when converting the pulse templates to waveforms. For more on this, see The Sequencing Process: Obtaining Pulse Instances From Pulse Templates.
2.1.1. Introducing Parameters¶
Now we want to make the template parameterizable. This allows us to
reuse the template for pulses with similar structure. Say we would like
to have the same pulse, but the intermediate linear interpolation part
should last 4 units of time instead of only 2. Instead of creating
another template with hardcoded values, we instruct the
TablePulseTemplate
instance to rely on parameters.
In [4]:
param_entries = {0: [(0, 0),
('ta', 'va', 'hold'),
('tb', 'vb', 'linear'),
('tend', 0, 'jump')]}
param_template = TablePT(param_entries)
Instead of using numerical values, we simply insert parameter names in
our entry list. You can use any combination of numerical values or
parameters names here. Note that we also gave our object the optional
identifier ‘foo’. Our param_template
thus now defines a set of
parameters.
In [5]:
print(param_template.parameter_names)
{'ta', 'vb', 'tend', 'va', 'tb'}
We now have a pulse template that we can instantiate with different parameter values, which we simply provide as a dictionary. To achieve the same pulse as above:
In [6]:
parameters = {'ta': 2,
'va': 2,
'tb': 4,
'vb': 3,
'tend': 6}
_ = plot(param_template, parameters, sample_rate=100)
To instantiate the pulse with longer intermediate linear interpolation
we now simply adjust the parameter values without touching the
param_template
itself:
In [7]:
parameters = {'ta': 2,
'va': 2,
'tb': 6,
'vb': 3,
'tend': 8}
_ = plot(param_template, parameters, sample_rate=100)