Closed Feargus closed 5 years ago
Hi!
Thanks for your feedback. You are correct in that the P-term is limited by the library to be in the output limits when using proportional on measurement, and I do agree with you that this is probably not how it should be. The problem with just removing it though is that the P-term could start growing kind of like in integral windup, although I don't know how big of a problem it would be. I will see if I can come up with a better solution when I have time.
Maybe a simple toggle? Right now, the PoM mode is useless to me, because even after symmetric bounds, and a parameter transformation, the system doesn't really work as intended, due to the way bounds are used. Anyway, I don't really see how the P-term could wind up. It is (anti-)proportional to the measurement, and tries to return the system to the initial state, no? It acts more like a friction, than a driving force. The I-term on the other hand, potentially increases without bounds in a static system away from the setpoint.
For example, a heater with a large thermal load (a large water pot) on top, takes a long time to reach the setpoint, and the I-term grows without bounds. If you then take off the pot, the system will strongly overshoot, due to the lower "inertia". The P-term doesn't change all this time, since the temperature doesn't change either. Anyway I'll leave you in peace now, thanks for your library, I'll try to make do as is.
You could just overwrite PID
's __call__
method, commenting out the line you don't want/need, like so:
class CustomPID(PID):
def __call__(self, input_, **kwargs):
if not self.auto_mode:
return self._last_output
now = _current_time()
dt = now - self._last_time if now - self._last_time else 1e-16
if (
self.sample_time is not None
and dt < self.sample_time
and self._last_output is not None
):
# Only update every sample_time seconds
return self._last_output
# Compute error terms
error = self.setpoint - input_
d_input = input_ - (
self._last_input if self._last_input is not None else input_
)
# 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._proportional -= self.Kp * d_input
# self._proportional = self._clamp(self._proportional, self.output_limits)
# Compute integral and derivative terms
self._integral += self.Ki * error * dt
self._integral = self._clamp(
self._integral, self.output_limits
) # avoid integral windup
self._derivative = -self.Kd * d_input / dt
# Compute final output
output = self._proportional + self._integral + self._derivative
output = self._clamp(output, self.output_limits)
# Keep track of state
self._last_output = output
self._last_input = input_
self._last_time = now
return output
def _clamp(self, value, limits):
lower, upper = limits
if value is None:
return None
elif upper is not None and value > upper:
return upper
elif lower is not None and value < lower:
return lower
return value
@Feargus I agree with your reasoning that the P-term should not be able to grow uncontrollably as the I-term. I removed the clamping on the P-term in version 0.2.2, please try it out and tell me how it works for you!
Works perfectly, thanks a lot
Hey, I'm not quite sure if this is a code issue, or if the problem is sitting in front of the keyboard. Anyway, I want to use a simple PID to control control a resistive heater via PWM on a raspberry pi. In the "normal", proportional-on-error mode, everything works fine. However, using proportional-on-measurement = True, I for the life of me cannot get the P-term to become negative (checking with print(pid.components)). This seems to be caused by my output limits of [0,100] (which are the limits for the PWM control). From what I understand from the last graph here: http://brettbeauregard.com/blog/2017/06/introducing-proportional-on-measurement/ the P term is supposed to go negative. Granted, I could change the output limits, but from what I understand, the limits should only affect the I-term. Also, the P-term goes negative just fine in the "normal" proportional-on-error mode.
From the above link, I gathered that the same tuning parameters should work for both modes with similar results. Yet neither those parameters nor any other (extremely large/small) values work.
Is this limiting of the P-term intended? Or am I doing something wrong? Thanks