# PID Autotuning

JuliaSimControls contains functionality for optimization-based tuning of PID controllers, subject to robustness constraints on closed-loop sensitivity functions. We currently implement two methods, one that optimizes a PID controller on the form

$$$K(s) = (k_p + k_i/s + k_d s)$$$

by solving

$$$\operatorname{minimize}_K \int e(t) dt$$$$$$\text{subject to} \\ ||S(s)||_\infty \leq M_S \\ ||T(s)||_\infty \leq M_T \\ ||KS(s)||_\infty \leq M_{KS}$$$

where $e(t) = r(t) - y(t)$ is the control error.

The second method performs joint optimization of a PID controller and a measurement filter on the form

$$$K(s) = C(s) F(s) = (k_p + k_i/s + k_d s) \dfrac{1}{(sT)^2 + 2ζTs + 1}, ζ = 1/√2$$$

by solving

$$$\operatorname{minimize}_{C, F} \int |e(t)| dt$$$$$$\text{subject to} \\ ||S(s)||_\infty \leq M_S \\ ||T(s)||_\infty \leq M_T\\ ||KS(s)||_\infty \leq M_{KS}$$$

The autotuning functions operate on SISO LTISystems from ControlSystems.jl. The general workflow is

1. Define a plant model, P
2. Define desired constraints on the maximum magnitudes $M_S, M_T, M_{KS}$ of the sensitivity functions $S = \dfrac{1}{1+ PK}$, $T = \dfrac{PK}{1+ PK}$ and $KS = \dfrac{K}{1+ PK}$.
3. Choose problem and solver parameters and create an AutoTuningProblem.
4. Call solve.
5. Plot the result.

If you want to use the optimized controller in a ModelingToolkit simulation, see OptimizedPID.

Examples of this are shown below.

Functions:

## Example: PID autotuning

JuliaSimControls contains a Pluto-based graphical app (GUI) for PID-controller tuning using the two methods below, accessible through the web interface. This example demonstrates the non-graphical interface.

### Integrated absolute error (IAE)

The following example optimizes a PID controller with a low-pass filter using the method from

K. Soltesz, C. Grimholt, S. Skogestad. Simultaneous design of proportional–integral–derivative controller and measurement filter by optimisation. Control Theory and Applications. 11(3), pp. 341-348. IET. 2017.

using JuliaSimControls, Plots
# Process model (continuous time LTI SISO system).
T = 4 # Time constant
L = 1 # Delay
K = 1 # Gain
P = tf(K, [T, 1.0])#*delay(L) # process dynamics
Ts = 0.1 # Discretization time
Tf = 25  # Simulation time

# Robustness constraints
Ms = 1.2   # Maximum allowed sensitivity function magnitude
Mt = Ms    # Maximum allowed complementary sensitivity function magnitude
Mks = 10.0 # Maximum allowed magnitude of transfer function from process output to control signal, sometimes referred to as noise sensitivity.
w = 2π .* exp10.(LinRange(-2, 2, 100)) # frequency grid

p0 = Float64[1, 1, 0, 0.001] # Initial parameter guess, kp, ki, kd, T_filter
prob = AutoTuningProblem(; P, Ms, Mt, Mks, w, Ts, Tf, metric = :IAE)

res = solve(prob, p0)
plot(res)

The figure shows the Nyquist curve of the loop-transfer function $P(s)K(s)$ using the optimized controller, as well as circles corresponding to the chosen constraints. The top figures show Bode plots of the closed-loop sensitivity functions together with the constrains, and the lower left figure shows the response to a unit load-disturbance step as well as a reference-step response. Note, the response to a reference step is not part of the optimization criterion, and optimized suppression of load disturbances often leads to a suboptimal response to reference steps. If steps are expected in the reference signal, reference shaping using a pre-filter is recommended (called a 2-DOF design, realized, for example, by the introduction of $W_r$ in the diagram of the following design example).

### Integrated error (IE)

The following example optimizes a PID controller using the method from

M. Hast, K. J. Astrom, B. Bernhardsson, S. Boyd. PID design by convex-concave optimization. European Control Conference. IEEE. Zurich, Switzerland. 2013.

This method optimizes integrated error (not integrated absolute error). This problem is relatively easy to solve and corresponds well to IAE if the system is well damped. If convergence of the above method (IAE) appears difficult, this method can be used as initialization by choosing metric = :IEIAE.

using JuliaSimControls, Plots
T = 4 # Time constant
K = 1 # Gain
P = tf(K, [T, 1.0]) # process dynamics

