3.6. Practical Proportional (P) and Proportional-Integral (PI) Control#

3.6.1. Learning Goals#

  • Explain terms in the equations for proportional control and proportional-integral control/

  • Derive velocity from form of PI control.

  • Define terminology

    • negative feedback

    • bias (aka offset or null) term

    • proportional gain and integral gain

  • Explain difference between setpoint tracking and disturbance rejection.

  • Explain roles of the proportional and integral terms contribute.

  • Explain the purpose of each of the following enhancements of ‘textbook’ PI control:

    • Anti-reset windup

      • Control algorithm modifications

      • Event loop modifications

    • Bumpless Transfer

3.6.2. Negative Feedback#

Negative feedback is the core principle underpinning process control. Negative feedback suppresses deviations from the setpoint. If the process variable grows above the setpoint then the manipulated variable is decreased. If the process variable falls below the setpoint then the manipulated variable is increased.

If the system exhibits a negative-going response to a positive change in the manipulated variable, then the sign of the proportional gain must be negative to assure negative feedback control.

Positive feedback is encountered in social, economic, and biological systems where there is a desire to amplify a desirable outcome. Positive feedback can induce good behaviors, result in ‘virtuous’ cycles of innovation and development, or wealth creation. But in most hard engineering situations, the immediate objective is to cause a variable to track a setpoint for which negative feedback is enabling technology


Study Question: Describe the two types of negative feedback taking place in the glucose/insulin/glucagon system diagrammed below.

Study Question: Why are two feedback loops necessary in this biological system? Can you think of an analogy for temperature control of the Temperature Control Lab?

Study Question: For the glucose feedback loops diagrammed above, describe at least one physiological source disturbance for each.

Study Question: Describe a situation where you have witnessed positive feedback in an audio or visual system.


3.6.3. Nomenclature#

In this notebook we will refer to control signals with a generic nomenclature common to the process control industry.

  • CV: Control variables. A variable that is the subject of control. For example, a product composition.

  • PV: Process variables. A variable that can be measured. Sometimes the same as the control variable, often different but closely related to a CV. For example, pressure or temperature of a binary mixture at phase equilibrium may be a proxy for composition.

  • MV: Manipulated variables. Variables that can be manipulated by the control system, such as flow via a valve position, or power input to heater.

  • DV: Disturbance variables. All of the exogeneous inputs that can affect our system of interest.

  • SP: Setpoints. Desired values for the control variables.

Textbook PID (position form):

