Source code for qblox_instruments.qcodes_drivers.io_channel

# ----------------------------------------------------------------------------
# Description    : IOChannel QCoDeS interface
# Git repository : https://gitlab.com/qblox/packages/software/qblox_instruments.git
# Copyright (C) Qblox BV (2020)
# ----------------------------------------------------------------------------


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

from typing import List, Union, Tuple, NoReturn
from functools import partial
from qcodes import validators as vals
from qcodes import Instrument, InstrumentChannel
from qblox_instruments.docstring_helpers import partial_with_numpy_doc
from qblox_instruments.qcodes_drivers.component import Component


# -- class -------------------------------------------------------------------


[docs] class IOChannel(Component): """ This class represents a single IO channel. It combines all IO channel specific parameters and functions into a single QCoDes InstrumentChannel. """ # ------------------------------------------------------------------------
[docs] def __init__( self, parent: Union[Instrument, InstrumentChannel], name: str, io_channel_idx: int, ): """ Creates a IO channel class and adds all relevant parameters for the IO channel. Parameters ---------- parent : Union[Instrument, InstrumentChannel] The QCoDeS class to which this IO channel belongs. name : str Name of this IO channel channel io_channel_idx : int The index of this IO channel in the parent instrument, representing which IO channel is controlled by this class. Returns ---------- Raises ---------- """ # Initialize instrument channel super().__init__(parent, name) # Store IO channel index self._io_channel_idx = io_channel_idx # Add required parent attributes for the QCoDeS parameters to function for attr_name in IOChannel._get_required_parent_attr_names(): self._register(attr_name) # Add parameters # -- Channel map ----------------------------------------------------- # -- TBD # -- IOChannel (QTM-only) -------------------------------------------- self.add_parameter( "out_mode", label="Output function of the I/O port for the given channel", docstring="Sets/gets the output function of the I/O Port for the given" "channel ('disabled' = port is in 50Ohm mode, " "'low' = the port drives low-impedance 0V, 'high' = the port " "drives low-impedance ~3.3V)", unit="", vals=vals.Enum("disabled", "low", "high", "sequencer"), set_cmd=partial(self._set_io_channel_config_val, ["out_mode"]), get_cmd=partial(self._get_io_channel_config_val, ["out_mode"]), ) self.add_parameter( "in_threshold_primary", label="primary threshold voltage used for digitization of the " "input signal for the given channel", docstring="Sets/gets the primary threshold voltage used for " "digitization of the input signal on the given channel", unit="V", vals=vals.Numbers(), set_parser=float, get_parser=float, set_cmd=partial( self._set_io_channel_config_val, ["in_threshold_primary"], ), get_cmd=partial( self._get_io_channel_config_val, ["in_threshold_primary"], ), ) self.add_parameter( "binned_acq_time_source", label="timetag data source for acquisitions made on the given channel", docstring="Sets/gets the timetag data source for acquisitions made on this channel " "using the acquire_timetags instruction", unit="", vals=vals.Enum("first", "second", "last"), set_cmd=partial( self._set_io_channel_config_val, ["binned_acq_time_source"], ), get_cmd=partial( self._get_io_channel_config_val, ["binned_acq_time_source"], ), ) self.add_parameter( "binned_acq_time_ref", label="time reference that the timetag recorded for each acquire_timetags instruction" "is recorded in relation to", docstring="Sets/gets the time reference that the timetag recorded for each acquire_timetags " "instruction is recorded in relation to", unit="", vals=vals.Enum( "start", "end", "first", *[f"first{x}" for x in range(8)], "sequencer" ), set_cmd=partial( self._set_io_channel_config_val, ["binned_acq_time_ref"], ), get_cmd=partial( self._get_io_channel_config_val, ["binned_acq_time_ref"], ), ) self.add_parameter( "binned_acq_on_invalid_time_delta", label="averaging and binning logic behaviour if/when no valid time delta is available", docstring="Sets/gets averaging and binning logic behaviour if/when no valid time delta " "is available, typically because no event occurred in the window", unit="", vals=vals.Enum( "error", "record_0", "discard", ), set_cmd=partial( self._set_io_channel_config_val, ["binned_acq_on_invalid_time_delta"], ), get_cmd=partial( self._get_io_channel_config_val, ["binned_acq_on_invalid_time_delta"], ), ) self.add_parameter( "binned_acq_threshold_source", label="data source of the threshold recorded by acquire_timetags", docstring="Sets/gets the data source of the threshold recorded by " "acquire timetags", unit="", vals=vals.Enum("thresh0", "thresh1"), set_cmd=partial( self._set_io_channel_config_val, ["binned_acq_threshold_source"], ), get_cmd=partial( self._get_io_channel_config_val, ["binned_acq_threshold_source"], ), ) self.add_parameter( "current_in_level", label="current level of the input", docstring="Gets the current level of the input. Returns 0 if the input " "level is below in_threshold_primary, or 1 if it's above" "acquire timetags", unit="", vals=vals.Ints(0, 1), set_cmd=False, get_cmd=partial( self._get_io_channel_status_val, ["io_monitor"], ), max_val_age=0.0, # disable read cache ) self.add_parameter( "in_counter_mode", label="manual control over the counter gate", docstring="Sets/gets the manual control over the counter gate", unit="", vals=vals.Enum("sequencer", "disabled", "enabled"), set_cmd=partial( self._set_io_channel_config_val, ["in_counter_mode"], ), get_cmd=partial( self._get_io_channel_config_val, ["in_counter_mode"], ), ) for counter_type in ["rising", "falling"]: self.add_parameter( f"in_counter_{counter_type}", label=f"raw value of the hardware {counter_type}-edge counter", docstring=f"Gets the raw value of the hardware {counter_type}-edge counter", unit="", vals=vals.Ints(), set_cmd=False, get_cmd=partial( self._get_io_channel_status_val, [f"count_{counter_type}"], ), max_val_age=0.0, # disable read cache ) self.add_parameter( "in_trigger_en", label="sending triggers to the trigger network automatically", docstring="Sets/gets the enable that controls sending triggers " "to the trigger network automatically or based on direct sampling " "of the inputs. The mode is configured by in_trigger_mode, and the " "address by in_trigger_address", unit="", vals=vals.Bool(), set_cmd=partial( self._set_io_channel_config_val, ["in_trigger_en"], ), get_cmd=partial( self._get_io_channel_config_val, ["in_trigger_en"], ), ) self.add_parameter( "in_trigger_mode", label="which event causes a trigger to be sent if in_trigger_en is enabled", docstring="Sets/gets which event causes a trigger to be sent if in_trigger_en " "is enabled ", unit="", vals=vals.Enum("rising", "falling", "sampled-high", "sampled-low"), set_cmd=partial( self._set_io_channel_config_val, ["in_trigger_mode"], ), get_cmd=partial( self._get_io_channel_config_val, ["in_trigger_mode"], ), ) self.add_parameter( "in_trigger_address", label="which event causes a trigger to be sent if in_trigger_en is enabled", docstring="Sets/gets which event causes a trigger to be sent if in_trigger_en " "is enabled ", unit="", vals=vals.Ints(1, 15), set_cmd=partial( self._set_io_channel_config_val, ["in_trigger_address"], ), get_cmd=partial( self._get_io_channel_config_val, ["in_trigger_address"], ), ) self.add_parameter( "scope_trigger_mode", label="how the scope/trace unit for this channel is triggered", docstring="Sets/gets how the scope/trace unit for this channel is triggered " "is enabled ", unit="", vals=vals.Enum("sequencer", "external"), set_cmd=partial( self._set_io_channel_config_val, ["scope_trigger_mode"], ), get_cmd=partial( self._get_io_channel_config_val, ["scope_trigger_mode"], ), ) self.add_parameter( "scope_trigger_level", label="how the scope/trace unit for this channel is triggered", docstring="Sets/gets how the scope/trace unit for this channel is triggered " "is enabled ", unit="", vals=vals.Enum("any", "low", "high", "rising", "falling"), set_cmd=partial( self._set_io_channel_config_val, ["scope_trigger_level"], ), get_cmd=partial( self._get_io_channel_config_val, ["scope_trigger_level"], ), ) self.add_parameter( "scope_mode", label="what type of data is traced when the scope/trace unit for this channel" "is triggered", docstring="Sets/gets what type of data is traced when the scope/trace unit for " "this channel is triggered", unit="", vals=vals.Enum("scope", "timetags", "timetags-windowed"), set_cmd=partial( self._set_io_channel_config_val, ["scope_mode"], ), get_cmd=partial( self._get_io_channel_config_val, ["scope_mode"], ), ) self.add_parameter( "thresholded_acq_trigger_en", label="whether the thresholded acquisition result of acquire_timetags is mapped " "to the trigger network for feedback purposes", docstring="Sets/gets whether the thresholded acquisition result of acquire_timetags " "is mapped to the trigger network for feedback purposes", unit="", vals=vals.Bool(), set_cmd=partial( self._set_io_channel_config_val, ["thresholded_acq_trigger_en"], ), get_cmd=partial( self._get_io_channel_config_val, ["thresholded_acq_trigger_en"], ), ) for result in ["low", "mid", "high", "invalid"]: self.add_parameter( f"thresholded_acq_trigger_address_{result}", label=f"whether a trigger is to be sent and which trigger address is to be used when the result is {result}", docstring=f"Sets/gets whether a trigger is to be sent and which trigger address is to be used when the result is {result}", unit="", vals=vals.Ints(0, 15), set_cmd=partial( self._set_io_channel_config_val, [f"thresholded_acq_trigger_address_{result}"], ), get_cmd=partial( self._get_io_channel_config_val, [f"thresholded_acq_trigger_address_{result}"], ), )
# ------------------------------------------------------------------------ @property def io_channel_idx(self) -> int: """ Get IO channel index. Parameters ---------- Returns ---------- int IOChannel index Raises ---------- """ return self._io_channel_idx # ------------------------------------------------------------------------ @staticmethod def _get_required_parent_attr_names() -> List: """ Return list of parent attribute names that are required for the QCoDeS parameters to function, so that the can be registered to this object using the _register method. Parameters ---------- Returns ---------- List List of parent attribute names to register. Raises ---------- """ # IOChannel attributes attr_names = [] for operation in ["set", "get"]: attr_names.append(f"_{operation}_io_channel_config") attr_names.append(f"_{operation}_io_channel_config_val") attr_names.append("_get_io_channel_status") attr_names.append("_get_io_channel_status_val") attr_names.append("get_scope_data") return attr_names # ------------------------------------------------------------------------ def _register(self, attr_name: str) -> None: """ Register parent attribute to this IO channel using functools.partial to pre-select the IO channel index. If the attribute does not exist in the parent class, a method that raises a `NotImplementedError` exception is registered instead. The docstring of the parent attribute is also copied to the registered attribute. Parameters ---------- attr_name : str Attribute name of parent to register. Returns ---------- Raises ---------- """ if hasattr(self.parent, attr_name): parent_attr = getattr(self.parent, attr_name) partial_doc = ( "Note\n" + "----------\n" + "This method calls {1}.{0} using functools.partial to set the " + "IO channel index. The docstring above is of {1}.{0}:\n\n" ).format(attr_name, type(self.parent).__name__) partial_func = partial_with_numpy_doc( parent_attr, self.io_channel_idx, end_with=partial_doc ) setattr(self, attr_name, partial_func) else: def raise_not_implemented_error(*args, **kwargs) -> None: raise NotImplementedError( f'{self.parent.name} does not have "{attr_name}" attribute.' ) setattr(self, attr_name, raise_not_implemented_error)