pytec: clean up styling issues
parent
14a027c0f0
commit
6ea41d5cc8
|
@ -1,8 +1,8 @@
|
||||||
import math
|
import math
|
||||||
import logging
|
import logging
|
||||||
from time import time
|
|
||||||
from collections import deque, namedtuple
|
from collections import deque, namedtuple
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from pytec.client import Client
|
from pytec.client import Client
|
||||||
|
|
||||||
# Based on hirshmann pid-autotune libiary
|
# Based on hirshmann pid-autotune libiary
|
||||||
|
@ -10,6 +10,7 @@ from pytec.client import Client
|
||||||
# Which is in turn based on a fork of Arduino PID AutoTune Library
|
# Which is in turn based on a fork of Arduino PID AutoTune Library
|
||||||
# See https://github.com/t0mpr1c3/Arduino-PID-AutoTune-Library
|
# See https://github.com/t0mpr1c3/Arduino-PID-AutoTune-Library
|
||||||
|
|
||||||
|
|
||||||
class PIDAutotuneState(Enum):
|
class PIDAutotuneState(Enum):
|
||||||
STATE_OFF = 'off'
|
STATE_OFF = 'off'
|
||||||
STATE_RELAY_STEP_UP = 'relay step up'
|
STATE_RELAY_STEP_UP = 'relay step up'
|
||||||
|
@ -17,10 +18,11 @@ class PIDAutotuneState(Enum):
|
||||||
STATE_SUCCEEDED = 'succeeded'
|
STATE_SUCCEEDED = 'succeeded'
|
||||||
STATE_FAILED = 'failed'
|
STATE_FAILED = 'failed'
|
||||||
|
|
||||||
class PIDAutotune():
|
|
||||||
|
class PIDAutotune:
|
||||||
PIDParams = namedtuple('PIDParams', ['Kp', 'Ki', 'Kd'])
|
PIDParams = namedtuple('PIDParams', ['Kp', 'Ki', 'Kd'])
|
||||||
|
|
||||||
PEAK_AMPLITUDE_TOLERANCE = 0.05
|
PEAK_AMPLITUDE_TOLERANCE = 0.05
|
||||||
|
|
||||||
_tuning_rules = {
|
_tuning_rules = {
|
||||||
"ziegler-nichols": [0.6, 1.2, 0.075],
|
"ziegler-nichols": [0.6, 1.2, 0.075],
|
||||||
|
@ -31,10 +33,11 @@ class PIDAutotune():
|
||||||
"no-overshoot": [0.2, 0.4, 0.0667]
|
"no-overshoot": [0.2, 0.4, 0.0667]
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, setpoint, out_step=10, lookback=60, noiseband=0.5, sampletime=1.2):
|
def __init__(self, setpoint, out_step=10, lookback=60,
|
||||||
|
noiseband=0.5, sampletime=1.2):
|
||||||
if setpoint is None:
|
if setpoint is None:
|
||||||
raise ValueError('setpoint must be specified')
|
raise ValueError('setpoint must be specified')
|
||||||
|
|
||||||
self._inputs = deque(maxlen=round(lookback / sampletime))
|
self._inputs = deque(maxlen=round(lookback / sampletime))
|
||||||
self._setpoint = setpoint
|
self._setpoint = setpoint
|
||||||
self._outputstep = out_step
|
self._outputstep = out_step
|
||||||
|
@ -52,11 +55,11 @@ class PIDAutotune():
|
||||||
self._induced_amplitude = 0
|
self._induced_amplitude = 0
|
||||||
self._Ku = 0
|
self._Ku = 0
|
||||||
self._Pu = 0
|
self._Pu = 0
|
||||||
|
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Get the current state."""
|
"""Get the current state."""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
def output(self):
|
def output(self):
|
||||||
"""Get the last output value."""
|
"""Get the last output value."""
|
||||||
return self._output
|
return self._output
|
||||||
|
@ -129,7 +132,7 @@ class PIDAutotune():
|
||||||
|
|
||||||
self._inputs.append(input_val)
|
self._inputs.append(input_val)
|
||||||
|
|
||||||
# we don't want to trust the maxes or mins until the input array is full
|
# we don't trust the maxes or mins until the input array is full
|
||||||
if len(self._inputs) < self._inputs.maxlen:
|
if len(self._inputs) < self._inputs.maxlen:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -164,14 +167,16 @@ class PIDAutotune():
|
||||||
abs_max = self._peaks[-2]
|
abs_max = self._peaks[-2]
|
||||||
abs_min = self._peaks[-2]
|
abs_min = self._peaks[-2]
|
||||||
for i in range(0, len(self._peaks) - 2):
|
for i in range(0, len(self._peaks) - 2):
|
||||||
self._induced_amplitude += abs(self._peaks[i] - self._peaks[i+1])
|
self._induced_amplitude += abs(self._peaks[i]
|
||||||
|
- self._peaks[i+1])
|
||||||
abs_max = max(self._peaks[i], abs_max)
|
abs_max = max(self._peaks[i], abs_max)
|
||||||
abs_min = min(self._peaks[i], abs_min)
|
abs_min = min(self._peaks[i], abs_min)
|
||||||
|
|
||||||
self._induced_amplitude /= 6.0
|
self._induced_amplitude /= 6.0
|
||||||
|
|
||||||
# check convergence criterion for amplitude of induced oscillation
|
# check convergence criterion for amplitude of induced oscillation
|
||||||
amplitude_dev = ((0.5 * (abs_max - abs_min) - self._induced_amplitude)
|
amplitude_dev = ((0.5 * (abs_max - abs_min)
|
||||||
|
- self._induced_amplitude)
|
||||||
/ self._induced_amplitude)
|
/ self._induced_amplitude)
|
||||||
|
|
||||||
logging.debug('amplitude: {0}'.format(self._induced_amplitude))
|
logging.debug('amplitude: {0}'.format(self._induced_amplitude))
|
||||||
|
@ -179,7 +184,7 @@ class PIDAutotune():
|
||||||
|
|
||||||
if amplitude_dev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE:
|
if amplitude_dev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE:
|
||||||
self._state = PIDAutotuneState.STATE_SUCCEEDED
|
self._state = PIDAutotuneState.STATE_SUCCEEDED
|
||||||
|
|
||||||
# if the autotune has not already converged
|
# if the autotune has not already converged
|
||||||
# terminate after 10 cycles
|
# terminate after 10 cycles
|
||||||
if self._peak_count >= 20:
|
if self._peak_count >= 20:
|
||||||
|
@ -192,7 +197,8 @@ class PIDAutotune():
|
||||||
logging.debug('peak finding successful')
|
logging.debug('peak finding successful')
|
||||||
|
|
||||||
# calculate ultimate gain
|
# calculate ultimate gain
|
||||||
self._Ku = 4.0 * self._outputstep / (self._induced_amplitude * math.pi)
|
self._Ku = 4.0 * self._outputstep / \
|
||||||
|
(self._induced_amplitude * math.pi)
|
||||||
print('Ku: {0}'.format(self._Ku))
|
print('Ku: {0}'.format(self._Ku))
|
||||||
|
|
||||||
# calculate ultimate period in seconds
|
# calculate ultimate period in seconds
|
||||||
|
@ -206,12 +212,12 @@ class PIDAutotune():
|
||||||
print('rule: {0}'.format(rule))
|
print('rule: {0}'.format(rule))
|
||||||
print('Kp: {0}'.format(params.Kp))
|
print('Kp: {0}'.format(params.Kp))
|
||||||
print('Ki: {0}'.format(params.Ki))
|
print('Ki: {0}'.format(params.Ki))
|
||||||
print('Kd: {0}'.format(params.Kd))
|
print('Kd: {0}'.format(params.Kd))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def init_tuner(self, inputValue, timestamp):
|
def init_tuner(self, input_value, timestamp):
|
||||||
self._peak_type = 0
|
self._peak_type = 0
|
||||||
self._peak_count = 0
|
self._peak_count = 0
|
||||||
self._output = 0
|
self._output = 0
|
||||||
|
@ -224,6 +230,7 @@ class PIDAutotune():
|
||||||
self._peak_timestamps.append(timestamp)
|
self._peak_timestamps.append(timestamp)
|
||||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Auto tune parameters
|
# Auto tune parameters
|
||||||
# Thermostat channel
|
# Thermostat channel
|
||||||
|
@ -234,17 +241,19 @@ def main():
|
||||||
output_step = 1
|
output_step = 1
|
||||||
# Reference period for local minima/maxima, seconds
|
# Reference period for local minima/maxima, seconds
|
||||||
lookback = 3
|
lookback = 3
|
||||||
# Determines by how much the input value must overshoot/undershoot the setpoint, celcius
|
# Determines by how much the input value must
|
||||||
|
# overshoot/undershoot the setpoint, celcius
|
||||||
noiseband = 1.5
|
noiseband = 1.5
|
||||||
|
|
||||||
# logging.basicConfig(level=logging.DEBUG)
|
# logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
tec = Client()
|
tec = Client()
|
||||||
|
|
||||||
data = next(tec.report_mode())
|
data = next(tec.report_mode())
|
||||||
ch = data[channel]
|
ch = data[channel]
|
||||||
|
|
||||||
tuner = PIDAutotune(target_temperature, output_step, lookback, noiseband, ch['interval'])
|
tuner = PIDAutotune(target_temperature, output_step,
|
||||||
|
lookback, noiseband, ch['interval'])
|
||||||
|
|
||||||
for data in tec.report_mode():
|
for data in tec.report_mode():
|
||||||
try:
|
try:
|
||||||
|
@ -255,13 +264,15 @@ def main():
|
||||||
if (tuner.run(temperature, ch['time'])):
|
if (tuner.run(temperature, ch['time'])):
|
||||||
break
|
break
|
||||||
|
|
||||||
tunerOut = tuner.output()
|
tuner_out = tuner.output()
|
||||||
|
|
||||||
tec.set_param("pwm", channel, "i_set" , tunerOut)
|
tec.set_param("pwm", channel, "i_set", tuner_out)
|
||||||
|
|
||||||
except:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
tec.set_param("pwm", channel, "i_set" , channel)
|
tec.set_param("pwm", channel, "i_set", 0)
|
||||||
|
|
||||||
if __name__ == "__main__": main()
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue