PyThermostat: Modify PIDAutotune for GUI usage #162
@ -2,7 +2,7 @@ import math
|
||||
import logging
|
||||
import time
|
||||
from collections import deque, namedtuple
|
||||
from enum import Enum
|
||||
from enum import Enum, auto
|
||||
|
||||
from pythermostat.client import Client
|
||||
|
||||
@ -13,11 +13,12 @@ from pythermostat.client import Client
|
||||
|
||||
|
||||
class PIDAutotuneState(Enum):
|
||||
STATE_OFF = 'off'
|
||||
STATE_RELAY_STEP_UP = 'relay step up'
|
||||
STATE_RELAY_STEP_DOWN = 'relay step down'
|
||||
STATE_SUCCEEDED = 'succeeded'
|
||||
STATE_FAILED = 'failed'
|
||||
OFF = auto()
|
||||
RELAY_STEP_UP = auto()
|
||||
RELAY_STEP_DOWN = auto()
|
||||
SUCCEEDED = auto()
|
||||
FAILED = auto()
|
||||
READY = auto()
|
||||
|
||||
|
||||
|
||||
class PIDAutotune:
|
||||
@ -45,7 +46,7 @@ class PIDAutotune:
|
||||
self._noiseband = noiseband
|
||||
self._out_min = -out_step
|
||||
self._out_max = out_step
|
||||
self._state = PIDAutotuneState.STATE_OFF
|
||||
self._state = PIDAutotuneState.OFF
|
||||
self._peak_timestamps = deque(maxlen=5)
|
||||
self._peaks = deque(maxlen=5)
|
||||
self._output = 0
|
||||
@ -57,6 +58,21 @@ class PIDAutotune:
|
||||
self._Ku = 0
|
||||
self._Pu = 0
|
||||
|
||||
def set_param(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 set_ready(self):
|
||||
self._state = PIDAutotuneState.READY
|
||||
self._peak_count = 0
|
||||
|
||||
def set_off(self):
|
||||
self._state = PIDAutotuneState.OFF
|
||||
|
||||
def state(self):
|
||||
"""Get the current state."""
|
||||
return self._state
|
||||
@ -94,29 +110,30 @@ class PIDAutotune:
|
||||
"""
|
||||
now = time_input * 1000
|
||||
|
||||
if (self._state == PIDAutotuneState.STATE_OFF
|
||||
or self._state == PIDAutotuneState.STATE_SUCCEEDED
|
||||
or self._state == PIDAutotuneState.STATE_FAILED):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
if self._state not in {
|
||||
esavkin
commented
Isn't there a way to shorten it? Isn't there a way to shorten it?
atse
commented
Yep, did it in the latest force-push to Yep, did it in the latest force-push to 828648ed76.
esavkin
commented
Wouldn't the negative logic be applicable here? Like Wouldn't the negative logic be applicable here? Like `not in (STEP_UP, STEP_DOWN)`.
atse
commented
Humm, that's true. Was worried about Humm, that's true. Was worried about `self._state` being set to a non-`PIDAutotuneState` value, but that shouldn't happen under normal circumstances.
atse
commented
Done in force-push to Done in force-push to f4c1dab00f.
|
||||
PIDAutotuneState.RELAY_STEP_DOWN,
|
||||
PIDAutotuneState.RELAY_STEP_UP,
|
||||
}:
|
||||
self._state = PIDAutotuneState.RELAY_STEP_UP
|
||||
|
||||
self._last_run_timestamp = now
|
||||
|
||||
# check input and change relay state if necessary
|
||||
if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
and input_val > self._setpoint + self._noiseband):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
||||
if self._state == PIDAutotuneState.RELAY_STEP_UP
|
||||
and input_val > self._setpoint + self._noiseband:
|
||||
self._state = PIDAutotuneState.RELAY_STEP_DOWN
|
||||
logging.debug('switched state: {0}'.format(self._state))
|
||||
logging.debug('input: {0}'.format(input_val))
|
||||
elif (self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
||||
and input_val < self._setpoint - self._noiseband):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
elif self._state == PIDAutotuneState.RELAY_STEP_DOWN
|
||||
and input_val < self._setpoint - self._noiseband:
|
||||
self._state = PIDAutotuneState.RELAY_STEP_UP
|
||||
logging.debug('switched state: {0}'.format(self._state))
|
||||
logging.debug('input: {0}'.format(input_val))
|
||||
|
||||
# set output
|
||||
if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP):
|
||||
if self._state == PIDAutotuneState.RELAY_STEP_UP:
|
||||
self._output = self._initial_output - self._outputstep
|
||||
elif self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN:
|
||||
elif self._state == PIDAutotuneState.RELAY_STEP_DOWN:
|
||||
self._output = self._initial_output + self._outputstep
|
||||
|
||||
# respect output limits
|
||||
@ -184,16 +201,16 @@ class PIDAutotune:
|
||||
logging.debug('amplitude deviation: {0}'.format(amplitude_dev))
|
||||
|
||||
if amplitude_dev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE:
|
||||
self._state = PIDAutotuneState.STATE_SUCCEEDED
|
||||
self._state = PIDAutotuneState.SUCCEEDED
|
||||
|
||||
# if the autotune has not already converged
|
||||
# terminate after 10 cycles
|
||||
if self._peak_count >= 20:
|
||||
self._output = 0
|
||||
self._state = PIDAutotuneState.STATE_FAILED
|
||||
self._state = PIDAutotuneState.FAILED
|
||||
return True
|
||||
|
||||
if self._state == PIDAutotuneState.STATE_SUCCEEDED:
|
||||
if self._state == PIDAutotuneState.SUCCEEDED:
|
||||
self._output = 0
|
||||
logging.debug('peak finding successful')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user
Inconsistent string delimiter.
Can't it just use
auto()
anyway?Actually yes, switched to
auto()
in force-push to828648ed76
.Then I believe #71 would be unnecessary since the string values aren't used anywhere.
Also just realised this highlights the verbosity of the
STATE_
prefix.Refactored in force-push to
869922c928
.