Configuration Module

The configuration module provides classes and utilities for managing OPX-1000 configurations. The Settings class contains high-level parameters for nuclear spin control, while the other classes define specific configuration elements such as chasis, controller, element, pulse, waveform, and integration weights. Unless modifying the hardware configureation, users will primarily interact with the Settings class and the configuration generator function, config_from_settings().

Settings

class qeg_nmr_qua.config.settings.ExperimentSettings(n_avg=4, pulse_length=1100, pulse_amplitude=0.25, pulse_shape='square', pulse_rise_fall=0.0, rotation_angle=90.0, const_len=100, const_amp=0.03, thermal_reset=4000000000, center_freq=282190100, offset_freq=750, readout_delay=20000, readout_amp=0.01, dwell_time=4000, readout_start=0, readout_end=256000, resonator_relaxation=250000, excitation_length=5000, save_dir=None, res_key='resonator', amp_key='amplifier', helper_key='helper', sw_key='switch', square_key='square', square_pi_key='square_pi', gaussian_key='gaussian', gaussian_square_key='gaussian_square', lowpass_square_key='lowpass_square', tukey_key='tukey')[source]

Bases: object

Container for experiment-specific program parameters and hardware configuration.

This dataclass manages all user-facing settings for NMR experiments on the OPX-1000, including pulse parameters, frequencies, readout configuration, and data handling. All values are stored in standard units (nanoseconds, Hz, amplitude) and converted internally as needed.

Features:

  • Mutable with validation: Settings can be updated atomically with update()

  • Serialization: Convert to/from dictionaries with to_dict() and from_dict()

  • Change notifications: Register callbacks with register_update_callback() to be notified when settings change

  • Atomic updates: All changes are validated before being applied

Parameter Groups:

Pulse Parameters: Core pulse control settings

  • n_avg: Number of signal averages (default: 4)

  • pulse_length: Duration of control pulse in nanoseconds (default: 1.1 µs)

  • pulse_amplitude: Normalized pulse amplitude 0-0.5 (default: 0.25, representing 0.5 Vpp)

  • pulse_shape: Name of pulse shape operation (default: “sqr_pi_half”)

  • pulse_rise_fall: Fraction of pulse length for rise/fall time from 0 to 1 (default: 0.0)

  • rotation_angle: Pulse rotation angle in degrees (default: 90°)

Continuous Wave (CW) Parameters: For continuous wave experiments

  • const_len: Length of continuous wave pulse in nanoseconds (default: 100 ns)

  • const_amp: Amplitude of continuous wave pulse (default: 0.03)

Timing Parameters: Experiment timing and delays

  • thermal_reset: Pre-scan delay for thermal equilibration, in nanoseconds (default: 4 s)

  • readout_delay: Minimum delay before measurement occurs, in nanoseconds (default: 20 µs)

  • dwell_time: Demodulation interval during readout, in nanoseconds (default: 4 µs)

  • readout_start: Start time of readout window, in nanoseconds (default: 0)

  • readout_end: End time of readout window, in nanoseconds (default: 256 µs)

Frequency Parameters: NMR frequency configuration

  • center_freq: Center frequency for NMR in Hz (default: 282.1901 MHz for ¹⁹F)

  • offset_freq: Frequency offset in Hz. This increases by 50-100 Hz every few days (default: 750 Hz)

Resonator Parameters: Resonator excitation settings

  • readout_amp: Readout pulse amplitude, should be small (default: 0.01)

  • excitation_length: Duration of resonator excitation pulse in nanoseconds (default: 5 µs)

  • excitation_amp: Amplitude of resonator excitation (default: 0.03)

Data Handling:

  • save_dir: Directory for saving experimental data (default: None, uses data/ folder)

Configuration Keys: Element names in the OPX configuration

  • res_key: Resonator element name (default: “resonator”)

  • amp_key: Amplifier element name (default: “amplifier”)

  • helper_key: Helper element name (default: “helper”)

  • sw_key: Switch control element name (default: “switch”)

  • sqr_pi_half_key: π/2 pulse operation name (default: “sqr_pi_half”)

  • gaus_pi_half_key: Gaussian π/2 pulse operation name (default: “gaus_pi_half”)

  • gaus_sqr_pi_half_key: Gaussian square pulse operation name (default: “gaus_sqr_pi_half”)

Validation:

All settings are validated on instantiation and update:

  • n_avg must be an integer >= 1

  • pulse_length must be >= 64 ns

  • pulse_amplitude must be in range [-0.5, 0.5]

  • pulse_rise_fall must be in range [0, 1]

  • readout_delay must be >= 5 µs

  • Frequency must be in valid OPX range: 0 <= (center_freq - offset_freq) < 750 MHz

