Source code for qcodes.instrument_drivers.Keysight.keysight_34934a

import logging
import re
from typing import TYPE_CHECKING

from qcodes import validators

from .keysight_34980a_submodules import Keysight34980ASwitchMatrixSubModule

if TYPE_CHECKING:
    from collections.abc import Callable

    from typing_extensions import Unpack

    from qcodes.instrument import (
        InstrumentBaseKWArgs,
        InstrumentChannel,
        VisaInstrument,
    )
    from qcodes.parameters import Parameter


[docs] class Keysight34934A(Keysight34980ASwitchMatrixSubModule): """ InstrumentModule that represents the Keysight34934A module Args: parent: the system which the module is installed on name: user defined name for the module slot: the slot the module is installed """ def __init__( self, parent: "VisaInstrument | InstrumentChannel", name: str, slot: int, **kwargs: "Unpack[InstrumentBaseKWArgs]", ) -> None: super().__init__(parent, name, slot, **kwargs) self.protection_mode: Parameter = self.add_parameter( name="protection_mode", get_cmd=self._get_relay_protection_mode, set_cmd=self._set_relay_protection_mode, vals=validators.Enum("AUTO100", "AUTO0", "FIX", "ISO"), docstring="get and set the relay protection mode. " "The fastest switching speeds for relays " "in a given signal path are achieved using " "the FIXed or ISOlated modes, followed " "by the AUTO100 and AUTO0 modes. " "There may be a maximum of 200 Ohm of " "resistance, which can only be bypassed " "by 'AUTO0' mode. See manual and " "programmer's reference for detail.", ) """ get and set the relay protection mode. The fastest switching speeds for relays in a given signal path are achieved using the FIXed or ISOlated modes, followed by the AUTO100 and AUTO0 modes. There may be a maximum of 200 Ohm of resistance, which can only be bypassed by "AUTO0" mode. See manual and programmer's reference for detail.""" layout = self.ask(f"SYSTEM:MODule:TERMinal:TYPE? {self.slot}") self._is_locked = layout == "NONE" if self._is_locked: logging.warning( f"For slot {slot}, no configuration module" f"connected, or safety interlock jumper removed. " "Making any connection is not allowed" ) config = self.ask(f"SYST:CTYP? {slot}").strip('"').split(",")[1] layout = config.split("-")[1] self.row, self.column = (int(num) for num in re.findall(r"\d+", layout))
[docs] def write(self, cmd: str) -> None: """ When the module is safety interlocked, users can not make any connections. There will be no effect when try to connect any channels. """ if self._is_locked: logging.warning( "Warning: no configuration module connected, " "or safety interlock enabled. " "Making any connection is not allowed" ) return self.parent.write(cmd)
[docs] def validate_value(self, row: int, column: int) -> None: """ to check if the row and column number is within the range of the module layout. Args: row: row value column: column value """ if (row > self.row) or (column > self.column): raise ValueError("row/column value out of range")
def _get_relay_protection_mode(self) -> str: return self.ask(f"SYSTem:MODule:ROW:PROTection? {self.slot}") def _set_relay_protection_mode(self, mode: str) -> None: self.write(f"SYSTem:MODule:ROW:PROTection {self.slot}, {mode}")
[docs] def to_channel_list( self, paths: list[tuple[int, int]], wiring_config: str | None = "" ) -> str: """ convert the (row, column) pair to a 4-digit channel number 'sxxx', where s is the slot number, xxx is generated from the numbering function. Args: paths: list of channels to connect [(r1, c1), (r2, c2), (r3, c3)] wiring_config: for 1-wire matrices, values are 'MH', 'ML'; for 2-wire matrices, values are 'M1H', 'M2H', 'M1L', 'M2L' Returns: in the format of '(@sxxx, sxxx, sxxx, sxxx)', where sxxx is a 4-digit channel number """ numbering_function = self.get_numbering_function( self.row, self.column, wiring_config ) channels = [] for row, column in paths: channel = f"{self.slot}{numbering_function(row, column)}" channels.append(channel) channel_list = f"(@{','.join(channels)})" return channel_list
[docs] @staticmethod def get_numbering_function( rows: int, columns: int, wiring_config: str | None = "" ) -> "Callable[[int, int], str]": """ to select the correct numbering function based on the matrix layout. On P168 of the user's guide for Agilent 34934A High Density Matrix Module: http://literature.cdn.keysight.com/litweb/pdf/34980-90034.pdf there are eleven equations. This function here simplifies them to one. Args: rows: the total row number of the matrix module columns: the total column number of the matrix module wiring_config: wiring configuration for 1 or 2 wired matrices Returns: The numbering function to convert row and column in to a 3-digit number """ layout = f"{rows}x{columns}" available_layouts = { "4x32": ["M1H", "M2H", "M1L", "M2L"], "4x64": ["MH", "ML"], "4x128": [""], "8x32": ["MH", "ML"], "8x64": [""], "16x32": [""], } if layout not in available_layouts: raise ValueError(f"Unsupported layout: {layout}") if wiring_config not in available_layouts[layout]: raise ValueError( f"Invalid wiring config '{wiring_config}' for layout {layout}" ) offsets = {"M1H": 0, "M2H": 1, "M1L": 2, "M2L": 3, "MH": 0, "ML": 1} offset = 0 if wiring_config != "": offset = offsets[wiring_config] * columns channels_per_row = 800 / rows offset += 100 - int(channels_per_row) def numbering_function(row: int, col: int) -> str: return str(int(channels_per_row * row + col + offset)) return numbering_function