Software PID
A proportional-integral-derivative controller (PID controller) is a feedback-based control loop mechanism that is widely employed in industrial control systems and a variety of other applications requiring constantly modulated control. Hence the name, a PID controller constantly calculates an error value e as the difference between a desired set-point (SP) and a measured process variable (PV) and then makes a correction based on proportional, integral, and derivative terms (denoted P, I, and D, respectively).
The PID control scheme is named for its three correcting terms, the sum of which represents the variable being controlled. The proportional, integral, and derivative terms are added together to determine the PID controller’s output. Using U_out as the output of the controller, the final version of the PID algorithm is
where:
- ( K_p ) is the proportional gain, a tuning parameter.
- ( K_i ) is the integral gain, a tuning parameter.
- ( K_d ) is the derivative gain, a tuning parameter.
- ( e(t) ) is the error, defined as the difference between the set-point (SP) and the process variable (PV(t)).
- ( t ) is the time or instantaneous time (the present).
- ( T ) is the variable of integration, taking on values from time ( 0 ) to the present time ( t ).
Proportional term
The output produced by the proportional term is proportionate to the current error value. Adjusting the proportional response is accomplished by multiplying the error by the proportional gain constant, $K_p$.
A high proportional gain causes a substantial change in output for a given error change. If the proportionate gain is excessively large, the system may become unstable. A modest gain, on the other hand, results in a limited output reaction to a big input error and a controller that is less responsive or sensitive. In response to system disturbances, the control action may be too modest if the proportional gain is too low.
Integral term
The contribution made by the integral term is proportional to both the amount and duration of the mistake. In a PID controller, the integral is the total of the instantaneous error across time and provides the cumulative offset that should have been rectified before. Error accumulation is then multiplied by integral gain $K_i$ and added to the controller output.
The integral term speeds the process’s approach to the set-point and removes the residual steady-state error that happens with a proportional controller. Nevertheless, as the integral term responds to mistakes accumulated in the past, it might lead the current result to exceed the set-point value.
Derivative term
Calculating the process error’s derivative involves finding the error’s slope over time and multiplying this rate of change by the derivative gain $K_d$. The size of the derivative term’s contribution to the total control action is known as the derivative gain, or $K_d$.
Derivative action enhances the system’s settling time and stability by predicting its behavior. Implementations of PID controllers require extra low-pass filtering for the derivative term to reduce high-frequency gain and noise because an ideal derivative is not causative.
Code
import time
from PyQt5.QtCore import QObject
import pyexcel as p
class BasisTempStabilizer(QObject):
def __init__(self, data, pid_mutex, the_mutex, pid, thermostat, settings):
DATA = data
SETTINGS = settings
PID = pid
THE = thermostat
PIDMUX = pid_mutex
THEMUX = the_mutex
first_iteration = True
previousTime = 0
sleepTime = 1
pidP = SETTINGS.pidP
pidI = SETTINGS.pidI
pidD = SETTINGS.pidD
erri = 0
errd = 0
errPrev = 0
while True:
with PIDMUX:
if DATA.sigmaMode:
th0 = 0.5*(PID.getSensorTemp(1) + PID.getSensorTemp(2))
else:
th0 = PID.getSensorTemp(2)
currentTime = time.time()
dt = currentTime - previousTime
previousTime = currentTime
# initial good guess for the thermostat target temperature
th1 = self.ThermostatFluidTargetTemperature(DATA.stabilizerTargetTemp)
err = DATA.stabilizerTargetTemp - th0
# start controlling the thermostat actively only when we are close to the target temperature
# PID control
if abs(err) < 1 or not DATA.sigmaMode:
# proportional term
th1 += pidP*err
# integral term
if not first_iteration:
erri += err*dt
th1 += pidI*erri
# derrivative term
if not first_iteration:
errd = (err - errPrev)/dt
errPrev = err
th1 += pidD*errd
first_iteration = False
else:
first_iteration = True
erri = 0
errPrev = 0
errPrev = err
with THEMUX:
DATA.thermostatTargetTemp = th1
THE.setTargetTemperature(th1)
# stop thread check
if DATA.stabilizerStopThread:
break
# pause thread check
while DATA.stabilizerPauseThread:
time.sleep(0)
time.sleep(sleepTime)
def ThermostatFluidTargetTemperature(self, coldBasisTargetTemperature):
a = - 0.000108772
b = 1.06805
c = - 1.82042
x = coldBasisTargetTemperature
return a*x*x + b*x + c