Skip to content

shapes

Carrier waveform shapes for use with ToneBurst. All shapes are PulseShape subclasses — Equinox modules with a normalised periodic output (peak amplitude 1).

Shapes are passed as the shape argument to ToneBurst:

from jbubble.pulse import ToneBurst
from jbubble.pulse.shapes import Sine, Square, Rectangular

pulse = ToneBurst(freq=1e6, pressure=100e3, shape=Sine())

Base classes

PulseShape

PulseShape()

Bases: Module

Abstract periodic carrier waveform.

A pulse calls a shape as shape(t, freq, phase, initial_time). The shape returns the waveform value at time t [s], evaluated at the phase

\[ x = 2\pi f (t - t_0) - \phi, \]

where \(f\) is freq [Hz], \(t_0\) is initial_time [s], and \(\phi\) is phase [rad].

name property

name

Short identifier for the shape.

FourierPulseShape

FourierPulseShape()

Bases: PulseShape

Abstract carrier waveform built from a truncated Fourier series.

Subclasses implement term, the \(m\)-th term of the series, and norm_factor. Term \(m\) isn't always harmonic \(m\): in Square, term \(m\) is harmonic \(2m - 1\). The shape sums the first 10 terms (NUM_FOURIER_TERMS), divides by norm_factor, and adds dc_offset:

\[ s(t) = \frac{1}{\mathrm{norm\_factor}} \sum_{m=1}^{10} \mathrm{term}(m, t - t_0, f, \phi) + \mathrm{dc\_offset} \]

dc_offset property

dc_offset

Constant added after normalisation. The base value is 0.0.

norm_factor property

norm_factor

Divisor that normalises the summed series.

term

term(m: Array, t: Array, freq: ArrayLike, phase: ArrayLike) -> Array

Return the m-th Fourier term at time t, relative to initial_time.

Source code in jbubble/pulse/shapes.py
82
83
84
85
86
87
88
89
90
91
@abc.abstractmethod
def term(
    self,
    m: jax.Array,
    t: jax.Array,
    freq: ArrayLike,
    phase: ArrayLike,
) -> jax.Array:
    """Return the `m`-th Fourier term at time `t`, relative to `initial_time`."""
    pass

Concrete shapes

Sine

Sine()

Bases: PulseShape

Pure sine carrier.

