# 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 `LTISystem`

s from ControlSystems.jl. The general workflow is

- Define a plant model,
`P`

- 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}$.
- Choose problem and solver parameters and create an
`AutoTuningProblem`

. - Call
`solve`

. - Plot the result.

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

.

Examples of this are shown below.

Functions:

`solve`

: solve an autotuning problem.`AutoTuningProblem`

: define an autotuning problem.`OptimizedPID`

: obtain an`ODESystem`

representing the tuned PID controller.

## 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.AutoTuningProblem`

— Type`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).

`CommonSolve.solve`

— Method`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`

:

`JuliaSimControls.OptimizedPID`

— Method```
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:**

`popt`

: Obtained by solving an`AutoTuningProblem`

`kwargs`

: Are passed to`PID`