Skip to content

API reference

Auto-generated reference for the qprogram_qdac package: one program class, one mixin, one namespace, four operations, the trigger-position literal, and one capability profile. Names are linked into the guides where a narrative helps.

Program entry points

Two ways to get a QProgram with a typed .qdac namespace. Use the pre-combined class when qdac is the only vendor extension in play, and the mixin when a platform combines several vendor extensions on one program class.

Neither is needed at runtime: importing qprogram_qdac registers the namespace on the base qprogram.QProgram, so program.qdac.set_offset(...) resolves through the dynamic vendor lookup on any program. The typed surface is what editors and type checkers read.

QProgram

Bases: QdacMixin, QProgram

QProgram pre-combined with QdacMixin.

Behaves exactly like qprogram.QProgram, with editor autocomplete for qp.qdac.*.

QdacMixin

Mixin that adds a typed .qdac property to a QProgram subclass.

Combine it with qprogram.QProgram through multiple inheritance, listing one mixin per vendor. qprogram_qdac.QProgram is that combination already made.

qdac property

qdac: QdacNamespace

This program's typed QDAC namespace.

The first access builds a QdacNamespace bound to the program and stores it on the instance, so every later access hands back the same object.

Vendor namespace

QdacNamespace is the builder surface. Each method constructs one operation and appends it to the program's active block.

QdacNamespace

Bases: VendorNamespace

The QDAC vendor namespace, reached as program.qdac.<operation>().

Available on every QProgram instance once qprogram_qdac is imported. Each method type-checks its arguments through the signature, builds the matching operation, and appends it to whichever block the program has open.

wait_trigger

wait_trigger(bus: str, port: int) -> None

Append a WaitTrigger operation.

Parameters:

  • bus (str) –

    QDAC channel whose trigger input the sequencer listens on.

  • port (int) –

    Trigger input port number on the chassis.

Raises:

  • ValidationError

    If bus is a BusRef from another schema than the one attached to the program.

Source code in src/qprogram_qdac/namespace.py
def wait_trigger(self, bus: str, port: int) -> None:
    """Append a [`WaitTrigger`][qprogram_qdac.WaitTrigger] operation.

    Args:
        bus (str): QDAC channel whose trigger input the sequencer listens on.
        port (int): Trigger input port number on the chassis.

    Raises:
        ValidationError: If ``bus`` is a [`BusRef`][qprogram.BusRef] from another schema than the
            one attached to the program.
    """
    self._append(WaitTrigger(bus=bus, port=port))

set_trigger

set_trigger(
    bus: str,
    duration: int,
    position: TriggerPosition = "start",
    outputs: Iterable[int] = (),
) -> None

Append a SetTrigger operation.

Parameters:

  • bus (str) –

    QDAC channel whose trigger outputs are being configured.

  • duration (int) –

    Trigger-active duration in nanoseconds.

  • position (TriggerPosition, default: 'start' ) –

    Sequence event at which the triggers fire, one of "start", "step", "end", "end_step". Default "start".

  • outputs (Iterable[int], default: () ) –

    Trigger output indices to arm. Any iterable of ints will do: set, list, tuple, generator. Empty by default, which the qdac.empty-trigger-outputs predicate rejects at validation time.

Raises:

  • ValidationError

    If bus is a BusRef from another schema than the one attached to the program.

Source code in src/qprogram_qdac/namespace.py
def set_trigger(
    self,
    bus: str,
    duration: int,
    position: TriggerPosition = "start",
    outputs: Iterable[int] = (),
) -> None:
    """Append a [`SetTrigger`][qprogram_qdac.SetTrigger] operation.

    Args:
        bus (str): QDAC channel whose trigger outputs are being configured.
        duration (int): Trigger-active duration in nanoseconds.
        position (TriggerPosition): Sequence event at which the triggers fire, one of
            ``"start"``, ``"step"``, ``"end"``, ``"end_step"``. Default ``"start"``.
        outputs (Iterable[int]): Trigger output indices to arm. Any iterable of ints will do:
            ``set``, ``list``, ``tuple``, generator. Empty by default, which the
            ``qdac.empty-trigger-outputs`` predicate rejects at validation time.

    Raises:
        ValidationError: If ``bus`` is a [`BusRef`][qprogram.BusRef] from another schema than the
            one attached to the program.
    """
    self._append(SetTrigger(bus=bus, duration=duration, position=position, outputs=outputs))

