Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DMM Range Handler Functions #205

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 85 additions & 3 deletions src/fixate/drivers/dmm/keithley_6500.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@
from fixate.core.exceptions import InstrumentError, ParameterError
from fixate.drivers.dmm.helper import DMM
import time
from dataclasses import dataclass
from logging import getLogger

logger = getLogger(__name__)


@dataclass
class DMMRanges:
"""
Class to store DMM range definitions. These are taken from the DMM User Manual / Specifications.
"""

# Overrange is 20% on all ranges except 1000 VDC which is 1%
# fmt: off
current_dc = ( 10e-6, 100e-6, 1e-3, 10e-3, 100e-3, 1, 3, 10,) # Not all of these ranges are available. Modified to match Fluke DMM in some cases.
current_ac = (100e-3, 1e-3, 10e-3, 100e-3, 1, 3, 10)
voltage_dc = (0.1, 1, 10, 100, 1000)
voltage_ac = (100e-3, 1, 10, 100, 750)
resistance = (1, 10, 100, 1e3, 10e3, 100e3, 1e6, 10e6, 100e6)
temperature = () # Empty. No ranges for temperature
frequency = ( 300e-3,) # No adjustable range for frequency. Just put maximum range here.
period = (3.3e-6,) # No adjustable range for period. Just put maximum range here.
continuity = (1e3,) # No selectable range for continuity. Put maximum range here.
capacitance = (1e-9, 10e-9, 100e-9, 1e-6, 10e-6, 100e-6)
diode = (10,) # No selectable range for diode. Default is 10V

# Helper to map a mode to a range
# Note: This means we have to keep self._modes and this dictionary in sync. Maybe there is a better way to do this?
mode_to_range = {
"current_dc": current_dc,
"current_ac": current_ac,
"voltage_dc": voltage_dc,
"voltage_ac": voltage_ac,
"resistance": resistance,
"fresistance": resistance, # Four wire resistance uses the same ranges as two wire
"temperature": temperature, # Not currently implemented in the driver.
"frequency": frequency,
"period": period,
"continuity": continuity,
"capacitance": capacitance,
"diode": diode,
}
# fmt: on


class Keithley6500(DMM):
Expand Down Expand Up @@ -41,6 +84,7 @@ def __init__(self, instrument, *args, **kwargs):
"diode": "DIOD",
}

self.range = None # Currently selected range. Can be None if the mode does not have a range.
self._init_string = "" # Unchanging

# Adapted for different DMM behaviour
Expand Down Expand Up @@ -147,6 +191,7 @@ def reset(self):
self._write("*RST")
self._CLEAN_UP_FLAG = False
self._is_error()
self.instrument.clear() # Clear buffer after reset

def __enter__(self):
return self
Expand Down Expand Up @@ -244,17 +289,48 @@ def _set_measurement_mode(self, mode, _range=None, suffix=None):
:param _range:
:return:
"""
self.mode = mode
self.mode = mode # Update the mode.
self._manual_trigger = False
self.range = self._select_range(_range)

mode_str = f"SENS:FUNC '{self._modes[self._mode]}'"
if _range is not None:
mode_str += f"; :SENS:{self._modes[self._mode]}:RANGE {_range}"
if self.range is not None:
# Don't error when range is None. This is valid in some modes.
mode_str += f"; :SENS:{self._modes[self._mode]}:RANGE {self.range}"
if suffix is not None:
mode_str += suffix
self._write(mode_str)
self._write(f":COUN {self.samples}")
self._is_error()

def _select_range(self, value):
"""
Selects the appropriate range for the DMM to measure "value"

return: Range value to set on the DMM
raise: ParameterError if the range is not valid for the mode (over range)
"""
# Some modes don't have adjustable range. Return None if this is the case.
if value is None:
return None

ranges = self._get_ranges() # Get ranges for the current mode
for i in ranges:
if abs(value) <= i:
return i
raise ParameterError(
f"Requested range '{value}' is too large for mode '{self.mode}'"
)

def _get_ranges(self):
"""
Returns a tuple of available ranges for the current mode
"""
if self.mode is None:
raise InstrumentError("DMM mode is not set. Cannot return range")

return DMMRanges.mode_to_range[self.mode]

def voltage_ac(self, _range=None):
self._set_measurement_mode("voltage_ac", _range)

Expand All @@ -267,9 +343,15 @@ def voltage_dc(self, _range=None, auto_impedance=False):
self._set_measurement_mode("voltage_dc", _range, suffix=command)

def current_ac(self, _range=None):
if _range >= 400e-3:
# Modify the range to match the Fluke DMM port ranges
_range = 10 # 10A range will use the 10A port
self._set_measurement_mode("current_ac", _range)

def current_dc(self, _range=None):
if _range >= 400e-3:
# Modify the range to match the Fluke DMM port ranges
_range = 10 # 10A range will use the 10A port
self._set_measurement_mode("current_dc", _range)

def resistance(self, _range=None):
Expand Down
Loading