n_avg: int = 4
pulse_length: int = 1100
pulse_amplitude: float = 0.25
pulse_shape: str = 'square'
pulse_rise_fall: float = 0.0
rotation_angle: float = 90.0
const_len: int = 100
const_amp: float = 0.03
thermal_reset: int = 4000000000
center_freq: int = 282190100
offset_freq: int = 750
readout_delay: int = 20000
readout_amp: float = 0.01
dwell_time: int = 4000
readout_start: int = 0
readout_end: int = 256000
resonator_relaxation: int = 250000
excitation_length: int = 5000
excitation_amp = 0.03
save_dir: Path | str | None = None
res_key: str = 'resonator'
amp_key: str = 'amplifier'
helper_key: str = 'helper'
sw_key: str = 'switch'
square_key: str = 'square'
square_pi_key: str = 'square_pi'
gaussian_key: str = 'gaussian'
gaussian_square_key: str = 'gaussian_square'
lowpass_square_key: str = 'lowpass_square'
tukey_key: str = 'tukey'
validate()[source]

Validate all current settings and raise ValueError if any are invalid.

This method checks all constraints defined for ExperimentSettings:

  • n_avg must be a positive integer

  • pulse_length must be at least 64 ns (4 clock cycles @ 16 ns each)

  • pulse_amplitude must be in range [-0.5, 0.5] (max ±1 Vpp)

  • readout_delay must be at least 5 µs for ringdown protection

  • Effective frequency (center_freq - offset_freq) must be in OPX range [0, 750 MHz)

  • rotation_angle is normalized to [0, 360) automatically

Raises:

ValueError – If any setting violates the defined constraints.

Return type:

None

update(**kwargs)[source]

Update one or more settings atomically with full validation.

All requested changes are validated together before any are applied, ensuring the settings object remains in a valid state even if update fails. Registered callbacks are invoked only if changes are actually made.

Thread Safety: Not thread-safe. Callers must serialize access if concurrent updates are possible in their environment.

Parameters:

**kwargs – Field names and new values. Unknown fields raise AttributeError.

Returns:

Dictionary of fields that actually changed (name -> new_value).

Empty dict if no changes were made or all new values matched existing ones.

Return type:

dict

Raises:
  • AttributeError – If an unknown setting name is provided.

  • ValueError – If validation fails for any changed setting (no changes applied).

Example

>>> settings = ExperimentSettings()
>>> changes = settings.update(pulse_length=2000, n_avg=8)
>>> # changes now contains {"pulse_length": 2000, "n_avg": 8}
to_dict()[source]

Convert settings to a serializable dictionary.

Returns all user-facing settings as a plain Python dict suitable for JSON serialization or storage. Internal fields (callbacks, locks, etc.) are excluded.

Returns:

A shallow copy of all settings with internal fields excluded.

Return type:

dict

See also

from_dict() to reconstruct settings from a dict.

classmethod from_dict(data)[source]

Create a new ExperimentSettings instance from a dictionary.

Constructs a new instance with validation. Unknown fields in the input dict are silently ignored. All settings are validated before the instance is returned, ensuring consistency with class constraints.

Parameters:

data (Dict[str, Any]) – Dictionary with setting names as keys. Can contain extra keys which will be ignored.

Returns:

A new validated instance.

Return type:

ExperimentSettings

Raises:
  • ValueError – If any settings in the dict violate validation constraints.

  • TypeError – If any setting value is of an incompatible type.

See also

to_dict() to convert an instance to a dict.

Example

>>> data = {"n_avg": 16, "pulse_length": 2000, "extra_field": "ignored"}
>>> settings = ExperimentSettings.from_dict(data)
register_update_callback(fn)[source]

Register a callback to be notified when settings change.

The callback will be invoked each time settings are updated via update(). The callback signature is fn(self, changes_dict) where changes_dict contains the field names and new values.

Exception Handling: Callback exceptions are caught and suppressed to prevent failures from propagating to the caller. Consider logging exceptions if needed.

Parameters:

fn (Callable[[ExperimentSettings, Dict[str, Any]], None]) – A callable with signature (self: ExperimentSettings, changes: Dict[str, Any]) -> None.

Raises:

TypeError – If fn is not callable.

Return type:

None

See also

unregister_update_callback() to remove a callback.

Example

>>> def on_settings_change(settings, changes):
...     print(f"Settings changed: {changes}")
>>> settings = ExperimentSettings()
>>> settings.register_update_callback(on_settings_change)
>>> settings.update(n_avg=10)  # Prints: Settings changed: {'n_avg': 10}
unregister_update_callback(fn)[source]

Unregister a previously registered callback.

