Waveforms

Waveforms are essential ingredients for generating the Rydberg Hamiltonian. By controlling the waveforms of $\Omega$, $\Delta$, and $\phi$, one can prepare the ground states of certain target Hamiltonians and study their non-equilibrium dynamics. Bloqade supports several built-in waveforms and allows the users to specify waveforms by inputting functions. It also supports different operations of waveforms, such as waveform smoothening, composing, and more.

The generated waveforms can be directly used to build the time-dependent Hamiltonians. Please see the Hamiltonians section for more details.

Creating Waveforms

In Bloqade, the waveforms are defined as a Waveform object, which is a created by providing a callable object and a real number duration:

Bloqade gives users the flexibility to specify general waveforms by inputting functions. The following code constructs a sinusoidal waveform with a time duration of 2 μs:

using Bloqade, Bloqade.CairoMakie
waveform = Waveform(t->2.2*2π*sin(2π*t), duration = 2);
Bloqade.plot(waveform)
Example block output

In our documentation, we use the CairoMakie for plotting.

Bloqade supports built-in waveforms for convenience (see References below). For example, the codes below create different waveform shapes with a single line:

waveform = piecewise_linear(clocks=[0.0, 0.2, 0.5, 0.8, 1.0], values= 2π* [0.0, 1.5, 3.1, 3.1, 0.0]);
Bloqade.plot(waveform)
Example block output
waveform = piecewise_constant(clocks=[0.0, 0.2, 0.5, 0.7], values= 2π*[0.0, 1.5, 3.1]);
Bloqade.plot(waveform)
Example block output
waveform = linear_ramp(duration=0.5, start_value=0.0, stop_value=2π*1.0);
Bloqade.plot(waveform)
Example block output
waveform =  constant(duration=0.5, value=2π*2.1);
Bloqade.plot(waveform)
Example block output
waveform = sinusoidal(duration=2, amplitude=2π*2.2);
Bloqade.plot(waveform)
Example block output

In some cases, users may have their own waveforms specified by a vector of clocks and a vector of signal strengths. To build a waveform from the two vectors, we can directly use the functions piecewise_linear or piecewise_constant, corresponding to different interpolations.

clocks = collect(0:1e-1:2);
values1 = 2π*rand(length(clocks));
wf1 = piecewise_linear(;clocks, values=values1);
values2 = 2π*rand(length(clocks)-1)
wf2 = piecewise_constant(;clocks, values=values2);

fig = Figure(size=(960, 400))
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
Bloqade.plot!(ax1, wf1)
Bloqade.plot!(ax2, wf2)
fig
Example block output

For more advanced interpolation options, please see the JuliaMath/Interpolations package.

Operations on Waveforms

Bloqade also supports several operations on the waveforms.

Waveforms can be sliced using the duration syntax start..stop, e.g.:

wf = 2π*sinusoidal(duration=2.2);
wf1 = wf[1.1..1.5];
Bloqade.plot(wf1)

Note that time starts from 0.0 again, so the total duration is stop - start.

Waveforms can be composed together via append:

wf2 = linear_ramp(;start_value=0.0, stop_value=1.1*2π, duration=0.5);
waveform = append(wf1, wf2);
Bloqade.plot(waveform)
Example block output

where the waveform wf2 is appended at the end of wf1.

Sharp points in waveforms may result in bad performance in practice (e.g. for adiabatically preparing a ground state of a target Hamiltonian). It is sometimes preferred to smoothen the waveform using the moving average methods. One can use the smooth function to create a smoothened waveform from a piecewise linear waveform:

wf = piecewise_linear(clocks=[0.0, 2.0, 3.0, 4.0], values=2π*[0.0, 3.0, 1.1, 2.2]);
swf = smooth(wf;kernel_radius=0.1);

fig = Figure(size=(960, 400))
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
Bloqade.plot!(ax1, wf)
Bloqade.plot!(ax2, swf)
fig
Example block output

Waveform Arithmetics

