Quickstart

This guide shows you how to go from a Qiskit 2.0 scheduled circuit to sample-precise I/Q waveforms and interactive pulse sheets in minutes.

Prerequisites

  • Python 3.11+

  • Qiskit 2.5+ (pip install "qiskit>=2.5.0,<3")

  • qiskit-waveform-sim (pip install qiskit-waveform-sim)

Basic Workflow

  1. Create a backend and circuit

from qiskit import QuantumCircuit
from qiskit.providers.fake_provider import GenericBackendV2

backend = GenericBackendV2(num_qubits=2, seed=42)

qc = QuantumCircuit(2, 2)
qc.h(0)                    # Decomposes to rz(π/2) → sx → rz(π/2)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
  1. Transpile and schedule

from qiskit.transpiler import generate_preset_pass_manager

pm = generate_preset_pass_manager(
    optimization_level=1,
    backend=backend,
    scheduling_method="alap"
)
scheduled_qc = pm.run(qc)
  1. Compile the waveform simulator

from qiskit_waveform_sim import TargetWaveformSimulator

sim = TargetWaveformSimulator(backend.target).compile(scheduled_qc)
  1. Extract sample-precise I/Q snippets

# Get drive channel 0 waveform (first 2500 dt)
d0_snip = sim.get_snippet("d0", start_dt=0, length_dt=2500)

# Get cross-resonance channel waveform
cr_snip = sim.get_snippet("u(0,1)", start_dt=0, length_dt=2500)

# Access waveform data
print(f"Time points: {len(d0_snip.time_ns)}")
print(f"I component: {d0_snip.wave.real[:5]}")
print(f"Q component: {d0_snip.wave.imag[:5]}")
print(f"Frame phase: {d0_snip.phase_rad[:5]}")
  1. Visualize interactively

from qiskit_waveform_sim.visualization import show_pulse_sheet, show_iq_oscilloscope

# Multi-channel Pulse Sheet (schedule view)
show_pulse_sheet(sim, interactive=True)

# Sample-precise I/Q Oscilloscope (waveform view)
show_iq_oscilloscope(sim, "d0", start_dt=0, length_dt=1000, interactive=True)

# Combined view
from qiskit_waveform_sim.visualization import create_combined_view
fig = create_combined_view(sim, "d0", start_dt=0, length_dt=1000)
fig.show()

Custom Pulse Annotations

Attach custom pulse shapes to specific gates using Qiskit 2.0’s BoxOp and Annotation API:

from qiskit_waveform_sim import PulseEnvelopeAnnotation

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)

# Override SX gate with custom high-beta DRAG pulse
with qc.box(
    duration=160,
    unit="dt",
    annotations=[PulseEnvelopeAnnotation(shape="drag", amp=0.55, beta=0.25, sigma_ratio=0.2)]
):
    qc.sx(0)

qc.measure([0, 1], [0, 1])

# Transpile, schedule, and compile as before...
# The custom annotation will be automatically applied

Export to OpenQASM 3

Serialize circuits with pulse annotations to OpenQASM 3:

from qiskit_waveform_sim import PulseAnnotationSerializer
from qiskit import qasm3

qasm3_str = qasm3.dumps(
    scheduled_qc,
    annotation_handlers={"pulse_sim.envelope": PulseAnnotationSerializer()}
)
print(qasm3_str)

Next Steps