\[MV(t) = \bar{MV} + \underbrace{K_P (SP(t) - PV(t))}_{\text{proportional}} + \underbrace{K_I \int^t_0 (SP(t') - PV(t')) dt'}_{\text{integral}} + \underbrace{K_D \frac{d}{dt}(SP(t)-PV(t))}_{\text{derivative}}\]

Expressed with error signal \(e(t) = SP(t) - PV(t)\):

\[MV = \bar{MV} + \underbrace{K_P e(t)}_{\text{proportional}} + \underbrace{K_I \int^t_0 e(t') dt'}_{\text{integral}} + \underbrace{K_D \frac{d}{dt}e(t)}_{\text{derivative}}\]

The excellent cartoon explains the P, I, and D terms as different boxing styles.

3.6.4. Typical P&ID Diagram for PI and PID control.#

Source: Instrumentation Tools.com

Source: OptiControl

Suggested Software and Tutorials:

3.6.5. Time-Out for Engineering History#

Proportional control, and its variations, have a long history of implementation in both ancient and modern technologies.

3.6.5.1. Origins of PID Control#

3.6.5.1.1. Boulton and Watt Steam Engine#

Video demonstrating how a mechanical governor works.

3.6.5.1.2. Ship Autopilot - First PID application#

3.6.5.2. Implementations#

A collection of PID controllers you can buy on Amazon for home and commercial use:

3.6.5.3. Formulation of Proportional Control#

Proportional control adjusts the manipulated variable in proportion to the error between the setpoint and measured process variable.

\[MV(t) = \bar{MV} - K_P(PV(t) - SP(t)) = \bar{MV} + K_P(SP(t) - PV(t))\]

When measurements and actions take place at discrete points in time

\[\begin{align} MV_k & = \bar{MV} - K_P(PV_k - SP_k) = \bar{MV} + K_P(SP_k - PV_k) \end{align}\]

The constant of proportionality, \(K_p\), is called the proportional control gain. The error signal is the difference between the the measured process variable and setpoint,

\[\begin{align} e_k & = SP_k - PV_k \end{align}\]

for which the proportional control becomes

\[\begin{align} MV_k & = \bar{MV} + K_P e_k \end{align}\]

This is negative feedback control because if \(e_k > 0\), then the process variable is less than the setpoint, \(PV_k < SP_k\), and the control action \(MV_k\) is positive. Thus is the control action is in the opposite direction of the deviation.

The constant term \(\bar{MV}\) is called the bias, offset, or null value of the manipulated variable. It is an initial estimate of the value of the manipulated variable required to maintain the desired setpoint. The estimate can be determined in several ways:

  • manual adjustment of the manipulated variable followed by a transition to automatic control,

  • solving a process model for the desired steady state,

  • feedforward control,

  • a user provided estimate,

  • set to zero.

In subsequent notebooks we will see how \(\bar{MV}\) is used when building advanced control implementations.

3.6.5.4. Proportional Control Implementation#

Using the Python yield statement, n instance of a proportional controller is created by specifying the gain \(K_P\), upper and lower bounds on the manipulated variable, and the offset value \(\bar{MV}\).

# proportional control
def P(Kp, MV_bar=0):
    ''' Simulate a proportional controller.
    
    Arguments:
        Kp: the proportional gain
        MV_bar: the bias/offset

    Usage:
        proportional = P(Kp, MV_bar)
        next(proportional)
        MV = proportional.send((SP, PV))
    '''
    
    # initialize MV with bias/offset
    MV = MV_bar
    
    # run indefinitely
    while True:
        
        # limit the manipulated variable to the feasible range of values
        MV = max(0, min(100, MV))
        
        # yield MV to calling program. Then pause and wait for updates to SP and PV
        SP, PV = yield MV
        
        # compute error signal
        e = SP - PV
        
        # compute new value of the manipulated variable
        MV = MV_bar + Kp * e
        

The benefits of using the yield statement is that we can use the same code to create multiple instances of controller, each with it’s own parameters and state. The communication between the main event loop and a controller instance is illustrated in this diagram:

The following cells demonstrate performance of the controller when subject to a step change in setpoint and a disturbance input.

3.6.5.5. Testing Setpoint and Disturbance Reponses#

We’ll test the controller using the following inputs:

  • At time 20, the setpoint will switch from 25C to 40C.

  • At time 200, the second heater will turn at 100% power to introduce a disturbance.

Let’s see how proportional control works when applied to the Temperature Control Laboratory. For this simulation we set \(\bar{MV} = 0\) and \(K_p = 3.0\).

from tclab import TCLab, clock, Historian, Plotter, setup

TCLab = setup(connected=False, speedup=10)

# create functions to simulate setpoints and disturbance variables
def SP(t):
    return 40 if t >= 20 else 25

def DV(t):
    return 100 if t >= 200 else 0

# create a controller instance
controller = P(100)

# simulation duration and sampling time
t_final = 600
t_step = 2

with TCLab() as lab:

    # intialize historian and plotting
    sources = [["T1", lambda: lab.T1],
               ["SP1", lambda: SP(t)],
               ["Q1", lab.Q1],
               ["DV", lambda: DV(t)]]
    h = Historian(sources)
    p = Plotter(h, t_final, layout=[["T1", "SP1"], ["Q1"], ["DV"]])
    
    # initialize maximum power for both heaters
    lab.P1 = 200
    lab.P2 = 200
    
    # initialize the controller
    U1 = next(controller)
    lab.Q1(U1)
    lab.Q2(DV(0))

    # event loop
    for t in clock(t_final, t_step):
        
        # get measurement of process variable T1
        T1 = lab.T1
        
        # send current setpoint and PV to controller
        U1 = controller.send((SP(t), T1))
        
        # update manipulated variable
        lab.Q1(U1)
        
        # simulate disturbance
        lab.Q2(DV(t))
        
        # update the historian
        p.update(t)
../_images/42a46795964e577bc93b16adcaa1ab0e601c776d93f95acedf86aa0f3415131d.png
TCLab Model disconnected successfully.
../_images/42a46795964e577bc93b16adcaa1ab0e601c776d93f95acedf86aa0f3415131d.png

For systems without significant time delay and with properly chosen parameters, proportional control can achieve a fast response to changes in setpoint. Note, however, the steady state may be different than the desired setpoint, sometimes unacceptably different. This steady-state error a short-coming of purely proportional control.


Study Question: For this simulation, did the proportional control achieve the setpoint? Did proportional control reject the disturbance? How serious is the problem?


3.6.5.6. Steady-State Offset#

Proportional-only control provides no assurance the the process variable will eventually acquire the setpoint. To see this, consider the proportional control law

\[MV_k = \bar{MV} + K_P e_k\]

in the limit \(k\rightarrow\infty\).

\[e_{\infty} = \frac{MV_{\infty} - \bar{MV}}{K_P}\]

The error \(e_\infty\) expresses the steady-state difference between a process variable and it setpoint. With proportional control, the only options to reduce steady-state offset are

  1. Increase \(K_P\). This leads to increasing oscillations and relay-like behavior of the manipulated variable.

  2. Find a perfect initial estimate for \(\bar{MV}\). If we could do this, we wouldn’t need feedback control.

A persistent steady-state offset is most significant shortcoming of proportional-only control.


Study Question: Test the simulation for values of \(K_p\) that are twice as large, and half as large as demonstrated above. What do you notice about the steady-state error between the desired setpoint and the measured process variable?


3.6.6. Proportional-Integral (PI) Control#

3.6.6.1. Position form#

Given a process variable \(PV\) and setpoint \(SP\), proportional-integral control is defined by the relation

(3.1)#\[\begin{align} MV(t) & = \bar{MV} - K_P\left(PV(t) - SP(t)\right) - K_I\int_{0}^t (PV(t') - SP(t'))\,dt' \\ & = \bar{MV} + K_P\left(SP(t) - PV(t)\right) + K_I\int_{0}^t (SP(t') - PV(t'))\,dt' \end{align}\]

or

(3.2)#\[\begin{align} MV(t) & = \bar{MV} + K_P e(t) + K_I\int_{0}^t e(t') \,dt' \end{align}\]

where

\[e(t) = SP(t) - PV(t)\]

where \(K_P\) is the proportional gain and \(K_I\) is the integral gain. When implemented in discrete time with time steps of length \(h\), the basic rule for proportional-integral control becomes

(3.3)#\[\begin{align} MV_k & = \bar{MV} + K_P(SP_k - PV_k) + h K_I\sum_{j=0}^{j=k}(SP_j - PV_j) \end{align}\]

or

(3.4)#\[\begin{align} MV_k & = \bar{MV} + K_P e_k + h K_I\sum_{j=0}^{j=k}e_j \end{align}\]

where

(3.5)#\[\begin{align} e_k & = SP_k - PV_k \end{align}\]

This is the so-called position form of PI control. The position form specifies the value (or “position”) of the manipulated variable stricly in terms of the current and past values of the error signal \(e_k\). Note the sign convention: A positive error occurs when the process variable is greater than the setpoint. The position form of PI control is rarely used in practice.

3.6.6.2. Velocity form#

A more common implementation of PI control is done by computing how much the manipulated variable changes at each time step, and incrementing the manipulated variable by that amount. Consecutive values of \(MV\) are given by

(3.6)#\[\begin{align} MV_{k-1} & = \bar{MV} + K_p e_{k-1} + h K_i \sum_{j=0}^{k-1} e_{j} \\ MV_{k} & = \bar{MV} + K_p e_{k} + h K_i \sum_{j=0}^{k} e_{j} \end{align}\]

Taking differences gives a formula for updating the value of \(MV\) in response to process measurements or changes in setpoint.

(3.7)#\[\begin{align} MV_{k} & = MV_{k-1} + K_p(e_{k} - e_{k-1}) + h K_i e_{k} \end{align}\]

with \(MV_0 = \bar{MV}\). Let’s see how this works.

def PI(Kp, Ki, MV_bar=0):
    ''' Simulate a simple discrete time proportional-integral controller.
    
    Arguments:
        Kp: proportional gain
        Ki: integral gain
        MV_bar: bias (default = 0)

    Usage:
        controller = PI(Kp, Ki, MV_bar)
        MV = next(controller)
        MV = controller.send((SP, PV))

    '''

    # initialize MV
    MV = MV_bar

    # initialize the error
    e_prev = 0

    # run indefinitely
    while True:

        # yield MV to calling program. Then pause and wait for updates to SP aand PV
        SP, PV = yield MV

        # calculate the error
        e = SP - PV

        # calculate the manipulated variable (velocity form of the PI controller)
        MV = MV + Kp*(e - e_prev) + t_step*Ki*e

        # limit MV to the range 0 to 100
        MV = max(0, min(100, MV))

        # remember the error for the next time through the loop
        e_prev = e
        
from tclab import TCLab, clock, Historian, Plotter, setup
TCLab = setup(connected=False, speedup=60)

# Setpoint function for heater 1
def SP(t):
    return 40 if t >= 20 else 25

# Disturance signal (heater 2)
def DV(t):
    return 100 if t>= 200 else 0

# Create a controller instance
controller = PI(3, 0.2)

# Simulation duration and sampling time (seconds)
t_final = 600
t_step = 2

with TCLab() as lab:
    # Initialize historian and plotter
    sources = [("T1", lambda: lab.T1),
               ("Q1", lab.Q1),
               ("DV", lab.Q2),
               ("SP1", lambda: SP(t))]
    h = Historian(sources)
    layout = [["T1", "SP1"], ["Q1"], ["DV"]]
    p = Plotter(h, t_final, layout=layout)
    
    # set the heater power limits (recall 255 is maximum power)
    lab.P1 = 200
    lab.P2 = 200
    
    # Call the controller the first time
    U1 = next(controller)
    # Implement the first control action
    lab.Q1(U1)

    # loop over time
    for t in clock(t_final, t_step):

        # get measurement of process variable T1
        T1 = lab.T1

        # send current setpoint and PV to controller
        U1 = controller.send((SP(t), T1))

        # Implement the control action
        lab.Q1(U1)

        # Apply the disturbance
        lab.Q2(DV(t))

        # Update the historian and plot
        p.update(t)    
../_images/f43544a9f22a7940207b8761aea97fa9d220750126ff0812f896313edf008bb0.png
TCLab Model disconnected successfully.
../_images/f43544a9f22a7940207b8761aea97fa9d220750126ff0812f896313edf008bb0.png

As we can see from this example, an important practical property of proportonal-integral control is steady-state tracking of the setpoint. In other words, for a steaady setpoint \(\bar{SP}\), at steady-state

(3.8)#\[\begin{align} \lim_{k \rightarrow \infty} PV_k = \bar{SP} \end{align}\]

To see why this is true, start with the velocity form of the proportional-integral controller

(3.9)#\[\begin{align} MV_{k} & = MV_{k-1} + K_p(e_{k} - e_{k-1}) + h K_i e_{k} \end{align}\]

At steady-state \(MV_{k} = MV_{k-1}\) and \(e_{k} = e_{k-1}\) leaving

\[h K_i e_{k} = 0 \implies e_{k} = 0 \implies PV_{k} = \bar{SP}\]

Steady-state tracking is normally important in chemical process applications. For this reason, PI control is, by far, the most commonly encountered control used in the process industries.


Study Question: Repeat the simulation experiments using the Ziegler-Nichols and the Astrom and Murray tuning rules for PI control. Compare the magnitude of the recommended control constants. Compare the resulting performance in response to regard to both setpoint tracking and disturbance rejection. Compare:

  • Maximum overshoot

  • Damping

  • Time to acheive steady-state