Source code for qcodes.instrument_drivers.Keithley.Keithley_2400

from typing import TYPE_CHECKING

from qcodes.instrument import VisaInstrument, VisaInstrumentKWArgs
from qcodes.parameters import create_on_off_val_mapping
from qcodes.validators import Enum, Strings

if TYPE_CHECKING:
    from typing_extensions import Unpack

    from qcodes.parameters import Parameter


[docs] class Keithley2400(VisaInstrument): """ QCoDeS driver for the Keithley 2400 voltage source. """ default_terminator = "\n" def __init__( self, name: str, address: str, **kwargs: "Unpack[VisaInstrumentKWArgs]", ): super().__init__(name, address, **kwargs) self.rangev: Parameter = self.add_parameter( "rangev", get_cmd="SENS:VOLT:RANG?", get_parser=float, set_cmd="SOUR:VOLT:RANG {:f}", label="Voltage range", ) """Parameter rangev""" self.rangei: Parameter = self.add_parameter( "rangei", get_cmd="SENS:CURR:RANG?", get_parser=float, set_cmd="SOUR:CURR:RANG {:f}", label="Current range", ) """Parameter rangei""" self.compliancev: Parameter = self.add_parameter( "compliancev", get_cmd="SENS:VOLT:PROT?", get_parser=float, set_cmd="SENS:VOLT:PROT {:f}", label="Voltage Compliance", ) """Parameter compliancev""" self.compliancei: Parameter = self.add_parameter( "compliancei", get_cmd="SENS:CURR:PROT?", get_parser=float, set_cmd="SENS:CURR:PROT {:f}", label="Current Compliance", ) """Parameter compliancei""" self.volt: Parameter = self.add_parameter( "volt", get_cmd=self._get_read_output_protected, get_parser=self._volt_parser, set_cmd=":SOUR:VOLT:LEV {:.8f}", label="Voltage", unit="V", docstring="Sets voltage in 'VOLT' mode. " "Get returns measured voltage if " "sensing 'VOLT' otherwise it returns " "setpoint value. " "Note that it is an error to read voltage with " "output off", ) """Sets voltage in 'VOLT' mode. Get returns measured voltage if sensing 'VOLT' otherwise it returns setpoint value. Note that it is an error to read voltage with output off""" self.curr: Parameter = self.add_parameter( "curr", get_cmd=self._get_read_output_protected, get_parser=self._curr_parser, set_cmd=":SOUR:CURR:LEV {:.8f}", label="Current", unit="A", docstring="Sets current in 'CURR' mode. " "Get returns measured current if " "sensing 'CURR' otherwise it returns " "setpoint value. " "Note that it is an error to read current with " "output off", ) """Sets current in 'CURR' mode. Get returns measured current if sensing 'CURR' otherwise it returns setpoint value. Note that it is an error to read current with output off""" self.mode: Parameter = self.add_parameter( "mode", vals=Enum("VOLT", "CURR"), get_cmd=":SOUR:FUNC?", set_cmd=self._set_mode_and_sense, label="Mode", ) """Parameter mode""" self.sense: Parameter = self.add_parameter( "sense", vals=Strings(), get_cmd=":SENS:FUNC?", set_cmd=':SENS:FUNC "{:s}"', label="Sense mode", ) """Parameter sense""" self.output: Parameter = self.add_parameter( "output", set_cmd=":OUTP:STAT {}", get_cmd=":OUTP:STAT?", val_mapping=create_on_off_val_mapping(on_val="1", off_val="0"), ) """Parameter output""" self.nplcv: Parameter = self.add_parameter( "nplcv", get_cmd="SENS:VOLT:NPLC?", get_parser=float, set_cmd="SENS:VOLT:NPLC {:f}", label="Voltage integration time", ) """Parameter nplcv""" self.nplci: Parameter = self.add_parameter( "nplci", get_cmd="SENS:CURR:NPLC?", get_parser=float, set_cmd="SENS:CURR:NPLC {:f}", label="Current integration time", ) """Parameter nplci""" self.resistance: Parameter = self.add_parameter( "resistance", get_cmd=self._get_read_output_protected, get_parser=self._resistance_parser, label="Resistance", unit="Ohm", docstring="Measure resistance from current and voltage. " "Note that it is an error to read current " "and voltage with output off", ) """Measure resistance from current and voltage. Note that it is an error to read current and voltage with output off""" self.write(":TRIG:COUN 1;:FORM:ELEM VOLT,CURR") # This line sends 2 commands to the instrument: # ":TRIG:COUN 1" sets the trigger count to 1 so that each READ? returns # only 1 measurement result. # ":FORM:ELEM VOLT,CURR" sets the output string formatting of the the # Keithley 2400 to return "{voltage}, {current}". # Default value on instrument reset is "VOLT, CURR, RES, TIME, STATUS"; # however, resistance, status, and time are unused in this driver and # so are omitted. # These commands do not reset the instrument but do the minimal amount # to ensure that voltage and current parameters can be read from the # instrument, in the event that output formatting of the instrument was # previously changed to some other unknown state. self.connect_message() def _get_read_output_protected(self) -> str: """ This wrapper function around ":READ?" exists because calling ":READ?" on an instrument with output disabled is an error. So first we check that output is on and if not we return nan for volt, curr etc. """ output = self.output.get_latest() if output is None: # if get_latest returns None we have # to ask the instrument for the status of output output = self.output.get() if output == 1: msg = self.ask(":READ?") else: raise RuntimeError("Cannot perform read with output off") return msg def _set_mode_and_sense(self, msg: str) -> None: # This helps set the correct read out curr/volt if msg == "VOLT": self.sense("CURR") elif msg == "CURR": self.sense("VOLT") else: raise AttributeError("Mode does not exist") self.write(f":SOUR:FUNC {msg:s}")
[docs] def reset(self) -> None: """ Reset the instrument. When the instrument is reset, it performs the following actions. Returns the SourceMeter to the GPIB default conditions. Cancels all pending commands. Cancels all previously send `*OPC` and `*OPC?` """ self.write(":*RST")
def _volt_parser(self, msg: str) -> float: fields = [float(x) for x in msg.split(",")] return fields[0] def _curr_parser(self, msg: str) -> float: fields = [float(x) for x in msg.split(",")] return fields[1] def _resistance_parser(self, msg: str) -> float: fields = [float(x) for x in msg.split(",")] res = fields[0] / fields[1] return res