Interpolated Waveforms
import numpy as npimport matplotlib.pyplot as plt
import pulserfrom pulser import Pulse, Sequence, Registerfrom pulser.devices import AnalogDevicefrom pulser.waveforms import InterpolatedWaveformIn some particular applications (the most notorious being its use in optimal control at the pulse level) it is useful to define a waveform through the interpolation of a set of data points. For these cases, Pulser provides the InterpolatedWaveform class.
In its most stripped back form, the InterpolatedWavefrom requires two things: a duration and a list of values. The placement of these values along the times axis defaults to spacing the values evenly along the whole duration of the waveform.
# A standard interpolation (using PchipInterpolator)duration = 1000values = [0, 1, 4.4, 2, 3, 1, 0]int_wf = InterpolatedWaveform(duration, values)int_wf.draw()
If we want to specify the time coordinate of each data point, we can do so through the times option. These should come in a list of values betwen 0 and 1, which are interperted as fractions of the total duration. As an example, below we specify that the values are all bunched in the first half of the waveform, except for the last one, which is left at the end.
ts = np.r_[np.linspace(0.0, 0.5, num=len(values) - 1), 1]int_wf_t = InterpolatedWaveform(duration, values, times=ts)int_wf_t.draw()
Finally, an InterpolatedWaveform can be streched or contracted in both magnitude and duration:
# Streching an interpolated waveformint_wf_stretch_y = int_wf * 2int_wf_stretch_x = int_wf.with_new_duration(duration * 2)
fig, ax = plt.subplots()ax.plot(int_wf.samples, label="Original")ax.plot(int_wf_stretch_y.samples, label="Streched in Y")ax.plot(int_wf_stretch_x.samples, label="Streched in X")ax.legend()plt.show()
Use in a parameterized sequence
Section titled “Use in a parameterized sequence”The InterpolatedWaveform is used like any other waveform. In the contexts where it usually comes up, it might be helpful to incorporate it in a parametrized sequence. Below, we’ll show how to make a parametrized sequence where the data points for the amplitude and detuning waveforms are variables.
reg = Register.square(1, prefix="q")param_seq = Sequence(reg, AnalogDevice)param_seq.declare_channel("rydberg_global", "rydberg_global", initial_target=0)amp_vals = param_seq.declare_variable("amp_vals", size=5, dtype=float)det_vals = param_seq.declare_variable("det_vals", size=4, dtype=float)
amp_wf = InterpolatedWaveform(1000, amp_vals)det_wf = InterpolatedWaveform(1000, det_vals)pls = Pulse(amp_wf, det_wf, 0)
param_seq.add(pls, "rydberg_global")From here, we can build some random sequence by specifying the values of amp_vals and det_vals. For example:
seq1 = param_seq.build(amp_vals=[0, 2, 1, 2, 0], det_vals=[0, -5, 5, -5])seq1.draw()
Notice how the interpolation points are automatically drawn on top of the waveforms. You can disable this option through the draw_interp_pts parameter:
seq1.draw(draw_interp_pts=False)
