Skip to content

Commit

Permalink
Restructured the code relating to proportional on measurement to make…
Browse files Browse the repository at this point in the history
… it more readable and easier to understand. Also allows the proportional term to be monitored properly through the components-property when ponm is enabled.
  • Loading branch information
m-lundberg committed Feb 25, 2019
1 parent 11bfe19 commit 08d1bf2
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 16 deletions.
30 changes: 16 additions & 14 deletions simple_pid/PID.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self,
self.proportional_on_measurement = proportional_on_measurement

self._proportional = 0
self._error_sum = 0
self._integral = 0
self._derivative = 0

self._last_time = _current_time()
Expand All @@ -86,24 +86,25 @@ def __call__(self, input_):

# compute error terms
error = self.setpoint - input_
self._error_sum += self.Ki * error * dt
d_input = input_ - (self._last_input if self._last_input is not None else input_)
self._derivative = -self.Kd * d_input / dt

# compute the proportional term
if not self.proportional_on_measurement:
# regular proportional-on-error, simply set the proportional term
self._proportional = self.Kp * error
else:
# add the proportional error on measurement to error_sum
self._error_sum -= self.Kp * d_input
self._proportional = 0
self._proportional -= self.Kp * d_input
self._proportional = _clamp(self._proportional, self.output_limits)

# compute integral and derivative terms
self._integral += self.Ki * error * dt
self._integral = _clamp(self._integral, self.output_limits) # avoid integral windup

# clamp error sum to avoid integral windup (and proportional, if proportional-on-measurement is used)
self._error_sum = _clamp(self._error_sum, self.output_limits)
self._derivative = -self.Kd * d_input / dt

# compute final output
output = self._proportional + self._error_sum + self._derivative
output = self._proportional + self._integral + self._derivative
output = _clamp(output, self.output_limits)

# keep track of state
Expand All @@ -118,9 +119,8 @@ def components(self):
"""
The P-, I- and D-terms from the last computation as separate components as a tuple. Useful for visualizing
what the controller is doing or when tuning hard-to-tune systems.
Note: when using *proportional_on_measurement*, the proportional error will be baked into the I-term.
"""
return self._proportional, self._error_sum, self._derivative
return self._proportional, self._integral, self._derivative

@property
def tunings(self):
Expand All @@ -145,7 +145,8 @@ def auto_mode(self, enabled):
self._last_output = None
self._last_input = None
self._last_time = _current_time()
self._error_sum = _clamp(0, self.output_limits)
self._proportional = 0
self._integral = _clamp(0, self.output_limits)

self._auto_mode = enabled

Expand All @@ -164,8 +165,9 @@ def set_auto_mode(self, enabled, last_output=None):
self._last_output = last_output
self._last_input = None
self._last_time = _current_time()
self._error_sum = (last_output if last_output is not None else 0)
self._error_sum = _clamp(self._error_sum, self.output_limits)
self._proportional = 0
self._integral = (last_output if last_output is not None else 0)
self._integral = _clamp(self._integral, self.output_limits)

self._auto_mode = enabled

Expand All @@ -192,5 +194,5 @@ def output_limits(self, limits):
self._min_output = min_output
self._max_output = max_output

self._error_sum = _clamp(self._error_sum, self.output_limits)
self._integral = _clamp(self._integral, self.output_limits)
self._last_output = _clamp(self._last_output, self.output_limits)
4 changes: 2 additions & 2 deletions tests/test_pid.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_auto_mode():
# should reset when reactivating
pid.auto_mode = True
assert pid._last_input is None
assert pid._error_sum == 0
assert pid._integral == 0
assert pid(8) == 2

# last update time should be reset to avoid huge dt
Expand All @@ -143,7 +143,7 @@ def test_auto_mode():
# check that setting last_output works
pid.auto_mode = False
pid.set_auto_mode(True, last_output=10)
assert pid._error_sum == 10
assert pid._integral == 10


def test_separate_components():
Expand Down

0 comments on commit 08d1bf2

Please sign in to comment.