Friday, 21 September 2012

PID Controller in C++

This is an old project I did to teach myself basic control theory, its a PID controller written in Visual C++ 6 using MFC.

The project also contains its own Graph MFC control which is based on MFC GDI primitives.

Its a simulation of a basic PID controller.

PID Control Theory

Proportional-Integral-Derivative (PID) is a control algorithm used to set and maintain a measurement at a set-point. The PID algorithm calculates its output by summing three terms.

  • Proportional - A value proportional to the error of the measurement. 
  • Integral - A value proportional to the integral of the error over time. 
  • Derivative - A value proportional to the rate of change of the error.

The general form of the PID equation is thus:

m(t) = K* (e(t) + Kiòe(t)dt + Kdde)
          proportional   integral       derivative


m(t) = controller output
Kc = proportional gain
Ki = integral time constant
Kd = derivative time constant
e(t)  = error as a function of time = S(t) - X(t)
S(t) = current process setpoint.
X(t) = measured input

Variables Kc, Ki and Kd are adjustable for a given application of the controller.
Computer PID algorithms are based on data sampled on a cyclic basis.

The sample based PID equation is thus:
m(i) = K* (e(i) + T*Kiåe(k) + (Kd/T)*(e(i)-e(i-1)))
           proportional    integral            derivative


T = sampling interval
e(i) = error at ith sampling interval = S(t)-X(t)
e(i-1) = error at pervious sampling interval
e(k) = error at k where k increments by 1 through the range 0 <= k <= i
m(i) = controller output
Kc = proportional gain
Ki = integral action time
Kd = derivative action time

Complex Error

In practice, the first order difference term, (e(i) - e(i-1)), is very susceptible to noise problems. In most practical systems this term is replaced by the more stable, higher order equation:

                De = ( e(i) + 3*e(i-1) - 3*e(i-2) - e(i-3) ) / 6

Ramp Limit

Many systems implement a limit on the maximum rate at which the output value can change in order to stop any physical output devices from being ‘thrashed’.


Practical systems stop the summation of error terms if the current PID output level is outside a user specified range of high and low output values. This limiting of the summation term is commonly referred to as anti-reset-windup.


The general flow of a PID control will be as follows:

PID Control Diagram

An individual PID control  will function as follows: Automatic PID control A desired value or setpoint is entered. The input will be read. The difference between the input and the setpoint or error is calculated. An output value is calculated using this information and the PID algorithm. The output is optionally limited buy various methods. The output ramping is optionally limited.

Ramp Limit

The ramp limiting is optional when the PID calculation is active. If the user output is set the ramp limiting will always be applied. The ramp limiting is specified in degrees representing the angle the output makes with the horizontal on a graph. The time axis resolution is therefore critical to the significance of this parameter. A limit of zero degrees would make output ramping impossible and a limit of 90 degrees or greater would allow maximum ramping.


Anti reset windup is only applied when selected and the PID calculation is active. The anti reset windup upper and lower bounds are specified as a percentage of the entire output range. A limit of zero percent would make output ARW impossible and a limit of 50 percent or greater would allow maximum ARW.


Tuning and control loop performance
by Gregory K. McMillan
ISBN: 1-55617-49261
ISA - The Instrumentation, Systems, and Automation Society.

Tuning of industrial control systems
by Armando B. Corripio
ISBN: 1-55617-6996
ISA - The Instrumentation, Systems, and Automation Society.

Quinn-Curtis, Real-time graphics tools for windows manual.


Source code here.
Executable here.


  1. Hello!

    I am trying to implement a PID in C++.

    I have the PID Transfer Function but it is in continuous. Does anyone have an idea on how to write it in discrete form with C++??

    Tudor V

    1. Hi Tudor !

      Try looking at the source code here.

      The discrete code is actually pretty simple.


    2. I was looking for a discrete implementation as well and couldn't open the sources codes (must be my network...). Instead I found a very good article on PID control on wikipedia including pseudocode:


  2. Hi Tudor and Jasper, the source download works fine for me, it points to google drive.

    here is the discrete code :-

    // Proportional
    m_Proportional = m_Gain * m_Error;

    // Integral
    m_Integral = m_Integral + (m_Gain * (m_IntegralAct*CycleTime) * m_Error);

    // Derivative
    m_Derivative = m_Gain * (m_DerivativeAct/CycleTime) * m_ErrorChange;

    // Calculate Output
    m_Output = (m_Proportional + m_Integral + m_Derivative);

    its from PIDDlg.cpp.

    The Wikipedia stuff is similar.

  3. previous_error = 0
    integral = 0
    error = setpoint - measured_value
    integral = integral + error*dt
    derivative = (error - previous_error)/dt
    output = Kp*error + Ki*integral + Kd*derivative
    previous_error = error
    goto start

    what is the dt in this function?

  4. I believe dt is 'Time Delta' or 'Cycle Time', its the time between measurements.

    Normally PID controller runs in a continuous loop measuring an input sensor and controlling some output like a valve.

    Since PID control is very basic the actual usefulness generally means having a cycle time much shorter than the required adjustment time, so its normally implemented in micro controllers that make thousands measurements a second.

    This very short cycle time combined with some half decent tuning is sometimes good enough for basic control. However I believe in modern control systems you adaptive control / fuzzy control etc.

  5. Hi,
    I am implementing PID controller for Temp heater. I have to read data from RS232 port, and draw graph for the SP, PV and PID output. I tried to open source code you shared on this page, but unfortunately it is no more available on google page.
    Please share the C++ source code.

    1. Sandy, I have no problem accessing the code and the permissions are set to public, so I have no idea what problem you are experiencing.

  6. Can someone enplane e(k) to me?

  7. John, the explanation is here :-

    e(k) = error at k where k increments by 1 through the range 0 <= k <= i

    k is a range variable from 0 to i. e(k) is a function of that variable. It is the error at that point. The errors are then summed (the greek sigma sign) to get a total error.

    This comes from the fact that an integral in discrete math is really just a summation. You are adding up the columns under the curve. See Riemann sum.