Bloqade also supports several arithmetics on the waveforms. If two waveforms have the same duration, we can directly add up or subtract the strength of them, simply by using + or -:

wf1 = linear_ramp(;duration=2.2, start_value=0.0, stop_value=1.0*2π);
wf2 = sinusoidal(duration = 2.2, amplitude = 2.2*2π);
wf3 = wf1 + wf2;
wf4 = wf1 - wf2;

fig = Figure(size=(960, 400))
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
Bloqade.plot!(ax1, wf3)
Bloqade.plot!(ax2, wf4)
fig
Example block output

To increase the strength of a waveform by some factors, we can directly use *:

wf = linear_ramp(;duration=2.2, start_value=0.0, stop_value=1.0*2π);
wf_t = 3 * wf;

fig = Figure(size=(960, 400))
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
Bloqade.plot!(ax1, wf)
Bloqade.plot!(ax2, wf_t)
fig
Example block output

Such operations can also be broadcasted by using .*:

wf2, wf3 = [2.0, 3.0] .* wf1;

fig = Figure(size=(960, 400))
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
Bloqade.plot!(ax1, wf2)
Bloqade.plot!(ax2, wf3)
fig
Example block output

References

BloqadeWaveforms.WaveformType
struct Waveform{F,T<:Real}

Type for waveforms. Waveforms are defined as a function combined with a real number duration.

Fields

  • f: a callable object.
  • duration: a real number defines the duration of this waveform; default unit is μs.
source
BloqadeWaveforms.WaveformMethod
Waveform(f; duration::Real)

Create a Waveform object from callable f, the unit of duration is μs.

Example