Removes the callback from the list of callbacks to be invoked on updates. If the callback was not registered, this method does nothing (no error).

Parameters:

fn (Callable[[ExperimentSettings, Dict[str, Any]], None]) – The callback function to unregister. Must be the same object that was passed to register_update_callback().

Return type:

None

See also

register_update_callback() to register a callback.

Example

>>> def on_change(settings, changes):
...     pass
>>> settings = ExperimentSettings()
>>> settings.register_update_callback(on_change)
>>> settings.unregister_update_callback(on_change)
copy()[source]

Create a shallow copy of these settings.

Creates a new independent instance with the same field values. Callbacks are not copied (the new instance starts with no callbacks). Modifications to the copy do not affect the original.

Returns:

A new instance with identical settings.

Return type:

ExperimentSettings

Example

>>> settings1 = ExperimentSettings(n_avg=8)
>>> settings2 = settings1.copy()
>>> settings2.update(n_avg=16)
>>> settings1.n_avg  # Still 8
8
rf_freq()[source]

Calculate the effective RF (radio frequency) in MHz.

Computes the actual RF frequency used by the OPX by subtracting the frequency offset from the center frequency. This accounts for any frequency calibration adjustments stored in offset_freq.

Returns:

The effective RF frequency in MHz.

Return type:

int

Example

>>> settings = ExperimentSettings(center_freq=282_190_100, offset_freq=75_000)
>>> settings.rf_freq()
282_115_100
__init__(n_avg=4, pulse_length=1100, pulse_amplitude=0.25, pulse_shape='square', pulse_rise_fall=0.0, rotation_angle=90.0, const_len=100, const_amp=0.03, thermal_reset=4000000000, center_freq=282190100, offset_freq=750, readout_delay=20000, readout_amp=0.01, dwell_time=4000, readout_start=0, readout_end=256000, resonator_relaxation=250000, excitation_length=5000, save_dir=None, res_key='resonator', amp_key='amplifier', helper_key='helper', sw_key='switch', square_key='square', square_pi_key='square_pi', gaussian_key='gaussian', gaussian_square_key='gaussian_square', lowpass_square_key='lowpass_square', tukey_key='tukey')

Configuration from Settings

qeg_nmr_qua.config.config_from_settings.cfg_from_settings(settings)[source]

Create an OPXConfig object from ExperimentSettings. This function closesly reproduces the config_building.py example, as of 12/3/2025.

Return type:

OPXConfig

Chassis Configuration

OPX-1000 Configuration Module.

This module provides configuration utilities for the OPX-1000 LF-FEM for solid state NMR experiments.

class qeg_nmr_qua.config.config.OPXConfig(qop_ip='192.168.88.253', cluster='lex', controllers=<factory>, elements=<factory>, pulses=<factory>, waveforms=<factory>, digital_waveforms=<factory>, integration_weights=<factory>)[source]

Bases: object

Complete configuration for the OPX-1000 low-frequency front-end module.

This is the main configuration class that aggregates all sub-configurations needed to operate the OPX-1000 for NMR experiments. It manages controllers, elements (physical connections), pulses, waveforms, digital waveforms, and integration weights.

Connection Settings:

  • qop_ip: IP address of the Quantum Orchestration Platform (default: “192.168.88.253”)

  • cluster: Name of the OPX cluster to use (default: “lex”)

Configuration Components:

Each component is a nested configuration object:

  • controllers: ControllerConfig - Hardware controllers (analog/digital I/O)

  • elements: ElementConfig - Physical elements (resonators, amplifiers, etc.)

  • pulses: PulseConfig - Pulse definitions (control and measurement)

  • waveforms: AnalogWaveformConfig - Analog waveform shapes

  • digital_waveforms: DigitalWaveformConfig - Digital marker waveforms

  • integration_weights: IntegrationWeights - Integration weight sets for demodulation

Serialization:

Use to_dict() and from_dict() for programmatic serialization, or use save_to_file() and load_from_file() for JSON file I/O.

OPX Format:

Use to_opx_config() to generate the configuration in OPX-compatible format for passing to the Quantum Orchestration Platform.

Example

>>> config = OPXConfig(qop_ip="192.168.1.100")
>>> config.elements.add_element("resonator", frequency=282.1901e6)
>>> opx_config_dict = config.to_opx_config()
qop_ip: str = '192.168.88.253'
cluster: str = 'lex'
controllers: ControllerConfig
elements: ElementConfig
pulses: PulseConfig
waveforms: AnalogWaveformConfig
digital_waveforms: DigitalWaveformConfig
integration_weights: IntegrationWeights
to_dict()[source]

Convert the OPX configuration to a dictionary.

Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

OPXConfig

