Source code for instruments.keithley.keithley2182

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Driver for the Keithley 2182 nano-voltmeter
"""

# IMPORTS #####################################################################

from __future__ import absolute_import
from __future__ import division
from builtins import range, map

from enum import Enum
import quantities as pq

from instruments.generic_scpi import SCPIMultimeter
from instruments.abstract_instruments import Multimeter
from instruments.util_fns import ProxyList

# CLASSES #####################################################################


[docs]class Keithley2182(SCPIMultimeter): """ The Keithley 2182 is a nano-voltmeter. You can find the full specifications list in the `user's guide`_. Example usage: >>> import instruments as ik >>> meter = ik.keithley.Keithley2182.open_gpibusb("/dev/ttyUSB0", 10) >>> print meter.measure(meter.Mode.voltage_dc) """ # INNER CLASSES #
[docs] class Channel(Multimeter): """ Class representing a channel on the Keithley 2182 nano-voltmeter. .. warning:: This class should NOT be manually created by the user. It is designed to be initialized by the `Keithley2182` class. """ # pylint: disable=super-init-not-called def __init__(self, parent, idx): self._parent = parent self._idx = idx + 1 # PROPERTIES # @property def mode(self): return Keithley2182.Mode(self._parent.query('SENS:FUNC?')) @mode.setter def mode(self, newval): raise NotImplementedError @property def trigger_mode(self): raise NotImplementedError @trigger_mode.setter def trigger_mode(self, newval): raise NotImplementedError @property def relative(self): raise NotImplementedError @relative.setter def relative(self, newval): raise NotImplementedError @property def input_range(self): raise NotImplementedError @input_range.setter def input_range(self, newval): raise NotImplementedError # METHODS #
[docs] def measure(self, mode=None): """ Performs a measurement of the specified channel. If no mode parameter is specified then the current mode is used. :param mode: Mode that the measurement will be performed in :type mode: Keithley2182.Mode :return: The value of the measurement :rtype: `~quantities.quantity.Quantity` """ if mode is not None: # self.mode = mode raise NotImplementedError self._parent.sendcmd('SENS:CHAN {}'.format(self._idx)) value = float(self._parent.query('SENS:DATA:FRES?')) unit = self._parent.units return value * unit
# ENUMS #
[docs] class Mode(Enum): """ Enum containing valid measurement modes for the Keithley 2182 """ voltage_dc = "VOLT" temperature = "TEMP"
[docs] class TriggerMode(Enum): """ Enum containing valid trigger modes for the Keithley 2182 """ immediate = 'IMM' external = 'EXT' bus = 'BUS' timer = 'TIM' manual = 'MAN'
# PROPERTIES # @property def channel(self): """ Gets a specific Keithley 2182 channel object. The desired channel is specified like one would access a list. Although not default, the 2182 has up to two channels. For example, the following would print the measurement from channel 1: >>> meter = ik.keithley.Keithley2182.open_gpibusb("/dev/ttyUSB0", 10) >>> print meter.channel[0].measure() :rtype: `Keithley2182.Channel` """ return ProxyList(self, Keithley2182.Channel, range(2)) @property def relative(self): """ Gets/sets the relative measurement function of the Keithley 2182. This is used to enable or disable the relative function for the currently set mode. When enabling, the current reading is used as a baseline which is subtracted from future measurements. If relative is already on, the stored value is refreshed with the currently read value. See the manual for more information. :type: `bool` """ mode = self.channel[0].mode return self.query("SENS:{}:CHAN1:REF:STAT?".format(mode.value)) == "ON" @relative.setter def relative(self, newval): if not isinstance(newval, bool): raise TypeError("Relative mode must be a boolean.") mode = self.channel[0].mode if self.relative: self.sendcmd("SENS:{}:CHAN1:REF:ACQ".format(mode.value)) else: newval = ("ON" if newval is True else "OFF") self.sendcmd( "SENS:{}:CHAN1:REF:STAT {}".format(mode.value, newval)) @property def input_range(self): raise NotImplementedError @input_range.setter def input_range(self, newval): raise NotImplementedError @property def units(self): """ Gets the current measurement units of the instrument. :rtype: `~quantities.unitquantity.UnitQuantity` """ mode = self.channel[0].mode if mode == Keithley2182.Mode.voltage_dc: return pq.volt unit = self.query("UNIT:TEMP?") if unit == "C": unit = pq.celsius elif unit == "K": unit = pq.kelvin elif unit == "F": unit = pq.fahrenheit else: raise ValueError("Unknown temperature units.") return unit # METHODS #
[docs] def fetch(self): """ Transfer readings from instrument memory to the output buffer, and thus to the computer. If currently taking a reading, the instrument will wait until it is complete before executing this command. Readings are NOT erased from memory when using fetch. Use the ``R?`` command to read and erase data. Note that the data is transfered as ASCII, and thus it is not recommended to transfer a large number of data points using GPIB. :return: Measurement readings from the instrument output buffer. :rtype: `list` of `~quantities.quantity.Quantity` elements """ return list(map(float, self.query("FETC?").split(","))) * self.units
[docs] def measure(self, mode=None): """ Perform and transfer a measurement of the desired type. :param mode: Desired measurement mode. If left at default the measurement will occur with the current mode. :type: `Keithley2182.Mode` :return: Returns a single shot measurement of the specified mode. :rtype: `~quantities.quantity.Quantity` :units: Volts, Celsius, Kelvin, or Fahrenheit """ if mode is None: mode = self.channel[0].mode if not isinstance(mode, Keithley2182.Mode): raise TypeError("Mode must be specified as a Keithley2182.Mode " "value, got {} instead.".format(mode)) value = float(self.query("MEAS:{}?".format(mode.value))) unit = self.units return value * unit