julia> Waveform(duration=1.5) do t
            2π*(2t+1)
        end
                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                    ┌────────────────────────────────────────┐
                  4 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠚⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠚⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   value / 2π (MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                  1 │⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    └────────────────────────────────────────┘
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀2⠀

julia>
source
Intervals.:..Function
function (..)(first, last)

Exported from Intervals, creates a closed interval from first..last and can be used with Waveform structs to obtain a slice of a Waveform's values, with the waveform slice's time adjusted to begin at 0 μs and the duration being last - first.

Example

julia> wf = Waveform(t->2.2*2π*sin(2π*t), duration = 2)
                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Int64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                    ┌────────────────────────────────────────┐
                  3 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⡴⠋⠙⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠋⠙⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⡼⠁⠀⠀⠈⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠁⠀⠀⠈⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⢰⠃⠀⠀⠀⠀⠈⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠃⠀⠀⠀⠀⠈⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⢀⡏⠀⠀⠀⠀⠀⠀⢸⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡏⠀⠀⠀⠀⠀⠀⢸⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⡼⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   value / 2π (MHz) │⠧⠤⠤⠤⠤⠤⠤⠤⠤⠼⡦⠤⠤⠤⠤⠤⠤⠤⠤⢤⠧⠤⠤⠤⠤⠤⠤⠤⠤⠼⡦⠤⠤⠤⠤⠤⠤⠤⠤⢤│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⡞│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⢸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⢸⠁│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⢀⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⢀⠇⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⡀⠀⠀⢀⡞⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⣄⣠⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⣄⣠⠞⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀│
                 -3 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    └────────────────────────────────────────┘
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀2⠀

julia> wf[0.9..1.5]
                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                    ┌────────────────────────────────────────┐
                  3 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠤⠔⠒⠒⠒⠦⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠞⠉⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠲⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⢦⡀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⣄⠀⠀⠀│
   value / 2π (MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⣠⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀│
                    │⠀⠀⠀⠀⠀⠀⢀⡜⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢦│
                    │⠉⠉⠉⠉⠉⡽⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉│
                    │⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⢀⡴⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                 -2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    └────────────────────────────────────────┘
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀0.6⠀
source
BloqadeWaveforms.sample_valuesFunction
sample_values(wf::Waveform, clocks; offset::Real = zero(eltype(wf)))
sample_values(wf::Waveform; offset::Real = zero(eltype(wf)), dt::Real = 1e-3)

Samples of waveform wf values obtainable by either providing an iterable clocks containing exact time values to sample from or providing offset and dt values which specify the offset to add to the beginning and end of the waveforms time span and the step between time values.

See also sample_clock

julia> wf = linear_ramp(duration=0.5, start_value=0.0, stop_value=2π*1.0);

julia> sample_values(wf,0.0:0.1:0.5) # sample waveform values from range
6-element Vector{Float64}:
 0.0
 1.2566370614359172
 2.5132741228718345
 3.7699111843077517
 5.026548245743669
 6.283185307179586

julia> sample_values(wf; dt=5e-2) #5e-2 time gap between each sampled valued
11-element Vector{Float64}:
 0.0
 0.6283185307179586
 1.2566370614359172
 1.8849555921538759
 2.5132741228718345
 3.141592653589793
 3.7699111843077517
 4.39822971502571
 5.026548245743669
 5.654866776461628
 6.283185307179586
source
BloqadeWaveforms.sample_clockFunction
sample_clock(wf::Waveform; offset::Real = zero(eltype(wf)), dt::Real = 1e-3)

Generates range of time values based on wf's duration with dt time between each time value along with offset time added to the beginning and end of the waveform's time span.

See also sample_values

julia> wf = sinusoidal(duration=2, amplitude=2π*2.2); # create a waveform

julia> sample_clock(wf;) # range from 0.0 to 2.0 with step of 0.001 (default arg)
0.0:0.001:2.0

julia> sample_clock(wf; offset=0.1) # offset beginning and end by 0.1
0.1:0.001:2.1

julia> sample_clock(wf; dt = 2e-3) # set step size of 2e-3
0.0:0.002:2.0
source
BloqadeWaveforms.piecewise_linearFunction
piecewise_linear(;clocks, values)

Create a piecewise linear waveform.

Keyword Arguments

  • clocks::Vector{<:Real}: the list of clocks for the corresponding values.
  • values::Vector{<:Real}: the list of values at each clock.

Example

julia> piecewise_linear(clocks=[0.0, 2.0, 3.0, 4.0], values=2π * [0.0, 2.0, 2.0, 0.0])
                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 
                    ┌────────────────────────────────────────┐ 
                  2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢇⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡆⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱⡀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢇⠀⠀⠀⠀⠀│ 
   value / 2π (MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⢀⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀│ 
                    │⠀⠀⠀⠀⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱⡀⠀│ 
                    │⠀⠀⢀⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢇⠀│ 
                    │⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡆│ 
                  0 │⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱│ 
                    └────────────────────────────────────────┘ 
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀4⠀ 
source
BloqadeWaveforms.piecewise_constantFunction
piecewise_constant(;clocks, values, duration=last(clocks))

Create a piecewise constant waveform.

The number of elements in clocks should be one greater than the number of elements in values. For example, if you wanted to define a piecewise constant waveform with the following:

  • 0.0 2π ⋅ MHz from 0.0 to 0.5 μs
  • 1.0 2π ⋅ MHz from 0.5 to 0.9 μs
  • 2.1 2π ⋅ MHz from 0.9 to 1.1 μs

It would be expressed as: piecewise_constant(clocks=[0.0, 0.5, 0.9, 2.1], values=[0.0, 1.0, 2.1])

Keyword Arguments

  • clocks::Vector{<:Real}: the list of clocks for the corresponding values.
  • values::Vector{<:Real}: the list of values at each clock.
  • duration::Real: the duration of the entire waveform, default is the last clock.

Example

julia> piecewise_constant(clocks=[0.0, 0.2, 0.5, 0.9], values=2π * [0.0, 1.5, 3.1])
                    ┌────────────────────────────────────────┐
                  4 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡖⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   value / 2π (MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⢰⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠒⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    │⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                  0 │⣀⣀⣀⣀⣀⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                    └────────────────────────────────────────┘
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀0.9⠀
source
BloqadeWaveforms.piecewise_linear_interpolateFunction
piecewise_linear_interpolate(waveform;[max_vale=Inf64,max_slope=Inf64,min_step=0.0])

Function which takes a waveform and translates it to a linear interpolation subject to some constraints. The function returns a piecewise linear waveform. if the Waveform is piecewise linear only the constraints will be checked.

Arguments

Keyword Arguments

  • min_step: minimum possible step used in interpolation
  • max_slope: Maximum possible slope used in interpolation
  • atol: tolerance of interpolation, this is a bound to the area between the linear interpolation and the waveform.
source
BloqadeWaveforms.linear_rampFunction
linear_ramp(;duration, start_value, stop_value)

Create a linear ramp waveform.

Keyword Arguments

  • duration::Real: duration of the whole waveform.
  • start_value::Real: start value of the linear ramp.
  • stop_value::Real: stop value of the linear ramp.

Example

julia> linear_ramp(;duration=2.2, start_value=0.0, stop_value=1.0 * 2π)
                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 
                    ┌────────────────────────────────────────┐ 
                  1 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   value / 2π (MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    │⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                  0 │⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                    └────────────────────────────────────────┘ 
                    ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀3⠀ 
source
BloqadeWaveforms.constantFunction
constant(;duration::Real, value::Real)

Create a constant waveform.

Keyword Arguments

  • duration::Real: duration of the whole waveform.
  • value::Real: value of the constant waveform.
source
BloqadeWaveforms.sinusoidalFunction
sinusoidal(;duration::Real, amplitude::Real=one(start))

Create a sinusoidal waveform of the following expression.

amplitude * sin(2π*t)

Keyword Arguments

  • duration: duration of the waveform.
  • amplitude: amplitude of the sin waveform.
source
BloqadeWaveforms.smoothMethod
smooth(kernel, Xi::Vector, Yi::Vector, kernel_radius::Real)

Kernel smoother function via weighted moving average method. See also Kernel Smoother.

Theory

Kernel function smoothing is a technique to define a smooth function $f: \mathcal{R}^p → \mathbf{R}$ from a set of discrete points by weighted averaging the neighboring points. It can be written as the following equation.

\[Ŷ(X) = \sum_i K(X, X_i) Y_i / \sum_i K(X, X_i)\]

where $Ŷ(X)$ is the smooth function by calculating the moving average of known data points $X_i$ and $Y_i$. K is the kernel function, where $K(\frac{||X - X_i||}{h_λ})$ decrease when the Euclidean norm $||X - X_i||$ increase, $h_λ$ is a parameter controls the radius of the kernel.

Available Kernels

The following kernel functions are available via the Kernels module:

Kernels.biweight; Kernels.cosine; Kernels.gaussian; Kernels.logistic; Kernels.parabolic; Kernels.sigmoid; Kernels.triangle; Kernels.tricube; Kernels.triweight; Kernels.uniform

Arguments

  • kernel: a Julia function that has method kernel(t::Real).
  • Xi::Vector: a list of inputs X_i.
  • Yi::Vector: a list of outputs Y_i.
  • kernel_radius::Real: the radius of the kernel.
source
BloqadeWaveforms.Kernels.biweightFunction
biweight(t)

Biweight kernel function for smoothing waveforms via smooth

The function is defined as:

\[f(t) = \frac{15}{16}(1 - |t|^2)^2\]

when $|t| ≤ 1$. Otherwise, $f(t) = 0$.

source
BloqadeWaveforms.Kernels.cosineFunction
cosine(t)

Cosine kernel function for smoothing waveforms via smooth

The function is defined as:

\[f(t) = \frac{π}{4}\cos\left(\frac{π}{2}t\right)\]

when $|t| ≤ 1$. Otherwise, $f(t) = 0$.

source
BloqadeWaveforms.Kernels.tricubeFunction
tricube(t)

Tricube kernel function for smoothing waveforms via smooth

The function is defined as:

\[f(t) = \frac{70}{81}(1 - |t|^3)^3\]

when $|t| ≤ 1$. Otherwise, $f(t) = 0$.

source