Source code for qblox_instruments.types

# ----------------------------------------------------------------------------
# Description    : Qblox instruments instrument and module types
# Git repository : https://gitlab.com/qblox/packages/software/qblox_instruments.git
# Copyright (C) Qblox BV (2020)
# ----------------------------------------------------------------------------


# -- include -----------------------------------------------------------------

import re
import sys
from collections.abc import Collection, Iterable
from dataclasses import dataclass
from enum import Enum, IntEnum, unique
from typing import Any, Protocol, TypedDict, Union, runtime_checkable

if sys.version_info >= (3, 11):
    from typing import NotRequired
else:
    from typing_extensions import NotRequired

from qcodes import DelegateParameter

# -- definitions -------------------------------------------------------------

VersionTuple = tuple[int, int, int]


[docs] class DebugLevel(IntEnum): """Debug level for communication with the instrument.""" MINIMAL_CHECK = 0 """ Check for version mismatch between qblox-instruments and the firmware. Perform a system error check only when starting or stopping sequencers. """ ERROR_CHECK = 1 """Do not check for a version mismatch. Perform an error check on every SCPI call.""" NO_CHECK = 2 """Do not check for a version mismatch or system errors.""" VERSION_AND_ERROR_CHECK = 3 """ Check for version mismatch between qblox-instruments and the firmware. Perform an error check on every SCPI call. """
[docs] class TypeEnum(Enum): """ Type base class that arranges child enum string representations. """ def __repr__(self) -> str: return "<{}.{}>".format(str(type(self)).split("'")[1], self.name) def __str__(self) -> str: return str(self.value) def __eq__(self, other: Any) -> bool: if type(self) is type(other): return str(self) == str(other) elif other in [str(val) for val in type(self)]: return str(self) == other else: raise KeyError(f"{other} is not of type {type(self)}") def __key__(self) -> str: return str(self) def __hash__(self) -> int: return hash(self.__key__())
[docs] class InstrumentClass(TypeEnum): """ Instrument class enum. """ CLUSTER = "Cluster"
[docs] class InstrumentType(TypeEnum): """ Instrument/module type enum. """ MM = "MM" QCM = "QCM" QRM = "QRM" QTM = "QTM" QDM = "QDM" LINQ = "LINQ" QRC = "QRC" QSM = "QSM" _RF = "RF" _EOM = "EOM"
[docs] class ClusterType(TypeEnum): """ Cluster module type enum. """ _CLUSTER_MM = "Cluster MM" CLUSTER_QCM = "Cluster QCM" CLUSTER_QCM_RF = "Cluster QCM-RF" CLUSTER_QRM = "Cluster QRM" CLUSTER_QRM_RF = "Cluster QRM-RF" CLUSTER_QTM = "Cluster QTM" CLUSTER_QTM_EOM = "Cluster QTM-Pulse" CLUSTER_QDM = "Cluster QDM" CLUSTER_LINQ = "Cluster LINQ" CLUSTER_QRC = "Cluster QRC" CLUSTER_QSM = "Cluster QSM"
DummyModuleSpec = dict[Union[str, int], ClusterType]
[docs] @dataclass class DummyConfiguration: modules: DummyModuleSpec sw_scpi_version: tuple[int, ...] = (1, 1)
# -- class -------------------------------------------------------------------
[docs] class TypeHandle: """ Instrument type handler class. """ # ------------------------------------------------------------------------
[docs] def __init__(self, instrument: Union[ClusterType, str]) -> None: """ Create instrument type handler object. Parameters ---------- instrument : Union[ClusterType, str] Instrument/module type specification. """ # Set instrument type specification instrument = ( instrument.name.removeprefix("_") if isinstance(instrument, Enum) else instrument.upper() ) instrument_parts = re.split(" |_|-", instrument) try: self._instrument_class = InstrumentClass[instrument_parts[0]] self._instrument_type = InstrumentType[instrument_parts[1]] except KeyError: raise RuntimeError(f"Invalid instrument type: '{instrument}'") self._is_mm_type = self._instrument_type == InstrumentType.MM self._is_qrm_type = self._instrument_type == InstrumentType.QRM self._is_qcm_type = self._instrument_type == InstrumentType.QCM self._is_qtm_type = self._instrument_type == InstrumentType.QTM self._is_qdm_type = self._instrument_type == InstrumentType.QDM self._is_linq_type = self._instrument_type == InstrumentType.LINQ self._is_qrc_type = self._instrument_type == InstrumentType.QRC self._is_qsm_type = self._instrument_type == InstrumentType.QSM # Do a first RF assignment. # It is necessary for dummy modules but will get overwritten for real ones. self._is_rf_type = False self._is_eom_type = False if len(instrument_parts) > 2: self._is_rf_type = instrument_parts[2] == str(InstrumentType._RF) self._is_eom_type = instrument_parts[2] == str(InstrumentType._EOM) if not (self._is_rf_type or self._is_eom_type): raise RuntimeError(f"Invalid instrument type: '{instrument}'") # Add QRC to RF types self._is_rf_type |= self._is_qrc_type
# ------------------------------------------------------------------------ @property def instrument_class(self) -> InstrumentClass: """ Get instrument class (e.g. Cluster). Returns ------- InstrumentClass Instrument class """ return self._instrument_class # ------------------------------------------------------------------------ @property def instrument_type(self) -> InstrumentType: """ Get instrument type (e.g. MM, QRM, QCM, QTM). Returns ------- InstrumentType Instrument type """ return self._instrument_type # ------------------------------------------------------------------------ @property def is_mm_type(self) -> bool: """ Return if module is of type MM. Returns ------- bool True if module is of type MM. """ return self._is_mm_type # ------------------------------------------------------------------------ @property def is_qcm_type(self) -> bool: """ Return if module is of type QCM. Returns ------- bool True if module is of type QCM. """ return self._is_qcm_type # ------------------------------------------------------------------------ @property def is_qrm_type(self) -> bool: """ Return if module is of type QRM. Returns ------- bool True if module is of type QRM. """ return self._is_qrm_type # ------------------------------------------------------------------------ @property def is_qtm_type(self) -> bool: """ Return if module is of type QTM. Returns ------- bool True if module is of type QTM. """ return self._is_qtm_type # ------------------------------------------------------------------------ @property def is_qdm_type(self) -> bool: """ Return if module is of type QDM. Returns ------- bool True if module is of type QDM. """ return self._is_qdm_type # ------------------------------------------------------------------------ @property def is_eom_type(self) -> bool: """ Return if module is of type EOM. Returns ------- bool True if module is of type EOM. """ return self._is_eom_type # ------------------------------------------------------------------------ @property def is_linq_type(self) -> bool: """ Return if module is of type LINQ. Returns ------- bool True if module is of type LINQ. """ return self._is_linq_type # ------------------------------------------------------------------------ @property def is_qrc_type(self) -> bool: """ Return if module is of type QRC. Returns ------- bool True if module is of type QRC. """ return self._is_qrc_type # ------------------------------------------------------------------------ @property def is_qsm_type(self) -> bool: """ Return if module is of type QSM. Returns ------- bool True if module is of type QSM. """ return self._is_qsm_type # ------------------------------------------------------------------------ @property def is_rf_type(self) -> bool: """ Return if has RF functionality. Returns ------- bool True if module has RF functionality. """ return self._is_rf_type
[docs] class FrequencyParameter(DelegateParameter):
[docs] def __init__(self, *args, calibration_function, **kwargs) -> None: self._calibration_function = calibration_function super().__init__(*args, **kwargs)
[docs] def set_raw(self, val, cal_type=None) -> None: self.source.set(val) self._calibration_function(cal_type=cal_type)
[docs] class FilterMode(IntEnum): """ Enum for possible filter mode frequencies for QSM IO Channel. """ FREQ_10_HZ = 10 FREQ_10_KHZ = 10000 FREQ_250_KHZ = 250000
[docs] class WaveformWeight(TypedDict): index: int data: Collection[Union[int, float]]
[docs] class Acquisition(TypedDict): index: int num_bins: int
[docs] class Sequence(TypedDict, total=True): program: str waveforms: dict[str, WaveformWeight] weights: dict[str, WaveformWeight] acquisitions: dict[str, Acquisition]
[docs] class SampleEncoding(IntEnum): UNSUPPORTED = -1 F32 = 0 I32 = 1 I16 = 2
# SMF routing-mandatory types
[docs] @runtime_checkable class HasSlotIdx(Protocol): """Protocol for objects that behave like a Module.""" @property def slot_idx(self) -> int: ... # Optional: If the module has specific constant lookup def _get_module_constants(self) -> Any: ... # Optional: Standard Qblox list of sequencers @property def sequencers(self) -> Any: ...
[docs] @runtime_checkable class HasSeqIdx(Protocol): """Protocol for objects that behave like a Sequencer.""" @property def seq_idx(self) -> int: ...
RouterInputItem = Union[HasSlotIdx, HasSeqIdx] RouterInputPair = tuple[RouterInputItem, list[RouterInputItem]]
[docs] class RouterConfig(TypedDict): """Router configuration.""" router_id: int mask: int event_id: NotRequired[Union[int, list[int]]]
[docs] @unique class RouterID(IntEnum): """Internal Hardware IDs.""" GATHER = 1 SCATTER = 2
# Type: Single object or Iterable of objects _SingleTarget = Union[HasSeqIdx, HasSlotIdx] TargetInput = Union[_SingleTarget, Iterable[_SingleTarget]]
[docs] @unique class ModuleSource(IntEnum): """Input Source Selection.""" SELF_CAST = 1 # Internal Loopback PHY_A = 2 # Physical Port A
[docs] @unique class ModuleConfigType(IntEnum): """ Configuration Selection. Determines which routers to generate configuration for. """ GATHER = 1 # Configure only Input Source SCATTER = 2 # Configure only Sequencer Mask BOTH = 3 # Configure Both (Default)