Source code for instruments.hp.hp6624a

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Provides support for the HP6624a power supply
"""

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

from __future__ import absolute_import
from __future__ import division

from builtins import range
from enum import Enum

import quantities as pq

from instruments.abstract_instruments import (
    PowerSupply,
    PowerSupplyChannel
)
from instruments.util_fns import ProxyList, unitful_property, bool_property

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


[docs]class HP6624a(PowerSupply): """ The HP6624a is a multi-output power supply. This class can also be used for HP662xa, where x=1,2,3,4,7. Note that some models have less channels then the HP6624 and it is up to the user to take this into account. This can be changed with the `~HP6624a.channel_count` property. Example usage: >>> import instruments as ik >>> psu = ik.hp.HP6624a.open_gpibusb('/dev/ttyUSB0', 1) >>> psu.channel[0].voltage = 10 # Sets channel 1 voltage to 10V. """ def __init__(self, filelike): super(HP6624a, self).__init__(filelike) self._channel_count = 4 # INNER CLASSES #
[docs] class Channel(PowerSupplyChannel): """ Class representing a power output channel on the HP6624a. .. warning:: This class should NOT be manually created by the user. It is designed to be initialized by the `HP6624a` class. """ def __init__(self, hp, idx): self._hp = hp self._idx = idx + 1 # COMMUNICATION METHODS # def _format_cmd(self, cmd): cmd = cmd.split(" ") if len(cmd) == 1: cmd = "{cmd} {idx}".format(cmd=cmd[0], idx=self._idx) else: cmd = "{cmd} {idx},{value}".format( cmd=cmd[0], idx=self._idx, value=cmd[1] ) return cmd
[docs] def sendcmd(self, cmd): """ Function used to send a command to the instrument while wrapping the command with the neccessary identifier for the channel. :param str cmd: Command that will be sent to the instrument after being prefixed with the channel identifier """ cmd = self._format_cmd(cmd) self._hp.sendcmd(cmd)
[docs] def query(self, cmd): """ Function used to send a command to the instrument while wrapping the command with the neccessary identifier for the channel. :param str cmd: Command that will be sent to the instrument after being prefixed with the channel identifier :return: The result from the query :rtype: `str` """ cmd = self._format_cmd(cmd) return self._hp.query(cmd)
# PROPERTIES # @property def mode(self): """ Gets/sets the mode for the specified channel. """ raise NotImplementedError @mode.setter def mode(self, newval): raise NotImplementedError voltage = unitful_property( "VSET", pq.volt, set_fmt="{} {:.1f}", output_decoration=float, doc=""" Gets/sets the voltage of the specified channel. If the device is in constant current mode, this sets the voltage limit. Note there is no bounds checking on the value specified. :units: As specified, or assumed to be :math:`\\text{V}` otherwise. :type: `float` or `~quantities.quantity.Quantity` """ ) current = unitful_property( "ISET", pq.amp, set_fmt="{} {:.1f}", output_decoration=float, doc=""" Gets/sets the current of the specified channel. If the device is in constant voltage mode, this sets the current limit. Note there is no bounds checking on the value specified. :units: As specified, or assumed to be :math:`\\text{A}` otherwise. :type: `float` or `~quantities.quantity.Quantity` """ ) voltage_sense = unitful_property( "VOUT", pq.volt, readonly=True, doc=""" Gets the actual voltage as measured by the sense wires for the specified channel. :units: :math:`\\text{V}` (volts) :rtype: `~quantities.quantity.Quantity` """ ) current_sense = unitful_property( "IOUT", pq.amp, readonly=True, doc=""" Gets the actual output current as measured by the instrument for the specified channel. :units: :math:`\\text{A}` (amps) :rtype: `~quantities.quantity.Quantity` """ ) overvoltage = unitful_property( "OVSET", pq.volt, set_fmt="{} {:.1f}", output_decoration=float, doc=""" Gets/sets the overvoltage protection setting for the specified channel. Note there is no bounds checking on the value specified. :units: As specified, or assumed to be :math:`\\text{V}` otherwise. :type: `float` or `~quantities.quantity.Quantity` """ ) overcurrent = bool_property( "OVP", inst_true="1", inst_false="0", doc=""" Gets/sets the overcurrent protection setting for the specified channel. This is a toggle setting. It is either on or off. :type: `bool` """ ) output = bool_property( "OUT", inst_true="1", inst_false="0", doc=""" Gets/sets the outputting status of the specified channel. This is a toggle setting. True will turn on the channel output while False will turn it off. :type: `bool` """ ) # METHODS ##
[docs] def reset(self): """ Reset overvoltage and overcurrent errors to resume operation. """ self.sendcmd('OVRST') self.sendcmd('OCRST')
# ENUMS #
[docs] class Mode(Enum): """ Enum holding typical valid output modes for a power supply. However, for the HP6624a I believe that it is only capable of constant-voltage output, so this class current does not do anything and is just a placeholder. """ voltage = 0 current = 0
# PROPERTIES ## @property def channel(self): """ Gets a specific channel object. The desired channel is specified like one would access a list. :rtype: `HP6624a.Channel` .. seealso:: `HP6624a` for example using this property. """ return ProxyList(self, HP6624a.Channel, range(self.channel_count)) @property def voltage(self): """ Gets/sets the voltage for all four channels. :units: As specified (if a `~quantities.Quantity`) or assumed to be of units Volts. :type: `list` of `~quantities.quantity.Quantity` with units Volt """ return [ self.channel[i].voltage for i in range(self.channel_count) ] @voltage.setter def voltage(self, newval): if isinstance(newval, (list, tuple)): if len(newval) is not self.channel_count: raise ValueError('When specifying the voltage for all channels ' 'as a list or tuple, it must be of ' 'length {}.'.format(self.channel_count)) for i in range(self.channel_count): self.channel[i].voltage = newval[i] else: for i in range(self.channel_count): self.channel[i].voltage = newval @property def current(self): """ Gets/sets the current for all four channels. :units: As specified (if a `~quantities.Quantity`) or assumed to be of units Amps. :type: `list` of `~quantities.quantity.Quantity` with units Amp """ return [ self.channel[i].current for i in range(self.channel_count) ] @current.setter def current(self, newval): if isinstance(newval, (list, tuple)): if len(newval) is not self.channel_count: raise ValueError('When specifying the current for all channels ' 'as a list or tuple, it must be of ' 'length {}.'.format(self.channel_count)) for i in range(self.channel_count): self.channel[i].current = newval[i] else: for i in range(self.channel_count): self.channel[i].current = newval @property def voltage_sense(self): """ Gets the actual voltage as measured by the sense wires for all channels. :units: :math:`\\text{V}` (volts) :rtype: `tuple` of `~quantities.quantity.Quantity` """ return ( self.channel[i].voltage_sense for i in range(self.channel_count) ) @property def current_sense(self): """ Gets the actual current as measured by the instrument for all channels. :units: :math:`\\text{A}` (amps) :rtype: `tuple` of `~quantities.quantity.Quantity` """ return ( self.channel[i].current_sense for i in range(self.channel_count) ) @property def channel_count(self): """ Gets/sets the number of output channels available for the connected power supply. :type: `int` """ return self._channel_count @channel_count.setter def channel_count(self, newval): if not isinstance(newval, int): raise TypeError('Channel count must be specified as an integer.') if newval < 1: raise ValueError('Channel count must be >=1') self._channel_count = newval # METHODS ##
[docs] def clear(self): """ Taken from the manual: Return the power supply to its power-on state and all parameters are returned to their initial power-on values except the following: #) The store/recall registers are not cleared. #) The power supply remains addressed to listen. #) The PON bit in the serial poll register is cleared. """ self.sendcmd('CLR')