save_to_file(filepath)[source]

Save the OPXConfig to a JSON file at filepath.

Return type:

None

classmethod load_from_file(filepath)[source]

Load an OPXConfig from a JSON file at filepath.

Return type:

OPXConfig

to_opx_config()[source]

Convert to OPX configuration format.

Return type:

dict[str, Any]

add_controller(controller_config)[source]

Add a controller configuration.

add_element(name, element)[source]
add_pulse(name, pulse)[source]

Add a pulse configuration.

add_control_pulse(pulse_name, element_name, amplitude, length, waveform)[source]

Add a control pulse configuration.

add_waveform(name, waveform)[source]

Add an analog waveform configuration.

add_digital_waveform(name, state=0, length=0)[source]

Add a digital waveform (marker) configuration.

add_integration_weight(name, length, real_weight=1, imag_weight=0)[source]

Add an integration weight configuration.

__init__(qop_ip='192.168.88.253', cluster='lex', controllers=<factory>, elements=<factory>, pulses=<factory>, waveforms=<factory>, digital_waveforms=<factory>, integration_weights=<factory>)

Controller Configuration

OPX-1000 Controller Configuration Module.

This module provides configuration utilities for the OPX-1000 LF-FEM for solid state NMR experiments.

class qeg_nmr_qua.config.controller.AnalogOutput(offset=0.0, sampling_rate=1000000000, output_mode='direct')[source]

Bases: object

Configuration for an analog output channel of the OPX.

Analog outputs are used to generate control signals (pulses, RF signals, etc.) for driving quantum elements. Each output has an independent offset, sampling rate, and output mode.

offset

DC offset applied to the output in volts (default: 0.0). Used for calibration and bias adjustment.

Type:

float

sampling_rate

Output sampling rate in Hz (default: 1 GHz). Typically 1e9 for high-speed operations.

Type:

int

output_mode

Output mode, typically “direct” for direct waveform output (default: “direct”).

Type:

str

offset: float = 0.0
sampling_rate: int = 1000000000
output_mode: str = 'direct'
to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

AnalogOutput

to_opx_config()[source]
Return type:

dict[str, Any]

__init__(offset=0.0, sampling_rate=1000000000, output_mode='direct')
class qeg_nmr_qua.config.controller.AnalogInput(offset=0.0, gain_db=0, sampling_rate=1000000000)[source]

Bases: object

Configuration for an analog input channel of the OPX.

Analog inputs measure signals from quantum elements (e.g., resonator readout). Each input has independent offset, gain, and sampling rate for signal conditioning.

offset

Input offset in volts (default: 0.0). Compensates for DC bias in the measurement.

Type:

float

gain_db

Programmable gain amplifier setting in dB (default: 0). Amplifies or attenuates the input signal.

Type:

int

sampling_rate

Input sampling rate in Hz (default: 1 GHz). Must match the acquisition requirements.

Type:

int

offset: float = 0.0
gain_db: int = 0
sampling_rate: int = 1000000000
to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

AnalogInput

to_opx_config()[source]
Return type:

dict[str, Any]

__init__(offset=0.0, gain_db=0, sampling_rate=1000000000)
class qeg_nmr_qua.config.controller.DigitalIO(name='TTL', direction='output', inverted=False)[source]

Bases: object

Configuration for digital input/output lines.

Digital I/O is used for control signals like RF switching, marker pulses, and external triggering. Digital signals are binary (0 or 1) and can be synchronized with analog operations.

name

Descriptive name for this digital line (default: “TTL”). Example names: “RF_switch”, “marker1”, “trigger”.

Type:

str

direction

Signal direction, either “input” or “output” (default: “output”). Determines whether this line reads or drives digital signals.

Type:

str

inverted

Whether the signal logic is inverted (default: False). If True, a logical 0 is represented as a high voltage and vice versa.

Type:

bool

name: str = 'TTL'
direction: str = 'output'
inverted: bool = False
to_opx_config()[source]
Return type:

dict[str, Any]

to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

DigitalIO

__init__(name='TTL', direction='output', inverted=False)
class qeg_nmr_qua.config.controller.FEModuleConfig(slot=1, fem_type='LF', analog_outputs=<factory>, analog_inputs=<factory>, digital_outputs=<factory>)[source]

Bases: object

Configuration for the OPX-1000 controller.

slot: int = 1
fem_type: str = 'LF'
analog_outputs: dict[int, AnalogOutput]
analog_inputs: dict[int, AnalogInput]
digital_outputs: dict[int, DigitalIO]
add_digital_output(port, name='TTL', inverted=False)[source]

Add a digital output channel configuration.

Return type:

None

