-
Notifications
You must be signed in to change notification settings - Fork 312
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
4581: Update Textronix drivers to conform with standard r=jenshnielsen a=jenshnielsen This also moves the Keithley drivers from the Tektronix folder to a new Keithley drivers folder Co-authored-by: Jens H. Nielsen <Jens.Nielsen@microsoft.com>
- Loading branch information
Showing
47 changed files
with
4,902 additions
and
4,151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.. _keithley_api : | ||
|
||
Keithley Drivers | ||
================ | ||
|
||
.. automodule:: qcodes.instrument_drivers.Keithley | ||
:autosummary: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.. _tektronix_api : | ||
|
||
Tektronix Drivers | ||
================= | ||
|
||
.. automodule:: qcodes.instrument_drivers.tektronix | ||
:autosummary: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
from functools import partial | ||
from typing import Any, Callable, Union | ||
|
||
from qcodes.instrument import VisaInstrument | ||
from qcodes.validators import Bool, Enum, Ints, MultiType, Numbers | ||
|
||
|
||
def _parse_output_string(s: str) -> str: | ||
"""Parses and cleans string outputs of the Keithley""" | ||
# Remove surrounding whitespace and newline characters | ||
s = s.strip() | ||
|
||
# Remove surrounding quotes | ||
if (s[0] == s[-1]) and s.startswith(("'", '"')): | ||
s = s[1:-1] | ||
|
||
s = s.lower() | ||
|
||
# Convert some results to a better readable version | ||
conversions = { | ||
"mov": "moving", | ||
"rep": "repeat", | ||
} | ||
|
||
if s in conversions.keys(): | ||
s = conversions[s] | ||
|
||
return s | ||
|
||
|
||
def _parse_output_bool(value: str) -> bool: | ||
return True if int(value) == 1 else False | ||
|
||
|
||
class Keithley2000(VisaInstrument): | ||
""" | ||
Driver for the Keithley 2000 multimeter. | ||
""" | ||
|
||
def __init__(self, name: str, address: str, reset: bool = False, **kwargs: Any): | ||
super().__init__(name, address, terminator="\n", **kwargs) | ||
|
||
self._trigger_sent = False | ||
|
||
# Unfortunately the strings have to contain quotation marks and a | ||
# newline character, as this is how the instrument returns it. | ||
self._mode_map = { | ||
"ac current": '"CURR:AC"', | ||
"dc current": '"CURR:DC"', | ||
"ac voltage": '"VOLT:AC"', | ||
"dc voltage": '"VOLT:DC"', | ||
"2w resistance": '"RES"', | ||
"4w resistance": '"FRES"', | ||
"temperature": '"TEMP"', | ||
"frequency": '"FREQ"', | ||
} | ||
|
||
self.add_parameter( | ||
"mode", | ||
get_cmd="SENS:FUNC?", | ||
set_cmd="SENS:FUNC {}", | ||
val_mapping=self._mode_map, | ||
) | ||
|
||
# Mode specific parameters | ||
self.add_parameter( | ||
"nplc", | ||
get_cmd=partial(self._get_mode_param, "NPLC", float), | ||
set_cmd=partial(self._set_mode_param, "NPLC"), | ||
vals=Numbers(min_value=0.01, max_value=10), | ||
) | ||
|
||
# TODO: validator, this one is more difficult since different modes | ||
# require different validation ranges | ||
self.add_parameter( | ||
"range", | ||
get_cmd=partial(self._get_mode_param, "RANG", float), | ||
set_cmd=partial(self._set_mode_param, "RANG"), | ||
vals=Numbers(), | ||
) | ||
|
||
self.add_parameter( | ||
"auto_range_enabled", | ||
get_cmd=partial(self._get_mode_param, "RANG:AUTO", _parse_output_bool), | ||
set_cmd=partial(self._set_mode_param, "RANG:AUTO"), | ||
vals=Bool(), | ||
) | ||
|
||
self.add_parameter( | ||
"digits", | ||
get_cmd=partial(self._get_mode_param, "DIG", int), | ||
set_cmd=partial(self._set_mode_param, "DIG"), | ||
vals=Ints(min_value=4, max_value=7), | ||
) | ||
|
||
self.add_parameter( | ||
"averaging_type", | ||
get_cmd=partial(self._get_mode_param, "AVER:TCON", _parse_output_string), | ||
set_cmd=partial(self._set_mode_param, "AVER:TCON"), | ||
vals=Enum("moving", "repeat"), | ||
) | ||
|
||
self.add_parameter( | ||
"averaging_count", | ||
get_cmd=partial(self._get_mode_param, "AVER:COUN", int), | ||
set_cmd=partial(self._set_mode_param, "AVER:COUN"), | ||
vals=Ints(min_value=1, max_value=100), | ||
) | ||
|
||
self.add_parameter( | ||
"averaging_enabled", | ||
get_cmd=partial(self._get_mode_param, "AVER:STAT", _parse_output_bool), | ||
set_cmd=partial(self._set_mode_param, "AVER:STAT"), | ||
vals=Bool(), | ||
) | ||
|
||
# Global parameters | ||
self.add_parameter( | ||
"display_enabled", | ||
get_cmd="DISP:ENAB?", | ||
get_parser=_parse_output_bool, | ||
set_cmd="DISP:ENAB {}", | ||
set_parser=int, | ||
vals=Bool(), | ||
) | ||
|
||
self.add_parameter( | ||
"trigger_continuous", | ||
get_cmd="INIT:CONT?", | ||
get_parser=_parse_output_bool, | ||
set_cmd="INIT:CONT {}", | ||
set_parser=int, | ||
vals=Bool(), | ||
) | ||
|
||
self.add_parameter( | ||
"trigger_count", | ||
get_cmd="TRIG:COUN?", | ||
get_parser=int, | ||
set_cmd="TRIG:COUN {}", | ||
vals=MultiType( | ||
Ints(min_value=1, max_value=9999), | ||
Enum("inf", "default", "minimum", "maximum"), | ||
), | ||
) | ||
|
||
self.add_parameter( | ||
"trigger_delay", | ||
get_cmd="TRIG:DEL?", | ||
get_parser=float, | ||
set_cmd="TRIG:DEL {}", | ||
unit="s", | ||
vals=Numbers(min_value=0, max_value=999999.999), | ||
) | ||
|
||
self.add_parameter( | ||
"trigger_source", | ||
get_cmd="TRIG:SOUR?", | ||
set_cmd="TRIG:SOUR {}", | ||
val_mapping={ | ||
"immediate": "IMM", | ||
"timer": "TIM", | ||
"manual": "MAN", | ||
"bus": "BUS", | ||
"external": "EXT", | ||
}, | ||
) | ||
|
||
self.add_parameter( | ||
"trigger_timer", | ||
get_cmd="TRIG:TIM?", | ||
get_parser=float, | ||
set_cmd="TRIG:TIM {}", | ||
unit="s", | ||
vals=Numbers(min_value=0.001, max_value=999999.999), | ||
) | ||
|
||
self.add_parameter("amplitude", unit="arb.unit", get_cmd=self._read_next_value) | ||
|
||
self.add_function("reset", call_cmd="*RST") | ||
|
||
if reset: | ||
self.reset() | ||
|
||
# Set the data format to have only ascii data without units and channels | ||
self.write("FORM:DATA ASCII") | ||
self.write("FORM:ELEM READ") | ||
|
||
self.connect_message() | ||
|
||
def trigger(self) -> None: | ||
if not self.trigger_continuous(): | ||
self.write("INIT") | ||
self._trigger_sent = True | ||
|
||
def _read_next_value(self) -> float: | ||
# Prevent a timeout when no trigger has been sent | ||
if not self.trigger_continuous() and not self._trigger_sent: | ||
return 0.0 | ||
|
||
self._trigger_sent = False | ||
|
||
return float(self.ask("SENSE:DATA:FRESH?")) | ||
|
||
def _get_mode_param( | ||
self, parameter: str, parser: Callable[[str], Any] | ||
) -> Union[float, str, bool]: | ||
"""Read the current Keithley mode and ask for a parameter""" | ||
mode = _parse_output_string(self._mode_map[self.mode()]) | ||
cmd = f"{mode}:{parameter}?" | ||
|
||
return parser(self.ask(cmd)) | ||
|
||
def _set_mode_param(self, parameter: str, value: Union[float, str, bool]) -> None: | ||
"""Read the current Keithley mode and set a parameter""" | ||
if isinstance(value, bool): | ||
value = int(value) | ||
|
||
mode = _parse_output_string(self._mode_map[self.mode()]) | ||
cmd = f"{mode}:{parameter} {value}" | ||
|
||
self.write(cmd) |
Oops, something went wrong.