quchip.control.envelopes

Pulse envelope models for quantum control.

Envelopes define the time-domain waveform shape E(t) that a drive line plays between t = 0 and t = duration. Subclasses are auto-registered for serialization and as JAX pytrees (via __init_subclass__), so envelope parameters — duration, amplitude, edge width, DRAG coefficient, anything stored on the instance — remain differentiable end-to-end.

Conventions

  • Times are ns, waveforms are complex (the real/imag parts are interpreted by the drive channel’s DriveModulation).

  • waveform(t, xp=jnp) must stay JAX-traceable when xp is jax.numpy; no concretization of t or of stored parameters.

References

  • Motzoi et al., Simple Pulses for Elimination of Leakage, PRL 103, 110501 (2009) — motivates Gaussian envelopes with DRAG corrections for short transmon pulses.

  • Krantz et al., APR 6, 021318 (2019), Sec. IV.C — flat-top (Gaussian-edge) pulses for two-qubit gates.

Examples

>>> from quchip import Gaussian, LinearRamp, Square, SquareWithGaussianEdges
>>> g = Gaussian(duration=20.0, sigmas=3.0, amplitude=0.05)
>>> sq = Square(duration=10.0, amplitude=0.1, phase=0.0)
>>> fg = SquareWithGaussianEdges(duration=40.0, amplitude=0.1)
>>> lr = LinearRamp(duration=60.0, ramp_duration=50.0, amplitude=4.0)

Classes

BaseEnvelope(duration, *[, amplitude])

Base class for pulse envelopes.

Gaussian(duration[, sigmas, amplitude])

Centered Gaussian pulse.

GaussianEdge(duration, edge_duration[, ...])

Flat-top pulse with Gaussian ramp-up and ramp-down edges.

LinearRamp(duration, ramp_duration[, amplitude])

Linearly rising ramp that holds at peak amplitude.

Square(duration[, amplitude, phase])

Constant-amplitude pulse with optional global phase.

SquareWithGaussianEdges(duration[, ...])

Flat-top pulse with Gaussian ramp-up and ramp-down edges.

class quchip.control.envelopes.BaseEnvelope(duration, *, amplitude=1.0)[source]

Bases: Registrable, ABC

Base class for pulse envelopes.

Subclasses store their shape parameters as public attributes and implement waveform(). Every public attribute is registered as a pytree leaf, so gradients flow through arbitrary envelope parameters without any extra bookkeeping. Serialization (the type registry and from_dict dispatch) is owned by the shared Registrable mixin; the JAX pytree registration below is independent of it.

Parameters:
  • duration (float) – Total pulse duration in ns. Must be positive at construction time when concrete; tracers are accepted unchanged.

  • amplitude (float) – Scalar amplitude applied on top of waveform().

abstractmethod waveform(t, *, xp=None)[source]

Evaluate the complex envelope at time points t (ns).

Pass xp=jax.numpy to keep the computation traceable; otherwise NumPy is used.

Parameters:
Return type:

ndarray

sample(tlist, *, real=False)[source]

Vectorized waveform evaluation on a time array.

Picks the array namespace from tlist (JAX if it is a JAX array/tracer, NumPy otherwise), so traced inputs stay traced and concrete inputs yield concrete outputs. Returns a complex array shaped like tlist (or the real part if real=True).

Parameters:
Return type:

Any

class quchip.control.envelopes.Gaussian(duration, sigmas=3, amplitude=1.0)[source]

Bases: EnvelopeShape

Centered Gaussian pulse.

\[E(t) = A \exp\!\left[-\frac{(t - \tau/2)^2}{2 \sigma^2}\right], \qquad \sigma = \frac{\tau}{2 N_\sigma}.\]

The sigmas parameter \(N_\sigma\) is the number of standard deviations from the pulse center to its edge at t = 0 or t = duration. Gaussian pulses minimize spectral leakage onto higher transmon levels and are the starting point for DRAG corrections (Motzoi et al., PRL 103, 110501 (2009)).

The scheduled window [0, duration] starts and ends at amplitude * exp(-sigmas**2 / 2), not zero — about 0.011 * amplitude at the default sigmas=3. The pulse turns on and off with that jump; the Gaussian waveform itself is unchanged.

Parameters:
  • duration (Any)

  • sigmas (Any)

  • amplitude (Any)

duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
sigmas: Any = Parameter(default=3, positive=True, nonnegative=False, serialize=True, unit=None)
amplitude: Any = Parameter(default=1.0, positive=False, nonnegative=False, serialize=True, unit=None)
value(t)[source]

Evaluate the centered Gaussian envelope at time points t.

Parameters:

t (Any)

Return type:

Any

class quchip.control.envelopes.GaussianEdge(duration, edge_duration, sigmas=3, amplitude=1.0)[source]

Bases: EnvelopeShape

Flat-top pulse with Gaussian ramp-up and ramp-down edges.

Each edge is a Gaussian of width \(\sigma = \tau_e / (2 N_\sigma)\) where \(\tau_e\) = edge_duration; the plateau between edges holds a constant amplitude \(A\). Total duration includes both edges. Commonly used for two-qubit gates (Krantz et al. 2019, Sec. IV.C) because the flat top sets the gate area while the Gaussian edges suppress spectral leakage.

Parameters:
  • duration (float) – Total pulse length, including both edges, in ns.

  • edge_duration (float) – Ramp time \(\tau_e\) per edge, in ns. Must satisfy 2 * edge_duration <= duration.

  • sigmas (float) – Number of standard deviations spanned by each edge.

  • amplitude (float) – Plateau amplitude \(A\).

