From c75d7f17f7e890fd27d223722ca65dde9e371a8c Mon Sep 17 00:00:00 2001 From: Oksana Shliakhtun Date: Mon, 30 Jan 2023 16:52:06 +0100 Subject: [PATCH] The PID parameters were added. Change-Id: I67a7db66ca13b60d35cb4041bbd35c6c4729416c --- frappy_psi/lakeshore.py | 56 ++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/frappy_psi/lakeshore.py b/frappy_psi/lakeshore.py index f6afd51..05b3bc1 100644 --- a/frappy_psi/lakeshore.py +++ b/frappy_psi/lakeshore.py @@ -22,7 +22,7 @@ from math import log2 from frappy.core import Readable, Parameter, IntRange, EnumType, FloatRange, \ StringIO, HasIO, StringType, Property, Writable, Drivable, IDLE, ERROR, \ - Attached + Attached, StructOf from frappy_psi.mixins import HasOutputModule, HasControlledBy @@ -33,6 +33,18 @@ class Ls340IO(StringIO): identification = [('*IDN?', r'LSCI,MODEL340,.*')] +class LakeShore(HasIO): + def set_par(self, cmd, *args): + head = cmd + ','.join([str(a) for a in args]) + tail = cmd.replace(' ', '? ') + reply = self.communicate(f'{head};{tail}') + return [float(num) for num in reply.split(',')] + + def get_par(self, cmd): + reply = self.communicate(cmd) + return [float(num) for num in reply.split(',')] + + class Sensor340(HasIO, Readable): """A channel of 340TC""" @@ -45,7 +57,7 @@ class Sensor340(HasIO, Readable): value = Parameter(unit='K') def read_value(self): - reply = self.communicate(f'KRDG?{self.channel}') + reply = self.communicate(f'KRDG? {self.channel}') return float(reply) def read_status(self): @@ -65,7 +77,7 @@ class Sensor340(HasIO, Readable): return IDLE, '' -class HeaterOutput(HasControlledBy, HasIO, Writable): +class HeaterOutput(LakeShore, HasControlledBy, HasIO, Writable): loop = Property('lakeshore loop', IntRange(1, 2), default=1) channel = Property('attached channel', StringType()) max_power = Parameter('max heater power', datatype=FloatRange(0, 100), unit='W', readonly=False) @@ -107,9 +119,9 @@ class HeaterOutput(HasControlledBy, HasIO, Writable): break prev = power self._range = irange - # CLIMIT + RANGE (using setpoint limit 999) - self.communicate(f'CLIMIT {self.loop},{self.SETPOINTLIMS},0,0,{icurrent},{irange}; RANGE {irange};' - f'CDISP {self.loop},1,{self.resistance},0;CDISP?{self.loop}') + self.communicate(f'CLIMIT {self.loop},{self.SETPOINTLIMS},0,0,{icurrent},{irange};' + f'RANGE {irange};' + f'CDISP {self.loop},1,{self.resistance},0;RANGE?') return self.read_max_power() def read_max_power(self): @@ -122,14 +134,14 @@ class HeaterOutput(HasControlledBy, HasIO, Writable): return max_power def set_range(self): - self.communicate(f'RANGE {self._range}; RANGE?') + self.set_par('RANGE ', {self._range}) def percent_to_power(self, percent): return min((percent / 100) ** 2 * self._max_power, 2500 / self.resistance) def power_to_percent(self, power): - return (power / self._max_power) ** (1/2) * 100 # limit + return (power / self._max_power) ** (1 / 2) * 100 # limit def read_value(self): return self.percent_to_power(float(self.communicate(f'HTR?'))) @@ -143,17 +155,19 @@ class HeaterOutput(HasControlledBy, HasIO, Writable): self.set_heater_mode(3) self.set_range() percent = self.power_to_percent(target) - reply = self.communicate(f'MOUT {self.loop},{percent:g};MOUT? {self.loop}') + reply = self.set_par(f'MOUT {self.loop}, {percent:g}') return self.percent_to_power(float(reply)) def set_heater_mode(self, mode): - self.communicate(f'CSET {self.loop},{self.channel},1,1,0; CMODE {self.loop},{int(mode)}; CMODE?{self.loop}') + self.communicate(f'CSET {self.loop},{self.channel},1,1,0') + self.set_par(f'CMODE {self.loop}, {int(mode)}') -class TemperatureLoop340(HasOutputModule, Sensor340, Drivable): +class TemperatureLoop340(HasOutputModule, Sensor340, Drivable, LakeShore): target = Parameter(unit='K') - # max_power = Parameter('max heater power', datatype=FloatRange(0, 100), unit='W', readonly=False) - # max_current = Parameter('max heater current', datatype=float, unit='A', readonly=False) + ctrlpars = Parameter('PID parameters', + StructOf(p=FloatRange(0, 1000), i=FloatRange(0, 1000), d=FloatRange(0, 1000)), + readonly=False) loop = Property('lakeshore loop', IntRange(1, 2), default=1) def write_target(self, target): @@ -164,10 +178,22 @@ class TemperatureLoop340(HasOutputModule, Sensor340, Drivable): out.write_max_power(out.max_power) self.activate_output() out.set_range() - reply = self.communicate(f'SETP {self.loop},{target};SETP? {self.loop}') + reply = self.set_par(f'SETP {self.loop},{target}') return float(reply) def read_target(self): - return float(self.communicate(f'SETP?{self.loop}')) + return float(self.communicate(f'SETP? {self.loop}')) + + def write_ctrlpars(self, ctrlpars): + p, i, d = self.set_par(f'PID {self.loop}', ctrlpars['p'], ctrlpars['i'], ctrlpars['d']) + return {'p': p, 'i': i, 'd': d} + + def read_ctrlpars(self): + p, i, d = self.get_par(f'PID? {self.loop}') + return {'p': p, 'i': i, 'd': d} + + + +