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 composition of a callable object and a real number duration:

struct Waveform

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


  • f: a callable object.
  • duration: a real number defines the duration of this waveform; default unit is μs.

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
using PythonCall
plt = pyimport("matplotlib.pyplot")
waveform = Waveform(t->2.2*2π*sin(2π*t), duration = 2);

In our documentation, we use the python package matplotlib 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]);
waveform = piecewise_constant(clocks=[0.0, 0.2, 0.5, 0.7], values= 2π*[0.0, 1.5, 3.1]);
waveform = linear_ramp(duration=0.5, start_value=0.0, stop_value=2π*1.0);
waveform =  constant(duration=0.5, value=2π*2.1);
waveform = sinusoidal(duration=2, amplitude=2π*2.2);

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, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
Bloqade.plot!(ax1, wf1)
Bloqade.plot!(ax2, wf2)

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];

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);

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, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
Bloqade.plot!(ax1, wf)
Bloqade.plot!(ax2, swf)

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, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
Bloqade.plot!(ax1, wf3)
Bloqade.plot!(ax2, wf4)

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, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
Bloqade.plot!(ax1, wf)
Bloqade.plot!(ax2, wf_t)

Such operations can also be broadcasted by using .*:

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

fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
Bloqade.plot!(ax1, wf2)
Bloqade.plot!(ax2, wf3)


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.


julia> piecewise_linear(clocks=[0.0, 2.0, 3.0, 4.0], values=[0.0, 2.0, 2.0, 0.0])
                  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 
                2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   value (2π ⋅ MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀│ 
                0 │⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱│ 
                  ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀4⠀ 
piecewise_constant(;clocks, values, duration=last(clocks))

Create a piecewise constant waveform.

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.


julia> piecewise_constant(clocks=[0.0, 0.2, 0.5], values=[0.0, 1.5, 3.1], duration=1.1)
                  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 
                4 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   value (2π ⋅ MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                0 │⣀⣀⣀⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                  ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀2⠀ 
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.


julia> linear_ramp(;duration=2.2, start_value=0.0, stop_value=1.0)
                  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Waveform{_, Float64}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ 
                1 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   value (2π ⋅ MHz) │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                0 │⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
                  ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀clock (μs)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀3⠀ 
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.
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.
smooth(kernel, Xi::Vector, Yi::Vector, kernel_radius::Real)

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


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:

biweight; cosine; gaussian; include; logistic; parabolic; sigmoid; triangle; tricube; triweight; uniform


  • 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.