See also

SquareWithGaussianEdges

Same shape parameterized by edge_frac (fraction) instead of absolute edge_duration.

References

  • Krantz et al., APR 6, 021318 (2019), Sec. IV.C.

duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
edge_duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
sigmas: Any = Parameter(default=3, positive=True, nonnegative=False, serialize=True, unit=None)
amplitude: Any = Parameter(default=1.0, positive=False, nonnegative=False, serialize=True, unit=None)
validate()[source]

Reject edges that overrun the pulse (2 * edge_duration > duration).

Return type:

None

value(t)[source]

Evaluate the flat-top Gaussian-edge envelope at time points t.

Parameters:

t (Any)

Return type:

Any

class quchip.control.envelopes.SquareWithGaussianEdges(duration, amplitude=1.0, edge_frac=0.25, sigmas=3)[source]

Bases: EnvelopeShape

Flat-top pulse with Gaussian ramp-up and ramp-down edges.

Each ramp has duration \(\tau_e = f_e \cdot \tau\) with \(f_e\) = edge_frac; the plateau between ramps holds amplitude \(A\). Total duration includes both edges. The Gaussian width is \(\sigma = \tau_e / (2 N_\sigma)\) with \(N_\sigma\) = sigmas.

This is the canonical shape used in Krantz et al. 2019 (Sec. IV.C) for two-qubit gates — the flat top sets the gate area while the Gaussian edges suppress spectral leakage. Parametrizing the ramp as a fraction of the total duration makes the shape shape-invariant under changes of duration.

Parameters:
  • duration (float) – Total pulse length in ns (includes both ramps).

  • amplitude (float) – Plateau amplitude \(A\).

  • edge_frac (float) – Ramp length as a fraction of the total duration. Must satisfy 0 < edge_frac and 2 * edge_frac <= 1.

  • sigmas (float) – Number of standard deviations spanned by each ramp.

duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
amplitude: Any = Parameter(default=1.0, positive=False, nonnegative=False, serialize=True, unit=None)
edge_frac: Any = Parameter(default=0.25, positive=True, nonnegative=False, serialize=True, unit=None)
sigmas: Any = Parameter(default=3, positive=True, nonnegative=False, serialize=True, unit=None)
validate()[source]

Reject ramps that overrun the pulse (2 * edge_frac > 1).

Return type:

None

property edge_duration: float

Ramp duration in ns (edge_frac * duration).

value(t)[source]

Evaluate the fraction-parameterized Gaussian-edge envelope.

Parameters:

t (Any)

Return type:

Any

class quchip.control.envelopes.LinearRamp(duration, ramp_duration, amplitude=1.0)[source]

Bases: EnvelopeShape

Linearly rising ramp that holds at peak amplitude.

The envelope rises linearly from 0 to amplitude over the first ramp_duration nanoseconds, then holds constant at amplitude for the remainder of the pulse.

\[E(t) = A \cdot \min\!\left(\frac{t}{\tau_r},\, 1\right), \qquad 0 \le t \le \tau,\]

where \(\tau_r\) is ramp_duration and \(\tau\) is duration.

Parameters:
  • duration (float) – Total pulse duration in ns. Must be > 0.

  • ramp_duration (float) – Duration of the linear rise in ns. Must satisfy 0 < ramp_duration <= duration.

  • amplitude (float) – Peak amplitude \(A\) (default 1.0).

Notes

For an adiabatic ramp into a Kerr-cat qubit, choose ramp_duration long compared to 1 / (2 * K) (the inverse gap at the bifurcation point). See Grimm et al., Nature 584, 205 (2020).

The waveform is JAX-traceable: ramp_duration and amplitude may be JAX tracers so the ramp parameters are differentiable.

Examples

>>> from quchip.control.envelopes import LinearRamp
>>> ramp = LinearRamp(duration=60.0, ramp_duration=50.0, amplitude=4.0)
>>> import numpy as np
>>> t = np.array([0.0, 25.0, 50.0, 55.0])
>>> np.real(ramp.waveform(t)).tolist()
[0.0, 2.0, 4.0, 4.0]
duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
ramp_duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
amplitude: Any = Parameter(default=1.0, positive=False, nonnegative=False, serialize=True, unit=None)
validate()[source]

Reject ramps longer than the pulse (ramp_duration > duration).

Return type:

None

value(t)[source]

Evaluate the linear-ramp envelope at time points t (ns).

Parameters:

t (array-like) – 1-D array of time points in nanoseconds.

Returns:

Complex-valued waveform: rises linearly over ramp_duration, holds constant at amplitude afterward.

Return type:

array

class quchip.control.envelopes.Square(duration, amplitude=1.0, phase=0.0)[source]

Bases: EnvelopeShape

Constant-amplitude pulse with optional global phase.

\[E(t) = A\, e^{i\phi}, \qquad 0 \le t \le \tau.\]
Parameters:
  • duration (float) – Pulse length \(\tau\) in ns.

  • amplitude (float) – Real amplitude \(A\) applied on top of value().

  • phase (float) – Global phase \(\phi\) in radians.

duration: Any = Parameter(default=<object object>, positive=True, nonnegative=False, serialize=True, unit='ns')
amplitude: Any = Parameter(default=1.0, positive=False, nonnegative=False, serialize=True, unit=None)
phase: Any = Parameter(default=0.0, positive=False, nonnegative=False, serialize=True, unit='rad')
value(t)[source]

Evaluate the constant complex envelope at time points t.

Parameters:

t (Any)

Return type:

Any