add_analog_output(port, offset=0.0, sampling_rate=1000000000, output_mode='direct')[source]

Add an analog output channel configuration.

Return type:

None

add_analog_input(port, offset=0.0, gain_db=0, sampling_rate=1000000000)[source]

Add an analog input channel configuration.

Return type:

None

to_opx_config()[source]
Return type:

dict[str, Any]

to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

FEModuleConfig

__init__(slot=1, fem_type='LF', analog_outputs=<factory>, analog_inputs=<factory>, digital_outputs=<factory>)
class qeg_nmr_qua.config.controller.ControllerConfig(model='opx1000', controller_name='con1', modules=<factory>)[source]

Bases: object

Overall OPX Chassis configuration.

model: str = 'opx1000'
controller_name: str = 'con1'
modules: dict[int, FEModuleConfig]
add_module(chasis_slot, module)[source]

Add a front-end module configuration.

Return type:

None

to_opx_config()[source]
Return type:

dict[str, Any]

to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

ControllerConfig

__init__(model='opx1000', controller_name='con1', modules=<factory>)

Element Configuration

OPX-1000 Element Configuration Module.

This module provides configuration utilities for the OPX-1000 LF-FEM for solid state NMR experiments.

class qeg_nmr_qua.config.element.digitalElementConfig(port, delay=0, buffer=0)[source]

Bases: object

Configuration for a digital element’s paired input/output connection.

Specifies how a digital marker or trigger signal is routed between the OPX and a physical element (like an RF switch or frequency marker).

port

Physical port specification as (controller_name, chassis_slot, port_number). Example: (“con1”, 1, 1) specifies controller 1, chassis slot 1, digital port 1.

Type:

tuple[str, int, int]

delay

Delay applied to the digital signal in nanoseconds (default: 0). Useful for synchronization with analog signals.

Type:

int

buffer

Buffer/timing margin in nanoseconds (default: 0). Provides timing headroom for signal stabilization.

Type:

int

port: tuple[str, int, int]
delay: int = 0
buffer: int = 0
to_dict()[source]
Return type:

dict[str, Any]

to_opx_config()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

digitalElementConfig

__init__(port, delay=0, buffer=0)
class qeg_nmr_qua.config.element.Element(name, frequency, analog_input, analog_output, digital_inputs=<factory>, operations=<factory>, time_of_flight=0.0, sticky=False)[source]

Bases: object

Configuration for a physical quantum element connected to the OPX-1000.

An Element represents a physical connection to the OPX, such as a resonator, amplifier, or signal source. It aggregates analog I/O ports, digital control lines, and associated pulse operations.

Port Mapping:

In OPX convention:

  • analog_input: The OPX’s output port that drives this element

  • analog_output: The OPX’s input port that reads from this element

  • This naming convention reflects the signal direction relative to the element, not the OPX.

name

Unique identifier for this element (e.g., “resonator”, “amplifier”).

Type:

str

frequency

Intermediate frequency (IF) of this element in Hz. For direct sampling, this is the actual RF frequency.

Type:

float

analog_input

Port specification for OPX output as (controller_name, chassis_slot, port_number).

Type:

tuple[str, int, int]

analog_output

Port specification for OPX input as (controller_name, chassis_slot, port_number).

Type:

tuple[str, int, int]

digital_inputs

Mapping of operation names to digital control configurations (default: empty).

Type:

dict[str, digitalElementConfig]

operations

Mapping of operation names to pulse config names (default: empty). Example: {“pi_half”: “pi_half_pulse”}.

Type:

dict[str, str]

time_of_flight

Signal propagation delay in nanoseconds (default: 0.0). Delay between when a pulse is output and when the response is received.

Type:

float

sticky

Whether this element retains state between operations (default: False). If True, the element state persists after pulse completion.

Type:

bool

name: str
frequency: float
analog_input: tuple[str, int, int]
analog_output: tuple[str, int, int]
digital_inputs: dict[str, digitalElementConfig]
operations: dict[str, str]
time_of_flight: float = 0.0
sticky: bool = False
add_digital_input(operation, controller_name, chasis_slot, port_number, delay=0, buffer=0)[source]

Add a digital input configuration for a specific operation.

Parameters:
  • operation (str) – Name of the digital operation (e.g “marker”).

  • controller_name (str) – Name of the OPX controller.

  • chasis_slot (int) – Physical slot number in chassis.

  • port_number (int) – Digital port number on the OPX.

  • delay (int) – Delay in nanoseconds.

  • buffer (int) – Buffer time in nanoseconds.

Return type:

None

to_opx_config()[source]

Convert the Element configuration to a dictionary.

Return type:

dict[str, Any]

to_dict()[source]
Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

Element

