# Adding PID controller to a MIMO state space system

**URL:** <https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681>\
**Category:** Modelling & Simulations\
**Tags:** controlsystems\
**Created:** [November 15, 2024, 2:08pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681 "2024-11-15T14:08:32Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![victor](https://avatars.discourse-cdn.com/v4/letter/v/3e96dc/32.png) [@victor](https://discourse.julialang.org/u/victor)\
**Post date:** [November 15, 2024, 2:08pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/1 "2024-11-15T14:08:32Z")

</div>

I have a state space process with two inputs and one output. The inputs are highly coupled. I would like to add a PID controller to one of the inputs with the output as measurement value. But I’m having a hard time with the feedback function. Could any one guide me in the right direction?

Quick example code:

```julia
using ControlSystemsBase, Plots
# Define the state space system
A = [1.0 0.5; 0.2 0.8]
B = [1.0 0.3; 0.4 1.1]
C = [2.0 1.5]
D = [0.5 0.2]

sys = ss(A, B, C, D)

# Simulate the system with lsim
t = 0:1.0:10
u1 = sin.(t)
u2 = cos.(t)
u = [u1 u2]'
y, t, x = lsim(sys, u, t)

plot(y')

# Step 2: Design the PID controller
Kp = 1.0
Ki = 0.5
Kd = 0.1
Tf = 0.1 # Filter time constant
C = pid(Kp, Ki, Kd, Tf=Tf, state_space=true, Ts=1.0, form=:parallel)

G= feedback(sys.sys*C ??????)

```

---

<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:** [November 15, 2024, 2:21pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/2 "2024-11-15T14:21:20Z")

</div>

If you want feedback a subset of the signals only, you use the advanced interface to `feedback`

```julia
  feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace;
           U1=:, Y1=:, U2=:, Y2=:, W1=:, Z1=:, W2=Int[], Z2=Int[],
           Wperm=:, Zperm=:, pos_feedback::Bool=false)
                ┌──────────────┐
        z1◄─────┤ sys1 │◄──────w1
   ┌─── y1◄─────┤ │◄──────u1 ◄─┐
   │ └──────────────┘ │
   │ α
   │ ┌──────────────┐ │
   └──► u2─────►│ sys2 ├───────►y2──┘
        w2─────►│ ├───────►z2
                └──────────────┘

```

It would look something like this

```julia
sysd = c2d(sys, C.Ts)
U1 = [1] # Index of the input of `sys1` that you want to connect
G = feedback(sysd, C; U1)

```

Set the other arguments to `feedback` as appropriate for what you want to include as inputs and outputs of the constructed feedback interconnection.

The output of `G` in my example above will be `Z1 = :`, that is, the output of the plant. The inputs will be `W1 = :`, that is, both inputs of the plant. If you want to keep only the unconnected input of the plant as input to the closed-loop system, set `W1 = [2]` (since you connected input `[1]` above).

---

<div class="post-metadata">

**Author:** ![victor](https://avatars.discourse-cdn.com/v4/letter/v/3e96dc/32.png) [@victor](https://discourse.julialang.org/u/victor)\
**Post date:** [November 15, 2024, 2:52pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/3 "2024-11-15T14:52:17Z")

</div>

Thanks for a quick reply, that seems to work. One more question, if I use a u vector as above in lsim would u[:,1] be my reference signal for the controller?

---

<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:** [November 15, 2024, 3:23pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/4 "2024-11-15T15:23:27Z")

</div>

The example I gave have plant inputs as inputs of `G`. If you want to have the controller input be the input instead, make the controller `sys1` and the plant `sys2` and choose the signals appropriately.

---

<div class="post-metadata">

**Author:** ![victor](https://avatars.discourse-cdn.com/v4/letter/v/3e96dc/32.png) [@victor](https://discourse.julialang.org/u/victor)\
**Post date:** [November 15, 2024, 3:34pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/5 "2024-11-15T15:34:34Z")

</div>

I would like to set the PID reference, but also give the u[:,2] signal to the plant. Is that possible?

---

<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:** [November 15, 2024, 8:21pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/6 "2024-11-15T20:21:52Z")

</div>

Yes, you can specify any signal as external inputs through the `W1, W2` arguments.

---

<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:** [November 16, 2024, 7:08am UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/7 "2024-11-16T07:08:27Z")

</div>

Here are two ways to achieve this, one using `feedback` and one using [`connect` with named systems from RobustAndOptimalControl.jl](https://juliacontrol.github.io/RobustAndOptimalControl.jl/dev/#Connecting-systems-together)

```julia
using ControlSystemsBase, Plots
# Define the state space system
A = [1.0 0.5; 0.2 0.8]
B = [1.0 0.3; 0.4 1.1]
C = [2.0 1.5]
D = [0.5 0.2]
sys = ss(A, B, C, D)

Kp = 1.0
Ki = 0.5
Kd = 0.1
Tf = 0.1 # Filter time constant
C = pid(Kp, Ki, Kd, Tf=Tf, state_space=true, Ts=1.0, form=:parallel)

sysd = c2d(sys, C.Ts) # Discretize plant

# ==============================================================================
# Connection using feedback
# ==============================================================================
U2 = [1] # Index of the input of plant that you want to connect
W2 = [2] # Index of the plant to keep as external input
W1 = [1] # Index of C to keep as external input
Z1 = [] # Index of C to keep as external output
Z2 = (:) # Index of the plant to keep as external output
G2 = feedback(C, sysd; U2, W1, W2, Z1, Z2)

res = step(G2, 10)
plot(res, layout=2, sp=[1 2])

# ==============================================================================
# Using Named Statespace systems
# ==============================================================================
using RobustAndOptimalControl
Pn = named_ss(sysd, "P")
Cn = named_ss(C, "C")
fb = sumblock("e = r - y", Ts=C.Ts) # Feedback node
connections = [
    :Py => :y
    :e => :Cu
    :Cy => :Pu1
]

z1 = [:Py] # External outputs
w1 = [:r, :Pu2] # External inputs
G3 = connect([Pn, Cn, fb], connections; z1, w1)

# ==============================================================================
## Compare
# ==============================================================================
bodeplot(G2)
bodeplot!(G3)

```

As the plot indicates, the two results are identical.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/8/f/8fdfe047093bedf7f0b0771e2612a246f40ea6a5.png)

* * *

Edit: I made a new release that allows the user in the latest example with named systems to instead pass external inputs and outputs using the more descriptive keyword arguments `external_inputs, external_outputs` instead of `w1, z1` (the latter option will continue to work).

---

<div class="post-metadata">

**Author:** ![victor](https://avatars.discourse-cdn.com/v4/letter/v/3e96dc/32.png) [@victor](https://discourse.julialang.org/u/victor)\
**Post date:** [November 17, 2024, 6:55pm UTC](https://discourse.julialang.org/t/adding-pid-controller-to-a-mimo-state-space-system/122681/8 "2024-11-17T18:55:12Z")

</div>

Thanks this was great help
