Control systems

we build upon simulate to simulate feedback and feedforward control systems.

P, PI, PID controller transfer functions

we express PID controller transfer functions in the form:

\[g_c(s)=K_c \left[1+\frac{1}{\tau_I}+\tau_D s \frac{1}{\tau_D \alpha s + 1}\right]\]

where $\alpha$ characterizes the derivative filter. this controller function function governs the controller output in response to the input error signal.

To construct P, PI, or PID controllers:

Kc = 2.0 # controller gain
pc = PController(Kc) # P-controller with given Kc

τI = 1.0 # integral time constant
pic = PIController(Kc, τI) # PI-controller with given Kc, τI

τD = 0.1 # derivative time constant
pidc = PIDController(Kc, τI,  τD, α=0.0) # PID-controller with given Kc, τI, τD. keyword argument is derivative filter α

to construct controller transfer functions $g_c(s)$ from the P, PI, or PID controller parameters:

pic = PIController(2.0, 1.0)
gc = TransferFunction(pic) # (2s+2) / s

servo response of a simple control system

with skills in block diagram algebra, we can use simulate to simulate a control system with a great degree of flexibility. as an example, we simulate the response of a simple feedback control system to a set point change.

let's specify $g_c(s)$ as a PI controller and $g_u(s)$ as a first-order system. the former describes the controller output responds to the error signal. the latter describes how the process responds to inputs– here, the process input is provided by the controller.

pic = PIController(1.0, 1.0) 
gc = TransferFunction(pic) # controller transfer function
gu = 3 / (4 * s + 1) # process transfer function

via block diagram algebra, we can solve for the transfer function governing the response to set point changes.

g_ol = gc * gu # open-loop transfer function

g_servo = g_ol / (1 + g_ol) # transfer function for servo response

the response of the process to a unit step set point change is thus:

Y_sp = 1 / s # unit step set point change
Y = g_servo * Y_sp # resulting output in response to our set point change

finally, we can find the response by inverting Y into the time domain:

final_time = 12.0
data_y = simulate(Y, final_time)

to also see the controller output, we build the error signal E and use $g_c(s)=U(s)/E(s)$ to get U.

E = Y_sp - Y # error signal
U = gc * E # resulting controller output
data_u = simulate(U, final_time) # controller output in the time domain

an easy way of getting the set point $y_{sp}(t)$ is:

data_y_sp = simulate(Y_sp, final_time)

finally, we can plot y, ysp, and u against t to visualize the response of our feedback PI control system to a set point change.

also plotted separately is the contribution to the controller output by the P- and I- components of the PI controller, obtained via:

U_Paction = Kc * E # P-action
U_Iaction = Kc / (τI * s) * E # I-action

data_u_Paction = simulate(U_Paction, final_time)
data_u_Iaction = simulate(U_Iaction, final_time)

feedback loops with time delays

when time delays are involved, we must use the special implementation of a transfer function, ClosedLoopTransferFunction. we provide an example below.

suppose the transfer functions in the block diagram are as defined below.

# PI controller transfer function
pic = PIController(1.0, 2.0)
gc = TransferFunction(pic)

# process, sensor dynamics
gu = 2 / (4 * s + 1) * exp(-0.5 * s)
gm = 1 / (s + 1) * exp(-0.75 * s)
gd = 6 / (6 * s + 1)

we define the closed-loop transfer functions for the response to set point changes $y_{sp}(t)$ and disturbances $d(t)$ as below:

# open-loop transfer function
g_ol = gc * gu * gm

# closed-loop transfer function for regulator response
gr = ClosedLoopTransferFunction(gd, g_ol)

# closed-loop transfer function for servo response
gs = ClosedLoopTransferFunction(gc * gu, g_ol)

where gr and gs represent the closed-loop transfer functions $g_r(s)$ and $g_s(s)$ respectively:

\[g_r(s)=\dfrac{Y(s)}{D(s)}=\dfrac{g_d(s)}{1+g_c(s)g_u(s)g_m(s)}\]

\[g_s(s)=\dfrac{Y(s)}{Y_{sp}(s)}=\dfrac{g_c(s)g_u(s)}{1+g_c(s)g_u(s)g_m(s)}\]

we can then simulate responses to set point changes as:

Ysp = 1 / s # unit step set point change
Y = gs * Ysp
data = simulate(Y, 50.0)

and to disturbances as:

D = 1 / s # unit step in disturbance variable d
Y = gr * D
data = simulate(Y, 50.0)
Controlz.PControllerType
pc = PController(Kc)

Construct a Proportional (P) controller by specifying the controller gain defined under the following transfer function representation:

\[g_c(s)=K_c\]

Arguments

  • Kc::Float64: controller gain

Example

pc = PController(1.0) # specify P controller gain
gc = TransferFunction(pc) # construct transfer function with this P-controller gain
source
Controlz.PIControllerType
pic = PIController(Kc, τI)

Construct a Proportional-Integral (PI) controller by specifying the controller gain and integral time constant defined under the following transfer function representation:

\[g_c(s)=K_c \left[1+\frac{1}{\tau_I s}\right]\]

Arguments

  • Kc::Float64: controller gain
  • τI::Float64: integral time constant

Example

pic = PIController(1.0, 3.0) # specify PI controller params
gc = TransferFunction(pic) # construct transfer function with these PI-controller params
source
Controlz.PIDControllerType
pidc = PIDController(Kc, τI, τD, α=0.0)

Construct a Proportional-Integral-Derivative (PID) controller by specifying the controller gain, integral time constant, derivative time constant, and derivative filter defined under the following transfer function representation:

\[g_c(s)=K_c \left[1+\frac{1}{\tau_I s}+\tau_D s \frac{1}{\alpha \tau_D s + 1}\right]\]

Arguments

  • Kc::Float64: controller gain
  • τI::Float64: integral time constant
  • τD::Float64: derivative time constant
  • α::Float64: derivative filter

Example

pidc = PIDController(1.0, 3.0, 0.1) # specify PID controller params
gc = TransferFunction(pidc) # construct transfer function with these PID-controller params
source