# Making a PD Controller Component in ModelingToolkit.jl

**URL:** <https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509>\
**Category:** Modelling & Simulations\
**Created:** [April 3, 2021, 4:51pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509 "2021-04-03T16:51:39Z")\
**Posts on this page:** 9\
**Page:** 2

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 5, 2021, 8:49pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/21 "2021-04-05T20:49:00Z")

</div>

Thanks!! It is difficult to keep track with the development of the documentation :-).

One more simple question… in the above `firstOrder` model,

```julia
function firstOrder(;name)
    @parameters K τ
    @variables f(t) y(t)
    eqs = [
        D(y) ~ (K*f - y)/τ
        ]
    ODESystem(eqs, name=name)
end

```

the function creates and returns an `ODESystem`. Is there a similar `DAESystem`? I only see headings for `ODESystem`, `SDESystem`, and `PDESystem` in the documentation…

If there is a `DAESystem`, is it required to specify initial values for the algebraic variables in addition to the states?

---

<div class="post-metadata">

**Author:** ![Dhruva2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dhruva2/32/18475_2.png) [@Dhruva2](https://discourse.julialang.org/u/Dhruva2)\
**Post date:** [April 5, 2021, 8:49pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/22 "2021-04-05T20:49:50Z")

</div>

OK here is my go of making a PID controller. Notes:

1. I was completely arbitrary in my choice of A B C D matrices and PID parameters
2. Defaults for each component could be added
3. Look how nice ModelingToolkit.jl makes it to access and plot particular variables by name in the solution

Any way this could be made cleaner, let me know.

```julia
using ModelingToolkit, OrdinaryDiffEq

## helper functions. reserving u_i and o_i as names of the ith input/output for each system
function get_input(sys, i)
    return getproperty(sys, Symbol(:u, Symbol('₀' + i)))
end
get_inputs(sys, i) = get_input.((sys,), 1:i)

function get_output(sys, i)
    return getproperty(sys, Symbol(:o, Symbol('₀' + i)))
end
get_outputs(sys, i) = get_output.((sys,), 1:i)

function linear_plant(A,B,C,D; name=:lp)
    
    num_inputs = size(B,2)
    num_states = size(A,1)
    num_outputs = size(C,1)
    @parameters t
    dt = Differential(t)
    @variables x[1:num_states](t)
    @variables u[1:num_inputs](t)
    @variables o[1:num_outputs](t)
    eqs = vcat(
                dt.(x) .~ A*x .+ B*u,
                o .~ C*x .+ D*u
    )    
    return ODESystem(eqs;
                        name=name
                        )   
end

function PID_controller(Pgain, Igain, Dgain, RC, num_inputs; name=:pid)
    @parameters t
    D = Differential(t)

    @variables u[1:num_inputs](t)
    @variables o[1:num_inputs](t)
    @variables int[1:num_inputs](t)
    @variables mv[1:num_inputs](t)
    eqs = vcat(
        D.(int) .~ Igain.*u, #integrator
        D.(mv) .~ u - RC.*(mv), # low pass filter 
        o .~ Dgain .* (u - RC.*(mv)) + Igain.*int + Pgain.*u
    )
    return ODESystem(eqs; name = name)
end

A = [0 1 0 0; -2 -2 0 0; 0 0 0 1; 0 0 -2 -2]
B = reshape([0 0 1. 0], 4,1)
C = reshape([1 0 0 0],1,4)
D = reshape([0], 1,1)
lp = linear_plant(A,B,C,D)
pid = PID_controller(1., 2.,1.5, 0.5, 1) 

function connect(plant, ref, pid)
    @parameters t 
    eqs = vcat(
            get_input(pid,1) ~ ref(t) - get_output(plant,1),
            get_output(pid,1) ~ get_input(plant, 1),
    ) 
    return ODESystem(eqs; systems=[plant,pid])
end

all = connect(lp,sin,pid)
final_sys = structural_simplify(all)

u0 = final_sys.states .=> zeros(length(final_sys.states))
prob = ODEProblem(final_sys, u0, (0.,100.), jac=true, sparse=true)
sol = solve(prob, Tsit5())

using Plots
plot(sol, vars = [pid.int₁])
sol[lp.u₁]

```

---

<div class="post-metadata">

**Author:** ![Dhruva2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dhruva2/32/18475_2.png) [@Dhruva2](https://discourse.julialang.org/u/Dhruva2)\
**Post date:** [April 5, 2021, 8:57pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/23 "2021-04-05T20:57:09Z")

</div>

There is a function `DAE_index_lowering` that does automated reduction of DAE systems into ODESystems:

[https://mtk.sciml.ai/stable/mtkitize\_tutorials/modelingtoolkitize\_index\_reduction/](https://mtk.sciml.ai/stable/mtkitize_tutorials/modelingtoolkitize_index_reduction/)

and yes no worries, I have the same issue with the evolving documentation!

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 5, 2021, 9:04pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/24 "2021-04-05T21:04:31Z")

</div>

Normally, PID controllers are SISO = single input, single output, and most tuning rules are based on SISO systems.

Unconstrained Linear Quadratic Control with infinite horizon has some resemblance with PID control, however…

- For a SISO system where the system is a double integrator (e.g., Newton’s law), this gives constant gain feedback from the two states (position and velocity), which can be interpreted as perfect PD control.
- If a state estimator or observer is added, this gives akin to a filtered PD controller.
- If one adds an extra state which is the integral of the control deviation and puts weight on this in the cost function, the result is a PID controller.

If the real system is _not_ a double integrator, one could in principle assume a double integrator in the control synthesis, which would then lead to a P(I)D controller. But then there is the robustness issue.

---

<div class="post-metadata">

**Author:** ![Dhruva2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dhruva2/32/18475_2.png) [@Dhruva2](https://discourse.julialang.org/u/Dhruva2)\
**Post date:** [April 5, 2021, 9:07pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/25 "2021-04-05T21:07:30Z")

</div>

Thanks, the intuition relating LQR to PID is interesting, I didn’t know about it.  
WRT my code…I just put arbitrary PID and ABCD parameters/matrices because I wanted a lazy MWE!

Also wrt finding system types, I find it’s useful to do evaluations of the form  
`ODESystem |> supertype |> supertype |> subtypes`  
to see what is available

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 5, 2021, 9:07pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/26 "2021-04-05T21:07:42Z")

</div>

> [@Dhruva2](#):
>
> and yes no worries, I have the same issue with the evolving documentation!

Note: the rapidly evolving documentation is a fantastic thing!, which means that there is rapid progress :-). But it is also tricky to keep up to date :-).

---

<div class="post-metadata">

**Author:** ![zdenek\_hurak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zdenek_hurak/32/53118_2.png) [@zdenek\_hurak](https://discourse.julialang.org/u/zdenek_hurak)\
**Post date:** [April 5, 2021, 9:28pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/27 "2021-04-05T21:28:18Z")

</div>

I do not think that the interpretation of an LQ-optimal (state) feedback controller as a PD controller requires a double-integrator model of the plant. What it does require is that the plant is modeled by a second-order state-space model where one of the states is the derivative of the other (in other words, the state variables are velocity and position). Proportional feedback on these two state variables is then, indeed, equivalent to a PD control on the position only.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [April 5, 2021, 9:55pm UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/28 "2021-04-05T21:55:27Z")

</div>

> [@BLI](#):
>
> the function creates and returns an `ODESystem` . Is there a similar `DAESystem` ? I only see headings for `ODESystem` , `SDESystem` , and `PDESystem` in the documentation…

There doesn’t need to be. `ODESystem` takes care of all DAE stuff automatically. You can even build `DAEProblem` from an `ODESystem` if it’s fully implicit.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 6, 2021, 10:10am UTC](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509/29 "2021-04-06T10:10:32Z")

</div>

Yeah, I think you’re right.

[Previous page](https://discourse.julialang.org/t/making-a-pd-controller-component-in-modelingtoolkit-jl/58509.md?page=1)