__init__(name, frequency, analog_input, analog_output, digital_inputs=<factory>, operations=<factory>, time_of_flight=0.0, sticky=False)
class qeg_nmr_qua.config.element.ElementConfig(elements=<factory>)[source]

Bases: object

Container for multiple Element configurations.

elements: dict[str, Element]
add_element(name, element)[source]

Add an element configuration.

Parameters:
  • name (str) – Name of the element.

  • frequency – Operating frequency in Hz.

  • analog_input – Tuple specifying the analog input (controller_name, chasis_slot, port_number).

  • analog_output – Tuple specifying the analog output (controller_name, chasis_slot, port_number).

  • time_of_flight – Delay between output and input signals in nanoseconds.

  • sticky – Whether the element retains state between operations.

Return type:

None

to_dict()[source]

Convert the Element configurations to a dictionary.

Return type:

dict[str, Any]

to_opx_config()[source]

Convert the Element configurations to OPX configuration format.

Return type:

dict[str, Any]

classmethod from_dict(d)[source]
Return type:

ElementConfig

__init__(elements=<factory>)

Pulse Configuration

class qeg_nmr_qua.config.pulse.ControlPulse(length=0, waveform='zero_wf', digital_marker='OFF')[source]

Bases: object

Configuration for a control (drive) pulse.

Defines a pulse used to drive/manipulate quantum states. Control pulses output a waveform to an element and may optionally trigger a digital marker for synchronization or external monitoring.

Current Limitations:

  • Single waveform only (no waveform mixing)

  • See MeasPulse for measurement pulses with integration.

length

Pulse duration in nanoseconds (default: 0). Must be a multiple of 4 ns (1 clock cycle).

Type:

int

waveform

Name of the waveform to play (default: “zero_wf”). Must be defined in the waveform configuration.

Type:

str

digital_marker

Whether to set a digital marker during pulse execution (default: “OFF”). “ON” activates the marker, “OFF” deactivates it. Use None for no marker.

Type:

Literal[“ON”, “OFF”] | None

length: int = 0
waveform: str = 'zero_wf'
digital_marker: Literal['ON', 'OFF'] | None = 'OFF'
to_opx_config()[source]
Return type:

Dict[str, Any]

to_dict()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

ControlPulse

__init__(length=0, waveform='zero_wf', digital_marker='OFF')
class qeg_nmr_qua.config.pulse.MeasPulse(length=1000, waveform='readout_wf', integration_weights=<factory>, digital_marker=None)[source]

Bases: object

Configuration for a measurement pulse.

Defines a pulse used for measurement/readout of quantum states. Measurement pulses output a waveform, acquire data, and apply integration weights for demodulation and signal extraction. Optionally triggers a digital marker.

Current Limitations:

  • Single waveform only (no waveform mixing)

  • See ControlPulse for simple control pulses.

Demodulation:

Integration weights are applied to the acquired signal to extract in-phase (I) and quadrature (Q) components. Common weight sets include cosine/sine, rotated, and optimized variants.

length

Measurement duration in nanoseconds (default: 1000). Must be a multiple of 4 ns (1 clock cycle).

Type:

int

waveform

Name of the readout waveform (default: “readout_wf”). Must be defined in the waveform configuration.

Type:

str

integration_weights

Mapping of demodulation weights for extracting I/Q components (default: default mapping).

Type:

IntegrationWeightMapping

digital_marker

Whether to trigger a digital marker during measurement (default: None). None means no marker action.

Type:

Literal[“ON”, “OFF”] | None

length: int = 1000
waveform: str = 'readout_wf'
integration_weights: IntegrationWeightMapping
digital_marker: Literal['ON', 'OFF'] | None = None
to_opx_config()[source]
Return type:

Dict[str, Any]

to_dict()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

MeasPulse

__init__(length=1000, waveform='readout_wf', integration_weights=<factory>, digital_marker=None)
class qeg_nmr_qua.config.pulse.PulseConfig(pulses=<factory>)[source]

Bases: object

Configuration for a pulse, which can be either a control pulse or a measurement.

pulses: dict[str, ControlPulse | MeasPulse]
add_pulse(name, pulse)[source]

Add a pulse configuration from one of the pulse types.

Parameters:
  • name (str) – Name of the pulse.

  • pulse (ControlPulse | MeasPulse) – ControlPulse or MeasPulse instance.

Return type:

None

add_control_pulse(name, length, waveform='const', digital_marker='OFF')[source]

Add a control pulse configuration.

Parameters:
  • name (str) – Name of the control pulse.

  • length (int) – Pulse length in nanoseconds.

  • waveform (str) – Waveform name.

  • digital_marker (Optional[Literal['ON', 'OFF']]) – Whether to set the digital marker during the pulse.

