Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Proportional–integral–derivative controller
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Pseudocode== Here is a very simple and explicit group of pseudocode that can be easily understood by the layman:{{Citation needed|date=February 2024}} * Kp - proportional gain * Ki - integral gain * Kd - derivative gain * dt - loop interval time (assumes reasonable scale)<ref group="lower-alpha">Note that for very small intervals (e.g. 60Hz/<math display="inline">.016\bar{6}</math> seconds), the resulting derivative value will be extremely large, and orders of magnitude larger than the proportional or integral components. Adjusting this value for the derivative (e.g. multiplying by 1000) or changing the division to multiplication is likely to yield the intended results. This holds true for all pseudocode presented here.</ref> previous_error := 0 integral := 0 loop: error := setpoint − measured_value proportional := error; integral := integral + error × dt derivative := (error - previous_error) / dt output := Kp × proportional + Ki × integral + Kd × derivative previous_error := error wait(dt) goto loop Below a pseudocode illustrates how to implement a PID considering the PID as an [[Infinite impulse response|IIR]] filter: The [[Z-transform]] of a PID can be written as (<math>\Delta_t</math> is the sampling time): :<math>C(z)= K_p + K_i\Delta_t \frac{z}{z-1} + \frac{K_d}{\Delta_t} \frac{z-1}{z}</math> and expressed in a IIR form (in agreement with the discrete implementation shown above): :<math>C(z)=\frac{\left(K_p+K_i\Delta_t+\dfrac{K_d}{\Delta_t}\right)+\left(-K_p-\dfrac{2K_d}{\Delta_t}\right) z^{-1} + \dfrac{K_d}{\Delta_t}z^{-2}}{1-z^{-1}}</math> We can then deduce the recursive iteration often found in FPGA implementation<ref> {{cite book|first1=Bhushana|language=en|last1=Thakur|title=Hardware {{as written|Implim|entation [sic]}} of FPGA based PID Controller|url=https://www.ijert.org/research/hardware-implimentation-of-fpga-based-pid-controller-IJERTV4IS020719.pdf}}<!-- auto-translated by Module:CS1 translator --> </ref> :<math>u[n] = u[n-1] + \left(K_p+ K_i\Delta_t+\dfrac{K_d}{\Delta_t}\right)\epsilon[n] + \left(-K_p-\dfrac{2K_d}{\Delta_t}\right)\epsilon[n-1] + \dfrac{K_d}{\Delta_t}\epsilon[n-2]</math> A0 := Kp + Ki*dt + Kd/dt A1 := -Kp - 2*Kd/dt A2 := Kd/dt error[2] := 0 // e(t-2) error[1] := 0 // e(t-1) error[0] := 0 // e(t) output := u0 // Usually the current value of the actuator loop: error[2] := error[1] error[1] := error[0] error[0] := setpoint − measured_value output := output + A0 * error[0] + A1 * error[1] + A2 * error[2] wait(dt) goto loop Here, Kp is a dimensionless number, Ki is expressed in <math>s^{-1}</math> and Kd is expressed in s. When doing a regulation where the actuator and the measured value are not in the same unit (ex. temperature regulation using a motor controlling a valve), Kp, Ki and Kd may be corrected by a unit conversion factor. It may also be interesting to use Ki in its reciprocal form (integration time). The above implementation allows to perform an I-only controller which may be useful in some cases. In the real world, this is [[digital-to-analog converter|D-to-A converted]] and passed into the process under control as the manipulated variable (MV). The current error is stored elsewhere for re-use in the next differentiation, the program then waits until dt seconds have passed since start, and the loop begins again, [[analog-to-digital converter|reading in]] new values for the PV and the setpoint and calculating a new value for the error.<ref name="codeproject">{{cite web |url=http://www.codeproject.com/Articles/36459/PID-process-control-a-Cruise-Control-example |title=PID process control, a "Cruise Control" example |publisher=CodeProject |access-date=4 November 2012 |year=2009}}</ref> Note that for real code, the use of "wait(dt)" might be inappropriate because it doesn't account for time taken by the algorithm itself during the loop, or more importantly, any pre-emption delaying the algorithm. A common issue when using <math>K_d</math> is the response to the derivative of a rising or falling edge of the setpoint as shown below: [[File:PID nofilter.gif|PID without derivative filtering]] A typical workaround is to filter the derivative action using a low pass filter of time constant <math>\tau_d/N</math> where <math>3<=N<=10</math>: [[File:PID filter.gif|PID with derivative filtering]] A variant of the above algorithm using an [[infinite impulse response]] (IIR) filter for the derivative: A0 := Kp + Ki*dt A1 := -Kp error[2] := 0 // e(t-2) error[1] := 0 // e(t-1) error[0] := 0 // e(t) output := u0 // Usually the current value of the actuator A0d := Kd/dt A1d := - 2.0*Kd/dt A2d := Kd/dt N := 5 tau := Kd / (Kp*N) // IIR filter time constant alpha := dt / (2*tau) d0 := 0 d1 := 0 fd0 := 0 fd1 := 0 loop: error[2] := error[1] error[1] := error[0] error[0] := setpoint − measured_value // PI output := output + A0 * error[0] + A1 * error[1] // Filtered D d1 := d0 d0 := A0d * error[0] + A1d * error[1] + A2d * error[2] fd1 := fd0 fd0 := ((alpha) / (alpha + 1)) * (d0 + d1) - ((alpha - 1) / (alpha + 1)) * fd1 output := output + fd0 wait(dt) goto loop
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)