Updates to OTF, and added RP100 strain cell power supply, as well as a couple network analysers. Results from the mRS network analyser are questionable at best, and nonsense at worst. Beware.
This commit is contained in:
132
frappy_psi/uniaxial_cell/RP100.py
Normal file
132
frappy_psi/uniaxial_cell/RP100.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# *****************************************************************************
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Paul M. Neves <pmneves@mit.edu>
|
||||
# *****************************************************************************
|
||||
|
||||
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, IntRange,\
|
||||
IDLE, BUSY, WARN, ERROR, Drivable, BoolType, Attached
|
||||
from ast import literal_eval
|
||||
|
||||
|
||||
class RP100IO(StringIO):
|
||||
"""communication with RP100"""
|
||||
end_of_line = '\n'
|
||||
#wait_before = 0.05
|
||||
identification = [('*IDN?', r'Razorbill,.*')]
|
||||
|
||||
|
||||
class VoltageChannel(HasIO, Drivable):
|
||||
"""a voltage output with loop"""
|
||||
|
||||
temp = Attached('frappy.core.Readable', mandatory=False)
|
||||
|
||||
# define the communication class for automatic creation of the IO module
|
||||
ioClass = RP100IO
|
||||
|
||||
# internal property to configure the channel
|
||||
channel = Property('the voltage channel', datatype=IntRange(1,2))
|
||||
|
||||
# modifying a property of inherited parameters (unit is propagated to the FloatRange datatype)
|
||||
value = Parameter('output voltage', FloatRange(-210, 210, unit='V'),
|
||||
readonly=True)
|
||||
target = Parameter('target voltage', FloatRange(-210, 210, unit='V'),
|
||||
readonly=False)
|
||||
meas_voltage = Parameter('measured output voltage', FloatRange(-250, 250, unit='V'),
|
||||
readonly=True)
|
||||
meas_current = Parameter('measured output current', FloatRange(-0.007, 0.007, unit='A'),
|
||||
readonly=True)
|
||||
max_target = Parameter('max. target', FloatRange(0, 210, unit='V'), readonly=False, default=210)
|
||||
min_target = Parameter('max. target', FloatRange(-210, 0, unit='V'), readonly=False, default=-210)
|
||||
slew_rate = Parameter('voltage slew rate', FloatRange(0.1e-3, 100e3, unit='V/s'), readonly=False, default=1)
|
||||
output_state = Parameter('output on or off', BoolType(), readonly=False)
|
||||
|
||||
def doPoll(self):
|
||||
super().doPoll()
|
||||
|
||||
# calculate temperature dependent voltage limits
|
||||
if(self.temp):
|
||||
temp = self.temp.target
|
||||
if temp > 250:
|
||||
self.max_target = 120
|
||||
self.min_target = -20
|
||||
elif temp >= 100:
|
||||
self.max_target = 120
|
||||
self.min_target = -50 + (temp-100)/5
|
||||
elif temp >= 10:
|
||||
self.max_target = 200 - 8*(temp-10)/9
|
||||
self.min_target = -200 + 5*(temp-10)/3
|
||||
elif temp < 10:
|
||||
self.max_target = 200
|
||||
self.min_target = -200
|
||||
|
||||
# if the current voltage exceeds these limits, reduce voltage to max/min
|
||||
if self.target > self.max_target:
|
||||
self.write_target(self.max_target)
|
||||
if self.target < self.min_target:
|
||||
self.write_target(self.min_target)
|
||||
|
||||
def read_value(self):
|
||||
# using the inherited HasIO.communicate method to send a command and get the reply
|
||||
reply = self.communicate(f'SOUR{self.channel}:VOLT:NOW?')
|
||||
return float(reply)
|
||||
|
||||
def read_status(self):
|
||||
while True:
|
||||
code, text = literal_eval(self.communicate(f'SYST:ERR?'))
|
||||
if code == 0:
|
||||
break
|
||||
self.log.warning('got error %d %s', code, text)
|
||||
return IDLE, ''
|
||||
|
||||
def read_target(self):
|
||||
# read back the target value
|
||||
target = float(self.communicate(f'SOUR{self.channel}:VOLT?'))
|
||||
return target
|
||||
|
||||
def write_target(self, target):
|
||||
# write here the target to the hardware
|
||||
status = self.read_output_state()
|
||||
|
||||
if target > self.max_target:
|
||||
target = self.max_target
|
||||
self.log.warning('Attempted to set voltage above maximum allowed voltage. Setting to max allowed instead.')
|
||||
if target < self.min_target:
|
||||
target = self.min_target
|
||||
self.log.warning('Attempted to set voltage below minimum allowed voltage. Setting to min allowed instead.')
|
||||
self.communicate(f'SOUR{self.channel}:VOLT {target};*OPC?')
|
||||
return self.read_target() # return the read back value
|
||||
|
||||
def read_slew_rate(self):
|
||||
return float(self.communicate(f'SOUR{self.channel}:VOLT:SLEW?'))
|
||||
|
||||
def write_slew_rate(self, slew_rate):
|
||||
self.communicate(f'SOUR{self.channel}:VOLT:SLEW {slew_rate};*OPC?')
|
||||
return self.read_slew_rate()
|
||||
|
||||
def read_output_state(self):
|
||||
a = int(self.communicate(f'OUTP{self.channel}?'))
|
||||
return bool(a)
|
||||
|
||||
def write_output_state(self, output_state):
|
||||
self.communicate(f'OUTP{self.channel} {int(output_state)};*OPC?')
|
||||
return self.read_slew_rate()
|
||||
|
||||
def read_meas_voltage(self):
|
||||
return float(self.communicate(f'MEAS{self.channel}:VOLT?'))
|
||||
|
||||
def read_meas_current(self):
|
||||
return float(self.communicate(f'MEAS{self.channel}:CURR?'))
|
||||
Reference in New Issue
Block a user