# Optimization-based PI controller tuning for a delay system

**URL:** <https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405>\
**Category:** Optimization (Mathematical)\
**Tags:** controlsystems\
**Created:** [August 6, 2025, 1:24pm UTC](https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405 "2025-08-06T13:24:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![VPBML](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vpbml/32/212617_2.png) [@VPBML](https://discourse.julialang.org/u/VPBML)\
**Post date:** [August 6, 2025, 1:24pm UTC](https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405/1 "2025-08-06T13:24:56Z")

</div>

Hi,  
I am trying to find a good tuning for a PI controler on a first-order-plus-delay system using Optimization. A naive first try combining ControlSystems.jl and Optimization.jl did not work and gave some errors. I wonder if it is possible to twist this approach somehow or if there are better (and convenient) alternatives. Thank you.  
Here is the MWE:

```julia-auto
using ControlSystems
using Optimization, OptimizationOptimJL, ForwardDiff, Zygote

function loss_tf(x, p)
    Kp, Ti = x[1], x[2]
    C = pid(Kp, Ti)
    G = p
    L = feedback(C*G)
    t_sim = 0.0:0.1:50.0
    y, t = step(L, t_sim)
    ISE = (t[2] - t[1])*sum((1 .- y).^2)
    return ISE
end

x0 = [2.5, 5.0]
p = tf(1.0, [5.0, 1]) * delay(1.0)
f = OptimizationFunction(loss_tf, Optimization.AutoForwardDiff())
prob = OptimizationProblem(f, x0, p, lb = [-Inf, 0.1], ub = [Inf, Inf])
sol = solve(prob, BFGS())

```

And the error it gave:

```julia-auto
ERROR: MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag{typeof(loss_tf), Float64}, Float64, 2})
The type `Float64` exists, but no method is defined for this combination of argument types when trying to construct it.

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [August 6, 2025, 1:32pm UTC](https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405/2 "2025-08-06T13:32:49Z")

</div>

Have you seen the example that does this in the documentation?  
[Optimization-based tuning–PID controller](https://juliacontrol.github.io/ControlSystems.jl/stable/examples/automatic_differentiation/#Optimization-based-tuning%E2%80%93PID-controller)

If you’re an academic or personal user, you may also find [PID Autotuning Â· DyadControlSystems](https://help.juliahub.com/dyadcontrol/dev/autotuning2/) useful.

---

<div class="post-metadata">

**Author:** ![VPBML](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vpbml/32/212617_2.png) [@VPBML](https://discourse.julialang.org/u/VPBML)\
**Post date:** [August 6, 2025, 1:59pm UTC](https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405/3 "2025-08-06T13:59:07Z")

</div>

Thanks for the response. I have looked at the documentation and followed it, but when I replaced the double-mass system with my simple FOPD, the code just gives this error:

```julia-auto
ERROR: The advanced interface to the function `feedback` (with connection keyword arguments) is currently not supported for LFT systems (such as nonlinear and time-delay systems)

```

DyadControlSystems is unfortunately not an option for my use case, but thanks for the suggestion.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [August 6, 2025, 2:06pm UTC](https://discourse.julialang.org/t/optimization-based-pi-controller-tuning-for-a-delay-system/131405/4 "2025-08-06T14:06:28Z")

</div>

You can convert the delay system to a rational system using

```julia-auto
pade(G, 2)

```

For a well-tuned PID controller, this approximation is typically very good, since the closed loop should, if the optimization is successful, be rendered insensitive to the phase error of the Padé approximation for high frequencies.