set_offset

set_offset(bus: str, offset: float | Expression) -> None

Append a SetOffset operation.

Parameters:

  • bus (str) –

    QDAC channel whose DC offset is being set.

  • offset (float | Expression) –

    Target offset in volts. Accepts a literal or any Expression, a loop-bound Variable included.

Raises:

  • ValidationError

    If bus is a BusRef from another schema than the one attached to the program.

Source code in src/qprogram_qdac/namespace.py
def set_offset(self, bus: str, offset: float | Expression) -> None:
    """Append a [`SetOffset`][qprogram_qdac.SetOffset] operation.

    Args:
        bus (str): QDAC channel whose DC offset is being set.
        offset (float | Expression): Target offset in volts. Accepts a literal or any
            [`Expression`][qprogram.Expression], a loop-bound [`Variable`][qprogram.Variable] included.

    Raises:
        ValidationError: If ``bus`` is a [`BusRef`][qprogram.BusRef] from another schema than the
            one attached to the program.
    """
    self._append(SetOffset(bus=bus, offset=offset))

play

play(
    bus: str,
    waveform: Waveform,
    dwell: int = 1,
    delay: int = 0,
    repetitions: int = 1,
    stepped: bool = False,
) -> None

Append a Play operation.

Parameters:

  • bus (str) –

    QDAC channel that emits the waveform.

  • waveform (Waveform) –

    Single-channel Waveform to emit. A str alias is accepted here too, to be resolved later by with_waveforms.

  • dwell (int, default: 1 ) –

    Per-sample dwell time in nanoseconds. Default 1.

  • delay (int, default: 0 ) –

    Delay before the first sample, in nanoseconds. Default 0.

  • repetitions (int, default: 1 ) –

    How many times the envelope is emitted. Default 1.

  • stepped (bool, default: False ) –

    True for discrete-step output, False for continuous interpolated output. Default False.

Raises:

  • ValidationError

    If bus is a BusRef from another schema than the one attached to the program.

Source code in src/qprogram_qdac/namespace.py
def play(  # ruff: ignore[too-many-arguments]  bus, envelope and the engine's four timing controls
    self,
    bus: str,
    waveform: Waveform,
    dwell: int = 1,
    delay: int = 0,
    repetitions: int = 1,
    stepped: bool = False,
) -> None:
    """Append a [`Play`][qprogram_qdac.Play] operation.

    Args:
        bus (str): QDAC channel that emits the waveform.
        waveform (Waveform): Single-channel [`Waveform`][qprogram.waveforms.Waveform] to emit. A
            ``str`` alias is accepted here too, to be resolved later by
            [`with_waveforms`][qprogram.QProgram.with_waveforms].
        dwell (int): Per-sample dwell time in nanoseconds. Default ``1``.
        delay (int): Delay before the first sample, in nanoseconds. Default ``0``.
        repetitions (int): How many times the envelope is emitted. Default ``1``.
        stepped (bool): ``True`` for discrete-step output, ``False`` for continuous
            interpolated output. Default ``False``.

    Raises:
        ValidationError: If ``bus`` is a [`BusRef`][qprogram.BusRef] from another schema than the
            one attached to the program.
    """
    self._append(
        Play(
            bus=bus,
            waveform=waveform,
            dwell=dwell,
            delay=delay,
            repetitions=repetitions,
            stepped=stepped,
        ),
    )

Operations

The AST nodes the namespace appends. They are data plus introspection: typed attributes, and a required_capabilities that reports the tokens a platform must declare to run the node. See Capabilities and profiles for how those tokens are checked.

WaitTrigger

WaitTrigger(bus: str, port: int)

Bases: Operation

A halt on a QDAC channel until an external trigger arrives on one input port.

This is how a QDAC sequence lines up with hardware on another instrument, a qblox sequencer's set_trigger for instance. The QDAC sequencer stops until the trigger fires, and emits no waveform while it waits.

