Skip to content

Join a ramp and a hold

Design a pulse that rises from zero, holds its final amplitude and stops. Inspect the time grid before running a one-atom experiment, then compare its excitation probability with a pulse-area prediction. Complete global drive and physical units first. Use the installed environment and run from the repository root.

The ramp rises from 0 to 1.2 rad/us over 0.2 us; the hold lasts 0.1 us. With zero detuning and phase, the Hamiltonian is always proportional to X. Its pulse area is 1.2 × 0.2 / 2 + 1.2 × 0.1 = 0.24 rad. Starting from ground, predict P(1) = sin²(0.24/2) before execution.

Compose compatible segments

"""Design a composed pulse and inspect its lowered waveform samples.

``Waveform.concat`` joins serial segments without inventing a scheduler. This
lesson uses a ramp followed by a hold, then validates that the resulting grid
and duration remain explicit before local simulation.
"""

from __future__ import annotations

import json

from cascaqit import AHSProgram, AtomRegister, MockNeutralAtomTarget, Waveform


def main() -> None:
    """Compose, lower, validate, and execute a two-segment pulse."""
    ramp = Waveform.linear(0.0, 1.2, duration=0.2, waveform_id="ramp")
    hold = Waveform.linear(1.2, 1.2, duration=0.1, waveform_id="hold")
    rabi = ramp.concat(hold, waveform_id="rabi.composed")

    program = (
        AHSProgram(
            AtomRegister.line(count=1, spacing=5.0),
            program_id="lesson.experimentalist.waveform",
        )
        .drive(
            rabi=rabi,
            detuning=Waveform.constant(0.0, duration=0.3),
            phase=0.0,
        )
        .measure()
    )
    target = MockNeutralAtomTarget.v0_1()
    validated = program.validate(target, shots=16)
    result = program.run(shots=0, seed=302, target=target, time_steps=120)
    waveform_ir = program.to_ir().hamiltonian.rabi

    payload = {
        "track": "quantum_experimentalist",
        "level": "foundation",
        "lesson": "waveform_design",
        "facts": {
            "waveform_kind": waveform_ir.kind,
            "times": waveform_ir.times,
            "values": waveform_ir.values,
            "duration": waveform_ir.times[-1],
            "validation_errors": [
                item.code for item in validated.diagnostics if item.severity == "error"
            ],
            "probability_sum": round(sum((result.probabilities or {}).values()), 12),
        },
        "boundaries": {
            "hardware_execution": False,
            "cloud_execution": False,
            "network_accessed": False,
            "credentials_loaded": False,
        },
    }
    print(json.dumps(payload, sort_keys=True))


if __name__ == "__main__":
    main()

Download the full script

python3 examples/user/tracks/quantum_experimentalist/02_foundation_waveform_design_en.py

The hold is written as Waveform.linear(1.2, 1.2, duration=0.1) so that both pieces belong to the linear family. concat() rebases each following segment's time relative to the combined pulse and returns a new waveform. It preserves the source pieces.

{
  "boundaries": {
    "cloud_execution": false,
    "credentials_loaded": false,
    "hardware_execution": false,
    "network_accessed": false
  },
  "facts": {
    "duration": 0.30000000000000004,
    "probability_sum": 1.0,
    "times": [
      0.0,
      0.2,
      0.30000000000000004
    ],
    "validation_errors": [],
    "values": [
      0.0,
      1.2,
      1.2
    ],
    "waveform_kind": "piecewise_linear"
  },
  "lesson": "waveform_design",
  "level": "foundation",
  "track": "quantum_experimentalist"
}

The result is piecewise linear with points near (0, 0), (0.2, 1.2), (0.3, 1.2). A printed duration of 0.30000000000000004 is the ordinary binary floating-point representation of this sum; it is not an extra intended pulse segment.

The script reports normalization. Add print(result.probabilities) in a local copy to check the physical prediction: P(1) ≈ 0.014331. The run uses 120 time steps and zero shots, so it returns probabilities without finite measurement samples. The validation call uses 16 shots to check the program against the mock target; those validation settings do not create samples or override the separate run call.

Pick the representation that matches the control

Representation Meaning between specified times
Constant or piecewise constant Holds a value, allowing steps between segments
Linear or piecewise linear Connects neighboring values with straight lines
Interpolated Uses shape-preserving PCHIP through the supplied samples

This concatenation interface supports matching constant-family or matching linear-family segments. Linear joins must have equal endpoint values. It rejects mixing the constant and linear families, even when a constant hold could be represented mathematically by either. Interpolated segments cannot be concatenated without refitting; define one interpolated waveform over the whole domain instead. See interpolated controls for the supported interface.

Test a design change

  1. Double the hold duration to 0.2 us and update the detuning duration to the new total. Compute the new pulse area and expected excitation probability.
  2. Replace the hold with Waveform.constant(1.2, duration=0.1). Read the error, then restore the compatible linear representation.
  3. Keep a linear hold but start it at 0.7 instead of 1.2. Explain the rejected seam and whether a physical step should instead use a different waveform representation.
Check your reasoning

The longer pulse has area 0.36 rad, giving P(1) = sin²(0.18) ≈ 0.032052. Mixing representations raises AHS_WAVEFORM_CONCAT_FAMILY_MISMATCH; the discontinuous linear join raises AHS_WAVEFORM_CONCAT_LINEAR_SEAM_MISMATCH. A step belongs in an explicitly permitted discontinuous representation and still needs target validation. Matching total duration and finite sample values is necessary, but not sufficient to prove a physical controller can produce the pulse.

This pulse-area shortcut depends on a single rotation axis and zero detuning. With noncommuting controls, timing shape matters beyond total area. Continue with local detuning to separate a waveform's time dependence from its spatial weights.

中文版

SDK 1.0.8a · `8b227bff`