Return type:

None

add_measurement_pulse(name, length, waveform='readout_wf', digital_marker=None, integration_weights=<IntegrationWeightMapping cos=cosine_weights sin=sine_weights opt_cos=opt_cosine_weights>)[source]

Add a measurement pulse configuration.

Parameters:
  • name (str) – Name of the measurement pulse.

  • length (int) – Pulse length in nanoseconds.

  • waveform (str) – Waveform name.

  • integration_weights (IntegrationWeightMapping) – Integration weight mapping.

Return type:

None

to_dict()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

PulseConfig

to_opx_config()[source]
Return type:

Dict[str, Any]

__init__(pulses=<factory>)

Waveform Configuration

class qeg_nmr_qua.config.waveform.AnalogWaveform(sample=0.0)[source]

Bases: object

Configuration for a single analog waveform.

Represents a waveform that can be output on an analog channel. Supports both constant-amplitude waveforms and arbitrary waveforms with sample-by-sample amplitude specification.

sample

Waveform amplitude specification. - If float: Constant waveform with that amplitude (in volts) - If list: Arbitrary waveform with per-sample amplitudes (in volts)

Type:

float | list

sample: float | list = 0.0
to_dict()[source]

It may be better to link to a file when sample is an array.

Return type:

Dict[str, Any]

to_opx_config()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

AnalogWaveform

__init__(sample=0.0)
class qeg_nmr_qua.config.waveform.ArbitraryWaveform(samples=<factory>)[source]

Bases: object

Configuration for an arbitrary (custom) analog waveform.

Represents a shaped waveform defined sample-by-sample. Useful for complex pulse shapes like STIRAP, RAPID, or other optimal control pulses.

samples

List of amplitude values (in volts) for each sample. The waveform is played back in sequence at the OPX sampling rate.

Type:

list[float]

samples: list[float]
to_dict()[source]
Return type:

Dict[str, Any]

to_opx_config()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

ArbitraryWaveform

__init__(samples=<factory>)
class qeg_nmr_qua.config.waveform.DigitalWaveform(state=0, length=0)[source]

Bases: object

Configuration for a digital marker waveform.

Defines a digital (binary) signal that can be used for RF switching, trigger signals, or monitoring pulse execution. The marker holds its specified state for the specified duration, then returns to 0 when the pulse ends.

Timing Behavior:

  • Length 0: Marker holds its state for the entire duration of the associated pulse

  • Length > 0: Marker holds its state for the specified nanoseconds, then returns to 0

state

Digital state (0 or 1). 0 = low/off, 1 = high/on (default: 0).

Type:

int

length

Duration the marker holds its state in nanoseconds (default: 0). Special case: 0 means hold for entire pulse duration.

Type:

int

state: int = 0
length: int = 0
to_opx_config()[source]
Return type:

Dict[str, str]

to_dict()[source]
Return type:

Dict[str, str]

classmethod from_dict(d)[source]
Return type:

DigitalWaveform

__init__(state=0, length=0)
class qeg_nmr_qua.config.waveform.AnalogWaveformConfig(waveforms=<factory>)[source]

Bases: object

Container for analog waveform definitions.

Manages a collection of named analog waveforms. Waveforms are referenced by name in pulse configurations. This design allows arbitrary key names for maximum flexibility.

Waveform Types:

Waveforms can be:

  • Constant amplitude (flat pulse)

  • Arbitrary shaped (custom pulse envelope)

waveforms

Mapping of waveform names to their configurations. Example: {“pi_pulse”: AnalogWaveform(…)}.

Type:

Dict[str, AnalogWaveform]

waveforms: Dict[str, AnalogWaveform]
add_waveform(name, sample=0.0)[source]

Add a waveform to the configuration for defining multiple pulse-types. Pulses are either constant amplitude or arbitrary waveforms. If constant, sample is a float amplitude value. If arbitrary, sample is a list of amplitude values which define the waveform shape, between -1 and 1.

Return type:

None

to_dict()[source]
Return type:

Dict[str, Any]

to_opx_config()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

AnalogWaveformConfig

__init__(waveforms=<factory>)
class qeg_nmr_qua.config.waveform.DigitalWaveformConfig(waveforms=<factory>)[source]

Bases: object

waveforms: Dict[str, DigitalWaveform]
add_waveform(name, state=0, length=0)[source]

Add a digital waveform (marker) to the configuration. A length of 0 means the marker will hold its state for the duration of the pulse it is associated with. If the pulse ends, the marker returns to 0.

Return type:

None

to_dict()[source]
Return type:

Dict[str, Any]

to_opx_config()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

DigitalWaveformConfig