## Robustness constraints
Ms  = 1.2  # Maximum allowed sensitivity function magnitude
Mt  = Ms   # Maximum allowed complementary sensitivity function magnitude
Mks = 10.0 # Maximum allowed magnitude of transfer function from process output to control signal, sometimes referred to as noise sensitivity.
w   = 2π .* exp10.(LinRange(-2, 2, 50)) # frequency vector

p0 = Float64[1, 1, 0.1] # Initial guess. Use only two parameters to tune a PI instead of PID controller
prob = AutoTuningProblem(; P, Ms, Mt, Mks, w, Ts=0.1, Tf=25.0, metric = :IE) # Set the metric here

res = solve(prob, p0)
plot(res)

### Choosing metric

The metric = :IE problem optimizes integrated error $\int e(t) dt$ (not integrated absolute error). This problem is relatively easy and fast to solve and corresponds well to IAE if the system is well damped. If this metric is chosen, a PI or PID controller is tuned, determined by the number of parameters in the initial guess. The method requires a stabilizing controller as an initial guess. If the plant is stable, the zero controller is okay. If the initial guess is not stabilizing, an attempt at automatically finding a feasible initial guess is made.

If the response is oscillatory, the metric = :IE metric is expected to perform poorly and metric = :IAE is recommended. If metric = :IAE is chosen, a PID controller with a low-pass filter is tuned by minimizing $\int |e(t)| dt$. This problem is nonconvex and can be difficult to solve. This method can be initialized with the IE method by selecting metric = :IEIAE.

## Index

JuliaSimControls.AutoTuningProblemType
AutoTuningProblem{S, W}

Optimizes a controller on the form

K(s) = C(s) * F(s) = (kp + ki/s + kd*s) * 1/((s*T)^2+2*ζ*T*s+1), ζ = 1/√2
$$$K(s) = C(s) F(s) = (k_p + k_i/s + k_d s) \dfrac{1}{(sT)^2 + 2ζTs + 1}, ζ = 1/√2$$$

Can be plotted after optimization by using Plots; plot(prob, C) where C is obtained from the optimization.

See also OptimizedPID

Keyword arguments:

• P::LTISystem: Plant model
• w::AbstractVector: Frequency grid vector
• Ts::Float64: Discretization time (sample time, arbitrary time unit)
• Tf::Float64: Simulation duration in the same time unit as Ts.
• Ms::Float64: Maximum allowed sensitivity
• Mt::Float64: Maximum allowed complimentary sensitivity
• Mks::Float64: Maximum allowed noise sensitivity (controller times sensitivity)
• pmax::Vector{Float64}: An optional vector of the same length as the number of estimated parameters that contains upper bounds on parameters, the default is fill(Inf, 4) (no bounds).
source
CommonSolve.solveMethod
res = solve(prob::AutoTuningProblem, p0; kwargs...)

Computes PID parameters, that minimize load step IAE, and filter for noise attenuation.

$$$K(s) = C(s) F(s) = (k_p + k_i/s + k_d s) \dfrac{1}{(sT)^2 + 2 ζ Ts + 1}$$$
• p0 Parameter vector: [kp; ki; kd; T]

See AutoTuningProblem for arguments. res is of type AutoTuningResult and can be plotted plot(res). It contains the optimized parameters as well as an ODESystem representing an optimized controller.

Based on pidfIAE from https://gitlab.control.lth.se/kristian/PIDopt K. Soltesz, C. Grimholt, S. Skogestad. Simultaneous design of proportional–integral–derivative controller and measurement filter by optimisation. Control Theory and Applications. 11(3), pp. 341-348. IET. 2017. See the git repo for further documentation.

Solver options for metric :IAE include

• maxeval = 500
• maxtime = 20
• xtol_rel = 1e-3
• alg = :LD_CCSAQ, other options are :LD_CCSAQ, :LD_MMA, :LD_SLSQP
• random_start = 0 A positive integer indicates a number of random starts to try in order to find a good soluiton. If random_start = 0, only the provided initial guess is used.

Solver options for metric :IE include

• maxiter = 15: Maximum number of convex-concave optimization iterations.
• tol = 1e-3: Tolerance for the convex-concave procedure.
• solver = Hypatia.Optimizer: Any MOI compatible solver.
• verbose = false:
source
JuliaSimControls.OptimizedPIDMethod
OptimizedPID(popt; name, kwargs...)
OptimizedPID(res::AutoTuningResult; name, kwargs...)

Takes optimized parameters popt and returns the following system

u_r                 ┌───────┐
───────────────────►       │  y
│  PID  ├────►
┌────────┐ ┌───►       │
u_y  │        │ │   └───────┘
────► filter ├─┘
│        │
└────────┘

Arguments:

source