Parameters:

  • bus (str) –

    QDAC channel whose trigger input the sequencer listens on.

  • port (int) –

    Trigger input port number on the chassis, typically 1-based.

Source code in src/qprogram_qdac/operations.py
def __init__(self, bus: str, port: int) -> None:
    self.bus = bus
    self.port = port

required_capabilities

required_capabilities() -> set[str]

Return the single vendor.qdac.wait_trigger token.

Source code in src/qprogram_qdac/operations.py
def required_capabilities(self) -> set[str]:
    """Return the single ``vendor.qdac.wait_trigger`` token."""
    return {"vendor.qdac.wait_trigger"}

SetTrigger

SetTrigger(
    bus: str,
    duration: int,
    position: TriggerPosition = "start",
    outputs: Iterable[int] | str = (),
)

Bases: Operation

An arming of one or more QDAC trigger outputs at a chosen sequence position.

The QDAC chassis carries an internal trigger bus with several output lines. This operation arms a subset of them to fire for duration nanoseconds at a sequence event: sequence start, every step, sequence end, or every step's end.

Parameters:

  • bus (str) –

    QDAC channel whose trigger outputs are being configured.

  • duration (int) –

    Trigger-active duration in nanoseconds.

  • position (TriggerPosition, default: 'start' ) –

    Sequence event at which the triggers fire, one of "start", "step", "end", "end_step". Default "start".

  • outputs (Iterable[int] | str, default: () ) –

    Trigger output indices to arm. Any iterable of ints, or a comma-separated string of them. Empty by default, which the qdac.empty-trigger-outputs predicate rejects at validation time.

Attributes:

  • outputs (tuple[int, ...]) –

    The argument as stored, sorted and deduplicated on the way in, so {2, 1} and [1, 2, 1] produce equal operations.

Raises:

  • TypeError

    If outputs is not iterable, or holds an element of a type int() will not take.

  • ValueError

    If outputs is a string whose comma-separated fields are not integers.

Source code in src/qprogram_qdac/operations.py
def __init__(
    self,
    bus: str,
    duration: int,
    position: TriggerPosition = "start",
    outputs: Iterable[int] | str = (),
) -> None:
    self.bus = bus
    self.duration = duration
    self.position: TriggerPosition = position
    self.outputs: tuple[int, ...] = _normalize_outputs(outputs)

required_capabilities

required_capabilities() -> set[str]

Return the single vendor.qdac.set_trigger token.

Source code in src/qprogram_qdac/operations.py
def required_capabilities(self) -> set[str]:
    """Return the single ``vendor.qdac.set_trigger`` token."""
    return {"vendor.qdac.set_trigger"}

SetOffset

SetOffset(bus: str, offset: float | Expression)

Bases: Operation

A static DC offset on a QDAC channel.

The channel holds offset volts until another operation changes it.

Parameters:

  • bus (str) –

    QDAC channel whose DC offset is being set.

  • offset (float | Expression) –

    Target offset in volts. Accepts a literal or any Expression, a loop-bound Variable included. A swept offset is re-uploaded once per iteration, which is what the qprogram_qdac.profiles constraint on the enclosing loop expresses.

Source code in src/qprogram_qdac/operations.py
def __init__(self, bus: str, offset: float | Expression) -> None:
    self.bus = bus
    self.offset = offset

required_capabilities

required_capabilities() -> set[str]

Return vendor.qdac.set_offset plus the tokens contributed by the offset expression.

Source code in src/qprogram_qdac/operations.py
def required_capabilities(self) -> set[str]:
    """Return ``vendor.qdac.set_offset`` plus the tokens contributed by the ``offset`` expression."""
    from qprogram.protocol import expression_tokens  # ruff: ignore[import-outside-top-level]

    return {"vendor.qdac.set_offset"} | expression_tokens(self.offset)

Play

Play(
    bus: str,
    waveform: Waveform,
    dwell: int = 1,
    delay: int = 0,
    repetitions: int = 1,
    stepped: bool = False,
)

Bases: Operation

An envelope emitted from a QDAC channel's waveform engine.

