From ccdff602c414b2e56e0947c060c75f007b7a0a4e Mon Sep 17 00:00:00 2001 From: topquark12 Date: Tue, 7 Jun 2022 13:54:18 +0800 Subject: [PATCH] add autotune --- pytec/autotune.py | 25 ++++++++++++++++++++++++- pytec/tecQT.py | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/pytec/autotune.py b/pytec/autotune.py index c1f593e..bf12432 100644 --- a/pytec/autotune.py +++ b/pytec/autotune.py @@ -17,6 +17,7 @@ class PIDAutotuneState(Enum): STATE_RELAY_STEP_DOWN = 'relay step down' STATE_SUCCEEDED = 'succeeded' STATE_FAILED = 'failed' + STATE_READY = 'ready' class PIDAutotune: @@ -56,6 +57,20 @@ class PIDAutotune: self._Ku = 0 self._Pu = 0 + def setParam(self, target, step, noiseband, sampletime, lookback): + self._setpoint = target + self._outputstep = step + self._out_max = step + self._out_min = -step + self._noiseband = noiseband + self._inputs = deque(maxlen=round(lookback / sampletime)) + + def setReady(self): + self._state = PIDAutotuneState.STATE_READY + + def setOff(self): + self._state = PIDAutotuneState.STATE_OFF + def state(self): """Get the current state.""" return self._state @@ -81,6 +96,13 @@ class PIDAutotune: kd = divisors[2] * self._Ku * self._Pu return PIDAutotune.PIDParams(kp, ki, kd) + def get_tec_pid (self): + divisors = self._tuning_rules["tyreus-luyben"] + kp = self._Ku * divisors[0] + ki = divisors[1] * self._Ku / self._Pu + kd = divisors[2] * self._Ku * self._Pu + return kp, ki, kd + def run(self, input_val, time_input): """To autotune a system, this method must be called periodically. @@ -95,7 +117,8 @@ class PIDAutotune: if (self._state == PIDAutotuneState.STATE_OFF or self._state == PIDAutotuneState.STATE_SUCCEEDED - or self._state == PIDAutotuneState.STATE_FAILED): + or self._state == PIDAutotuneState.STATE_FAILED + or self._state == PIDAutotuneState.STATE_READY): self._state = PIDAutotuneState.STATE_RELAY_STEP_UP self._last_run_timestamp = now diff --git a/pytec/tecQT.py b/pytec/tecQT.py index 8ca7fd9..4a94439 100644 --- a/pytec/tecQT.py +++ b/pytec/tecQT.py @@ -68,7 +68,8 @@ GUIparams = [[ {'name': 'Save to flash', 'type': 'action', 'tip': 'Save to flash'}, ] for _ in range(2)] -autoTuneState = [PIDAutotuneState.STATE_OFF, 'idle'] +autoTuner = [PIDAutotune(20, 1, 1, 1.5, refresh_period / 1000), + PIDAutotune(20, 1, 1, 1.5, refresh_period / 1000)] ## If anything changes in the tree, print a message def change(param, changes, ch): @@ -87,7 +88,8 @@ def change(param, changes, ch): if (childName == 'Disable Output'): tec.set_param('pwm', ch, 'i_set', 0) paramList[ch].child('Constant Current').child('Set Current').setValue(0) - paramList[ch].child('Temperature PID').setValue(False) + paramList[ch].child('Temperature PID').setValue(False) + autoTuner[ch].setOff() if (childName == 'Temperature PID'): if (data): @@ -130,7 +132,13 @@ def change(param, changes, ch): tec.set_param('pid', ch, 'kd', data) if (childName == 'PID Config.PID Auto Tune.Run'): - autoTuneState[ch] = 'triggered' + autoTuner[ch].setParam(paramList[ch].child('PID Config').child('PID Auto Tune').child('Target Temperature').value(), + paramList[ch].child('PID Config').child('PID Auto Tune').child('Test Current').value(), + paramList[ch].child('PID Config').child('PID Auto Tune').child('Temperature Swing').value(), + refresh_period / 1000, + 1) + autoTuner[ch].setReady() + paramList[ch].child('Temperature PID').setValue(False) if (childName == 'Save to flash'): tec.save_config() @@ -185,8 +193,8 @@ def TECsync(): if parents['tag'] == 'report': for data in tec.report_mode(): for children in parents['children']: + print(data) children['value'] = data[channel][children['tag']] - print(data[channel][children['tag']]) if quit: break if parents['tag'] == 'pwm': @@ -226,10 +234,24 @@ def updateData(): ch0currentGraph.update(data, cnt) ch1currentGraph.update(data, cnt) - for state in autoTuneState: - if state == 'triggered': - state = 'tuning' - + for channel in range (2): + if (autoTuner[channel].state() == PIDAutotuneState.STATE_READY or + autoTuner[channel].state() == PIDAutotuneState.STATE_RELAY_STEP_UP or + autoTuner[channel].state() == PIDAutotuneState.STATE_RELAY_STEP_DOWN): + autoTuner[channel].run(data[channel]['temperature'], data[channel]['time']) + tec.set_param('pwm', channel, 'i_set', autoTuner[channel].output()) + elif (autoTuner[channel].state() == PIDAutotuneState.STATE_SUCCEEDED): + kp, ki, kd = autoTuner[channel].get_tec_pid() + autoTuner[channel].setOff() + paramList[channel].child('PID Config').child('kP').setValue(kp) + paramList[channel].child('PID Config').child('kI').setValue(ki) + paramList[channel].child('PID Config').child('kD').setValue(kd) + tec.set_param('pid', channel, 'kp', kp) + tec.set_param('pid', channel, 'ki', ki) + tec.set_param('pid', channel, 'kd', kd) + elif (autoTuner[channel].state() == PIDAutotuneState.STATE_FAILED): + tec.set_param('pwm', channel, 'i_set', 0) + autoTuner[channel].setOff() if quit: break