This first chapter gives a brief recap of PID control theory. It describes the controller architecture and derives the formulas that will be implemented in C++ in the next chapter.

Prerequisites: basic control theory, Laplace and Z-transforms.

Continuous-time

In this first section, we'll assume that all signals are functions of a continuous time variable t. Later, we'll discretize the continuous-time controllers into a discrete-time approximation that can easily be manipulated by computers and microcontrollers.

Closed-loop controllers

Figure 1 shows the block diagram of a general closed-loop or feedback control system. The output y(t) of the plant (the system being controlled) is subtracted from the reference r(t), and this error e(t) is fed to the controller, which produces the control signal u(t) that is sent to the input of the plant, in an attempt to drive the error to zero.

Block diagram of a closed-loop controllerImage source code
Figure 1: Block diagram of a closed-loop controller

The PID controller

In a PID controller, the control signal is calculated as the sum of three components: a proportional component, an integral component, and a derivative component. The proportional component simply multiplies the error by a constant Kp, the integral component multiplies the time integral of the error by a constant Ki, and the derivative component multiplies the time derivative of the error by a constant Kd. Mathematically, the control law is given by u(t)=Kpe(t)+Ki0te(τ)dτ+Kdddte(t). The constants Kp, Ki and Kd are referred to as the proportional gain, the integral gain, and the derivative gain respectively.
The block diagram of this type of controller is shown in Figure 2.

Block diagram of a PID controllerImage source code
Figure 2: Block diagram of a PID controller

You can find intuitive explanations of the purpose of each of the three components all over the internet, but in short: the proportional component makes the controller act on the instantaneous error, the integral component accumulates past errors in order to minimize the steady-state and tracking error, and the derivative component penalizes the velocity at which the output changes, which can help to reduce overshoot.

Frequency domain

In the frequency or s-domain, the PID control law can be written as U(s)=(Kp+Ki1s+Kds)E(s), where U(s) and E(s) are the Laplace transforms of the respective time-domain signals u(t) and e(t). This formulation is represented by Figure 3.

Block diagram of a PID controller using Laplace notationImage source code
Figure 3: Block diagram of a PID controller using Laplace notation

Derivative filtering

The derivative of the error can be rather noisy, so practical PID controllers often include a low-pass filter. Let ef(t) be the low-pass filtered error, then the control law can be modified into u(t)=Kpe(t)+Ki0te(τ)dτ+Kdddtef(t). Or, in the frequency domain, U(s)=(Kp+Ki1s+KdsH(s))E(s). Here, H(s) is the transfer function of the low-pass filter for the derivative component.

For the sake of simplicity, we'll use a single-pole low-pass filter to filter the error before taking the derivative. The transfer function of this filter is H(s)=11+sTf, where Tf is the filter's time constant, a parameter we can tune later.

Discrete-time

Since computers and microcontrollers cannot deal with continuous time, the control law has to be discretized. We'll use Ts to note the time step or sampling interval.

Discrete-time signals

Given the continuous-time error signal e:RR:te(t), define the discrete-time error signal e[k] as e(t) sampled at t=kTs (with sampling interval Ts), e[]:ZR:ke[k]e(kTs).

We will use the same letters for continuous-time and discrete-time transfer functions and signals in the s- and z-domain, it should be clear from the context and the variables used (s or z) whether it's a continuous-time or discrete-time signal. For example, H(s) is a continuous-time transfer function, and H(z) is a discrete-time transfer function, defined by different rational functions.

Forward Euler

The first discretization method we'll have a look at is the forward Euler method, it is one of simplest methods available to approximate a continuous-time ordinary differential equation by a discrete-time difference equation or recurrence relation.

Integral

When the time step Ts is sufficiently small, the integral term of the PID control law at time t=kTs can be approximated by a Riemann sum: ei(t)0te(τ)dτn=0k1e[n]Tsei[k] Note that this is an approximation, ei(kTs)ei[k], they are not exactly equal.