The channel comes from bus, so the operation routes to that bus's capability slot like every other QDAC operation. The rest of the arguments are the waveform-engine program: the envelope and its timing.

Parameters:

  • bus (str) –

    QDAC channel that emits the waveform.

  • waveform (Waveform) –

    Single-channel Waveform whose envelope is uploaded to the waveform engine. A str alias is accepted here too, to be resolved later by with_waveforms.

  • dwell (int, default: 1 ) –

    Per-sample dwell time in nanoseconds, which sets the emission rate. Default 1.

  • delay (int, default: 0 ) –

    Delay in nanoseconds between sequence start and the first sample. Default 0.

  • repetitions (int, default: 1 ) –

    How many times the engine emits the envelope in total, the first emission included. Default 1.

  • stepped (bool, default: False ) –

    True to step through the samples discretely, re-arming the DAC for each one, False for continuous interpolated output. Default False.

Source code in src/qprogram_qdac/operations.py
def __init__(  # ruff: ignore[too-many-arguments]  bus, envelope and the engine's four timing controls
    self,
    bus: str,
    waveform: Waveform,
    dwell: int = 1,
    delay: int = 0,
    repetitions: int = 1,
    stepped: bool = False,
) -> None:
    self.bus = bus
    self.waveform = waveform
    self.dwell = dwell
    self.delay = delay
    self.repetitions = repetitions
    self.stepped = stepped

required_capabilities

required_capabilities() -> set[str]

Return vendor.qdac.play plus the tokens describing the waveform.

waveform.single is always required, since the engine drives one channel. A registered waveform class contributes its per-class token from qprogram.protocol.waveform_token on top, waveform.ramp for a Ramp for instance.

Source code in src/qprogram_qdac/operations.py
def required_capabilities(self) -> set[str]:
    """Return ``vendor.qdac.play`` plus the tokens describing the waveform.

    ``waveform.single`` is always required, since the engine drives one channel. A registered
    waveform class contributes its per-class token from [`qprogram.protocol.waveform_token`][]
    on top, ``waveform.ramp`` for a [`Ramp`][qprogram.waveforms.Ramp] for instance.
    """
    from qprogram.protocol import waveform_token  # ruff: ignore[import-outside-top-level]

    caps = {"vendor.qdac.play", "waveform.single"}
    tok = waveform_token(self.waveform)
    if tok is not None:
        caps.add(tok)
    return caps

TriggerPosition module-attribute

TriggerPosition = Literal[
    "start", "step", "end", "end_step"
]

The four trigger-fire positions the QDAC sequencer recognizes.

  • "start": the trigger fires when the sequence begins.
  • "step": the trigger fires at the start of every step of a stepped sequence.
  • "end": the trigger fires when the sequence finishes.
  • "end_step": the trigger fires at the end of every step.

Capability profile

The bundle a platform attaches to every qdac-driven bus: the four vendor tokens, the single-channel waveforms the engine can render, the one waveform-engine limit, and the two predicates that turn a swept parameter into a host-side loop and an empty trigger-output set into an error.

QDAC_DEFAULT_V1 module-attribute

QDAC_DEFAULT_V1 = Profile(
    name="qdac-default-v1",
    version=(0, 1, 0),
    extends=None,
    capabilities=_BUS_OPS | _WAVEFORMS,
    limits={"min_dwell_ns": 100},
    predicates=(
        _qdac_op_with_swept_var_is_host_only,
        _set_trigger_outputs_required,
    ),
    vendor_versions={"qdac": (0, 1, 0)},
)

The default QDAC bus-level capability profile.

Because qdac has no FPGA, a platform fills the host half of each qdac-driven bus slot with this profile and leaves the rt half empty. Every qdac operation is then host-side by design, and a loop whose operations are all qdac classifies as host-side through op-children consensus alone. A platform that does fill both halves gets the same outcome for swept programs, this time from the profile's own DomainConstraint predicate.

The profile holds every qdac vendor token (wait_trigger, set_trigger, set_offset, play) plus the single-channel waveforms the engine renders. The platform-level slot of a qdac platform's PlatformCapabilities uses the core-shipped qprogram-base-v1 directly: qdac has no bus-less operations, so it contributes nothing at that level.