\[ s = \sin x, \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.

Square

Square()

Bases: FourierPulseShape

Square wave from a 10-term Fourier series (odd harmonics 1 to 19).

\[ s = \frac{4}{\pi} \sum_{m=1}^{10} \frac{\sin\left((2m - 1) x\right)}{2m - 1}, \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape. The truncated series shows Gibbs ringing at the edges.

Sawtooth

Sawtooth()

Bases: FourierPulseShape

Rising sawtooth from a 10-term Fourier series.

\[ s = \frac{2}{\pi} \sum_{m=1}^{10} \frac{(-1)^{m+1}}{m} \sin(m x), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.

InvertedSawtooth

InvertedSawtooth()

Bases: FourierPulseShape

Falling sawtooth, the negative of Sawtooth.

\[ s = \frac{2}{\pi} \sum_{m=1}^{10} \frac{(-1)^{m}}{m} \sin(m x), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.

Triangle

Triangle()

Bases: FourierPulseShape

Triangle wave from a 10-term Fourier series (odd harmonics 1 to 9).

\[ s = -\frac{4}{\pi^2} \sum_{m=1}^{10} \frac{1 - (-1)^m}{m^2} \cos\left(m\left(x + \frac{\pi}{2}\right)\right), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape. The even terms vanish, so the 10 terms give the five harmonics 1, 3, 5, 7, and 9. The wave starts at 0 and peaks at \(x = \pi/2\).

Quadratic

Quadratic()

Bases: FourierPulseShape

Piecewise-parabolic wave from a 10-term Fourier series.

\[ s = \frac{6}{\pi^2} \sum_{m=1}^{10} \frac{(-1)^m}{m^2} \cos\left(m\left(x - \frac{\pi}{\sqrt{3}}\right)\right), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.

NegativeQuadratic

NegativeQuadratic()

Bases: Quadratic

Negative of Quadratic.

Rectangular

Rectangular(
    duty: float,
    high_level: float = 1.0,
    low_level: float = -1.0,
    phase_offset: float = 0.0,
)

Bases: FourierPulseShape

General duty-cycle rectangular waveform.

Parameterised by the duty cycle \(D\), the amplitude levels \(A\) and \(B\), and the window placement \(\phi_\text{off}\). The target waveform is

\[ s = \begin{cases} A & \left(t - t_0 - \dfrac{\phi_\text{off}}{2\pi} T\right) \bmod T < D T, \\ B & \text{otherwise}, \end{cases} \]

for zero carrier phase, where \(T = 1/f\) is the period. The high window starts a fraction \(\phi_\text{off}/2\pi\) into each period and lasts \(DT\); when \(\phi_\text{off}/2\pi + D > 1\), it wraps into the start of the next period. The code evaluates the first 10 harmonics of its Fourier series:

\[ \begin{aligned} s &= A D + B (1 - D) + \sum_{m=1}^{10} \left[a_m \cos(m y) + b_m \sin(m y)\right], \qquad y = x - \phi_\text{off}, \\ a_m &= \frac{A - B}{\pi m} \sin(2\pi m D), \qquad b_m = \frac{A - B}{\pi m} \left[1 - \cos(2\pi m D)\right], \end{aligned} \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape. The DC component is high_level * duty + low_level * (1 - duty).

Parameters:

Name Type Description Default
duty float

Fraction \(D\) of the period spent at high_level, with 0 < duty < 1.

required
high_level float

Amplitude \(A\) during the active window. Default: 1.0.

1.0
low_level float

Amplitude \(B\) outside the active window. Default: -1.0.

-1.0
phase_offset float

Cycle offset \(\phi_\text{off}\) [rad], equal to \(2\pi\) times the start fraction of the high window. 0 places the window at the cycle start and π at the midpoint. Default: 0.0.

0.0

Examples:

The following examples show common named forms.

Rectangular(duty=0.5)  # ±1 square
Rectangular(duty=0.5, phase_offset=jnp.pi)  # negative-then-positive square
Rectangular(duty=0.25)  # +1 for 25% of the cycle, -1 for 75%
Rectangular(  # monopolar: -1 for 99% of the cycle
    duty=0.01, high_level=0.0, low_level=-1.0, phase_offset=1.98 * jnp.pi
)

TimeDomainSquare

TimeDomainSquare(sharpness: float = 50.0)

Bases: PulseShape

Smooth square wave built in the time domain.

\[ s = \tanh(k \sin x), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape, and \(k\) is sharpness.

Parameters:

Name Type Description Default
sharpness float

Steepness \(k\) of the transitions. Default: 50.0.

50.0

TimeDomainSawtooth

TimeDomainSawtooth()

Bases: PulseShape

Rising sawtooth built in the time domain.

\[ s = \frac{2}{\pi} \arctan\left(\tan\frac{x}{2}\right), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.

TimeDomainTriangle

TimeDomainTriangle()

Bases: PulseShape

Triangle wave built in the time domain.

\[ s = \frac{2}{\pi} \arcsin(\sin x), \]

with \(x = 2\pi f (t - t_0) - \phi\) as in PulseShape.


Choosing a shape

Shape Spectral content Notes
Sine Single harmonic Default; smoothest, no harmonic artefacts
Square / TimeDomainSquare Odd harmonics Gibbs ringing in Fourier version; TimeDomainSquare avoids it
Sawtooth / TimeDomainSawtooth All harmonics Rising ramp; useful for asymmetric forcing
Triangle / TimeDomainTriangle Odd harmonics, faster roll-off Smoother than square
Rectangular(duty) General Full control over duty cycle, levels, and phase offset

For gradient-based optimisation of the carrier shape, prefer TimeDomain* variants or Sine — Fourier-series shapes truncate at 10 terms and are C^0 at sharp transitions.