This signal ei[k] can also be defined by the following recurrence relation {ei[k]=ei[k1]+e[k1]Tsei[0]=0.

In the z-domain, the forward Euler discretization we carried out in the previous paragraph can be expressed as Ei(z)=z1Ei(z)+Tsz1E(z)Ei(z)=Tsz1E(z). Recall that in the s-domain, the relation between Ei(s) and E(s) was given by Ei(s)=1sE(s), so in general, we could define forward Euler discretization as the mapping from the s-domain to the z-domain where sz1Ts.

Backward Euler

The backward Euler method is very similar to forward Euler, but it has a different time delay:
When applied to the derivative y(t)=ddtx(t), the forward Euler method results in the discrete-time recurrence relation y[k]=x[k+1]x[k]Ts, which is non-causal (the output y[k] depends on the future input x[k+1]). The following section introduces the backward Euler method, which will discretize this derivative as the causal recurrence y[k]=x[k]x[k1]Ts.

Derivative

We can approximate the derivative term in the control law using finite differences: ed(t)ddtef(t)ef(t)ef(tTs)Tsed[k]

In the z-domain, this is equivalent to Ed(z)=1z1TsEf(z)Ed(z)=z1zTsEf(z).

In the s-domain, we have Ed(s)=sEf(s), so backward Euler discretization is the mapping sz1zTs.

Low-pass filter

Applying this mapping to the transfer function of the low-pass filter for the derivative results in the following, Ef(s)=11+sTfE(s)Ef(z)=11+z1zTsTfE(z)=zTsz(Ts+Tf)TfE(z)=zβz(1β)E(z), where βTsTs+Tf. You might recognize this expression as the transfer function of the exponential moving average filter, usually defined by the recurrence relation ef[k]=βe[k]+(1β)ef[k1].

In practice, one often treats the derivative term as a whole, discretizing the derivative and the low-pass filter in one go by combining their transfer functions and then applying forward Euler: Ed(s)=sH(s)E(s)=s1+sTfE(s)=11s+TfE(s)Ed(z)=1Tsz1+TfE(z)=z1TsTf+zTfE(z) In the time domain, this becomes (TsTf)ed[k1]+Tfed[k]=e[k]e[k1]ed[k]=αe[k]e[k1]Ts+(1α)ed[k1], where αTsTf. This can be written as ed[k]=ef[k]ef[k1]Tsef[k]αe[k]+(1α)ef[k1]. The first equation is the finite differences approximation of a derivative, and the second is again an exponential moving average filter, but with a different weight factor compared to the result we got earlier using backward Euler.

Other discretization methods

An alternative method is the bilinear transform (also known as the trapezoidal rule or Tustin's rule), it is of a higher order than forward and backward Euler, and has some nice properties such as the fact that stable poles in one domain map to stable poles in the other. Other techniques include pole-zero matching, matched step response, frequency response approximations, but these are outside of the scope of this article as they are not usually applied to PID controllers.

Overview

The following table gives an overview of all signals that make up the PID control law, as well as their discretizations. The third column is the most important one, because the discrete-time recurrence relations can easily be implemented in software.

Continuous-time s-domain Discrete-time z-domain
e(t) E(s) e[k] E(z)
ei(t)=0te(τ)dτ Ei(s)=1sE(s) ei[k]=ei[k1]+Tse[k1] Ei(z)=Tsz1E(z)
ed(t)=ddtef(t) Ed(s)=sEf(s) ed[k]=ef[k]ef[k1]Ts Ed(z)=z1zTsEf(z)
ef(t)=e(t)Tfddtef(t) Ef(s)=11+sTfE(s) ef[k]=αe[k]+(1α)ef[k1] Ef(z)=αzz(1α)E(z)

Derivative on measurement

One disadvantage of the PID topology discussed above is that the derivative component will become very large if the reference r(t) suddenly changes. This effect is known as “derivative kick”.
The solution is really simple: instead of the derivative of the error, the derivative of the measurement is used. The former is known as “derivative on error”, the latter as “derivative on measurement”. Both topologies are equivalent if the reference is constant, because if ddtr(t)=0, then ddte(t)=ddty(t).

Figure 4 shows a block diagram of this new derivative on measurement topology, including the low-pass filter on the derivative.

Block diagram of a PID controller with “derivative on measurement”Image source code
Figure 4: Block diagram of a PID controller with “derivative on measurement”