__init__(waveforms=<factory>)

Integration Weights

class qeg_nmr_qua.config.integration.IntegrationWeightMapping(cos='cosine_weights', sin='sine_weights', minus_sin='minus_sine_weights', rotated_cos='rotated_cosine_weights', rotated_sin='rotated_sine_weights', rotated_minus_sin='rotated_minus_sine_weights', opt_cos='opt_cosine_weights', opt_sin='opt_sine_weights', opt_minus_sin='opt_minus_sine_weights')[source]

Bases: object

Mapping of demodulation weight names to integration weight set identifiers.

This class defines the naming convention for different integration weight sets used during measurement. Each attribute maps a weight type to its identifier in the integration weights configuration.

Standard Weight Sets:

  • cos, sin, minus_sin: Standard cosine/sine demodulation

  • rotated_cos, rotated_sin, rotated_minus_sin: Rotated basis demodulation

  • opt_cos, opt_sin, opt_minus_sin: Optimized weights for specific experiments

cos

Cosine weight set name (default: “cosine_weights”)

Type:

str

sin

Sine weight set name (default: “sine_weights”)

Type:

str

minus_sin

Negative sine weight set name (default: “minus_sine_weights”)

Type:

str

rotated_cos

Rotated cosine weight set (default: “rotated_cosine_weights”)

Type:

str

rotated_sin

Rotated sine weight set (default: “rotated_sine_weights”)

Type:

str

rotated_minus_sin

Rotated negative sine weight set (default: “rotated_minus_sine_weights”)

Type:

str

opt_cos

Optimized cosine weight set (default: “opt_cosine_weights”)

Type:

str

opt_sin

Optimized sine weight set (default: “opt_sine_weights”)

Type:

str

opt_minus_sin

Optimized negative sine weight set (default: “opt_minus_sine_weights”)

Type:

str

cos: str = 'cosine_weights'
sin: str = 'sine_weights'
minus_sin: str = 'minus_sine_weights'
rotated_cos: str = 'rotated_cosine_weights'
rotated_sin: str = 'rotated_sine_weights'
rotated_minus_sin: str = 'rotated_minus_sine_weights'
opt_cos: str = 'opt_cosine_weights'
opt_sin: str = 'opt_sine_weights'
opt_minus_sin: str = 'opt_minus_sine_weights'
to_dict()[source]
Return type:

Dict[str, str]

to_opx_config()[source]
Return type:

Dict[str, str]

classmethod from_dict(d)[source]
Return type:

IntegrationWeightMapping

__init__(cos='cosine_weights', sin='sine_weights', minus_sin='minus_sine_weights', rotated_cos='rotated_cosine_weights', rotated_sin='rotated_sine_weights', rotated_minus_sin='rotated_minus_sine_weights', opt_cos='opt_cosine_weights', opt_sin='opt_sine_weights', opt_minus_sin='opt_minus_sine_weights')
class qeg_nmr_qua.config.integration.IntegrationWeight(length=0, real_weight=1, imag_weight=0)[source]

Bases: object

Configuration for a single integration weight set for demodulation.

Defines how to demodulate and integrate an acquired signal. During measurement, the acquired signal is multiplied by cosine and sine reference signals (weighted by these parameters) and integrated over the measurement duration to extract in-phase (I) and quadrature (Q) components.

length

Integration window duration in nanoseconds (default: 0). Typically matches the measurement pulse length.

Type:

int

real_weight

Weight factor for cosine (I) component (default: 1.0). Scales the in-phase signal amplitude.

Type:

float

imag_weight

Weight factor for sine (Q) component (default: 0.0). Scales the quadrature signal amplitude.

Type:

float

length: int = 0
real_weight: float = 1
imag_weight: float = 0
to_opx_config()[source]
Return type:

Dict[str, Any]

to_dict()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

IntegrationWeight

__init__(length=0, real_weight=1, imag_weight=0)
class qeg_nmr_qua.config.integration.IntegrationWeights(weights=<factory>)[source]

Bases: object

Container for all integration weight sets used in the experiment.

Manages a collection of named integration weight configurations. During measurement, these weights are applied to demodulate and integrate the acquired signals, extracting I/Q components for data analysis.

weights

Mapping of weight set names to their configurations (default: empty).

Type:

dict[str, IntegrationWeight]

weights: dict[str, IntegrationWeight]
add_weight(name, length, real_weight=1, imag_weight=0)[source]

Add an integration weight set to the configuration.

Return type:

None

to_dict()[source]
Return type:

Dict[str, Any]

to_opx_config()[source]
Return type:

Dict[str, Any]

classmethod from_dict(d)[source]
Return type:

IntegrationWeights

__init__(weights=<factory>)