PID, although developed in the 1940s, has had staying power as a technique for developing closed-loop process control systems. The reason for its longevity is that PID is easily implemented in software and performs well for linear control problems. PID works very well when the suitable gain values are employed and the system responds smoothly over the range of interest. A non-linear system can usually be controlled by dividing it into multiple ranges, and selecting optimal gain values for each range.
E = Setpoint - PV
CV = Kp * E + Ki * Esum + Kd * PVdelta
PV = ProcessFunction(CV)
CV is the control variable. This value might be a voltage or valve position - something that causes the control system to change. Increasing the control variable eventually results in a measurable increase in the PV. Similarly, decreasing the CV causes the process to decrease the PV. A car's throttle position is the CV in a cruise-control application.
E is the error, the difference between the desired value (Setpoint) and the latest measured process variable (PV) value. The value of E is positive while PV is too low, and negative when PV is too large.
Esum is the sum of errors (E). This sum is updated at a regular interval where Esum = Esum + E. When E is positive (PV is too low) then Esum will grow larger at each update. When E is negative (PV is too high) then Esum will become smaller, or even grow negatively. When E is zero (PV is at the setpoint) then Esum remains constant. When the system is stable, both E and PVdelta are zero, and the only component contributing to CV is the Ki * Esum term.
Kd is the derivative gain. This factor controls how strongly the control system will react to changes in the process variable (PV) value. The affect of the Kd * PVdelta component is to dampen the system by reducing acceleration. Many systems run fine with Kd set to 0, resulting in what is known as a PI control loop.
Ki is the integral gain. This factor controls how strongly the control system will react to the continuous sum (Esum) of errors (E).
Kp is the proportional gain. This factor controls how strongly the control loop will react to the instantaneous error (E). The Kp * E component is positive when PV is too low, negative when PV is too high, and zero when the PV is at the set point value.
ProcessFunction represents the process. Given a control input CV, the process will, after some delay, update some easily measured parameter, PV. The purpose of the PID control loop is to adjust the value of CV to obtain the desired value for PV (and thereby make something work a little better).
PV is the process variable value. This is some aspect of the process that can be measured - and therefore managed. The PV is what we are trying to control. Changing the control variable (CV) tweeks the process and eventually results in a change to the measured PV value. A car's speed is the PV in a cruise-control application.
PVdelta is the rate of change of the process variable (PV) value. This can be calculated by subtracting the latest PV measurement from the previously measured PV value. The PVdelta is negative when PV is increasing, and positive when PV is decreasing. A car's acceleration is the PVdelta in a cruise-control application.
Setpoint is the desired value for the process variable (PV). A car's desired cruising speed is the Setpoint in a cruise-control application.
The most flexible way to view the PID calculation is as 3 independent terms that sum to become the control variable value. That is, CV = P+I+D. This arrangement of the PID calculation yields flexibility in adjusting gain values. The following sections break down how each term is calculated.
Proportional Term (Kp * E)
The proportional term of CV can be updated as often as new measurements of PV can be obtained. Unlike the Integral and Derivative terms, there is no reason to wait for the process to respond to the latest correction. The proportional correction to CV can be applied the instant that any Error is detected. In practice, it is usually a good idea to avoid computing Kp * E when E is lower than some threshold in order to avoid making constant small corrections to CV due to noise in the measurement of PV. Such a "dead-zone" can avoid wear and tear by preventing unnecessary "hunting" around the setpoint.
The proportional term of CV gets progressively weaker as the PV gets closer to the Setpoint. After some time, the Kp * E will exactly balance drag or friction in the process and reach a stable point where PV is just below the Setpoint.
Selecting a value for Kp can be determined by experimentation. Start with Ki and Kd at zero. Begin with estimated values and then increase Kp until the control system oscillates, then back off to a stable setting. The Kp may later be increased after adjusting Kd.
Integral Term (Ki * Esum)
The integral term of CV can be updated at a frequency that is limited by the hysteresis in the system. The PID should update the CV then wait for sufficient time to allow the process to make a significant and measureable affect on the PV before the next calculation. At each calculation, Esum = Esum + E. In most applications, the integral term should not be allowed to exceed the lower and upper limits for the CV (Esum < CVmax/Ki). As with the proportional term, it is good practice to not update the integral term when the Error (E) is below some threshold of tolerance. This can avoid constant small changes to CV, causing unnecessary wear on the components of the control system.
The integral term of CV will grow (or shrink) indefinitely until the Error (E) becomes zero. In this way, a PI or PID loop will eventually drag PV to the setpoint.
Selecting a value for Ki can be determined by experimentation. Start with small values and increase Ki until oscillation is first observed. Reduce Kp to remove the oscillation.
Derivative Term (Kd * PVdelta)
The derivative term of CV is updated at a frequency that is limited by the hysteresis in the system. The PID should update the CV then wait for sufficient time to allow the process to make a significant and measureable affect on the PV before the next calculation. Normally, the derivative and integral terms of the PID equation are calculated at the same frequency. At each calculation, PVdelta = PVprevious - PVnow.
The derivative term of CV will become large when PV is changing quickly, but is not a factor in systems that change very slowly. This component tends to dampen the system and its use may allow larger values for Kp without oscillation.
Selection of the best values for Kd requires iterative testing. First choose a trial value for Kd, then increase Kp until oscillation is observed. Try to remove the oscillation by increasing Kd. If that works, then repeat - increasing Kp to oscillation, and then increasing Kd to remove it. Use the largest gain settings that work well at both minimum and maximum useful Setpoint values.
The following psuedocode can be used as the basis for a simple PID implementation
// PID Example using integers
// Arbitrary numbers - pick appropriate values for
// the system of interest.
// INTERVAL = milliseconds for PV to react to CV
#define CVmax 255 // 0 to 255
#define PVmax 100 // 0 to 100%
#define INTERVAL 500 // 500ms between "I&D" updates
#define THRESHOLD 2 // error tolerance
// Make these run-time tunable in a real system.
// The GAIN macro divides the gain values by 100
// to allow finer granularity using integer arithmetic.
#define Kp 500 // Kp = 5.000
#define Ki 10 // Ki = 0.100
#define Kd 10000 // Kd = 100.0
#define GAIN(g,v) (((g)*(v)+50)/100)
int esum; // sum of errors
int pvprev; // saved previous pv value
int cvi; // integral component of CV
int cvd; // derivative component of CV
// For timekeeping
// time.h is standard C, defines CLOCKS_PER_SEC
// MS() returns milliseconds elapsed since (t)
clock_t stamp; // saved timestamp (from clock())
#define MS(t) (((clock()-(t))*1000)/CLOCKS_PER_SEC)
// PID function - given a PV and Setpoint, returns the CV.
// Call this function after each time the system obtains
// a fresh value for PV.
int pid (int pv, int setpoint)
int cv; // return value
error = setpoint - pv;
if ( abs(error) < THRESHOLD )
// Error is within tolerance.
error = 0;
// Compute proportional term
cv = GAIN(Kp, error); // Kp * E
if ( MS(stamp) >= INTERVAL )
// it has been long enough since last call to
// this function for the pv value to have been
// affected by the previously computed cv
stamp = clock();
// Compute integral term by summing errors.
esum = esum + error;
// Limit integral term to CV range.
if ( esum > CVmax/Ki )
esum = CVmax/Ki;
if ( esum < 0 )
esum = 0;
// calculate the integral term
cvi = GAIN(Ki, esum); // Ki * Esum;
// calculate the derivative term
cvd = GAIN(Kd, pvprev - pv); // Kd * PVdelta
pvprev = pv;
// Add terms: P+I+D
cv = cv + cvi + cvd;
// Limit cv to allowed values
if ( cv < 0 )
cv = 0;
if ( cv > CVmax )
cv = CVmax;
Advanced IC Engineering (ADVICE) makes no warranties with respect to this documentation and disclaims any implied warranties of merchantability and fitness for a particular purpose. ADVICE assumes no responsibility for any errors that may appear on this site. The information contained on this site is subject to change without notice and does not represent a commitment on the part of ADVICE.
If you have comments or questions about the information presented, please contact us.