Engee documentation
Notebook

Connecting models

In this example, learn how to model the connection of LTI systems in Engee. From simple serial and parallel connections to complex block diagrams.

Overview

Engee provides a number of functions to help you create LTI model associations. These functions include:

  • Serial and parallel connection (series, parallel)
  • Feedback connection (feedback, feedback2dof)
  • Input and output concatenation ([ , ], [ ; ], append, array2mimo)
  • General flowcharting (connect)

To illustrate the examples, let's connect the necessary libraries and create two systems with the following transfer functions:

In [ ]:
Pkg.add(["RobustAndOptimalControl", "ControlSystems"])
In [ ]:
using ControlSystems
In [ ]:
H1 = tf(2,[1, 3, 0])
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Int64}}
   2
--------
s^2 + 3s

Continuous-time transfer function model
In [ ]:
H2 = zpk([],[-5],5)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Int64}}
   1
5-----
 s + 5

Continuous-time transfer function model

Serial connection

Use the * statement or the series function to daisy-chain LTI models, for example:

gsconnectingmodels_01.png

In [ ]:
H = H2 * H1
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
          1
10-----------------
  (s + 5)(s + 3)(s)

Continuous-time transfer function model
In [ ]:
H = series(H1,H2)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
          1
10-----------------
  (s + 5)(s + 3)(s)

Continuous-time transfer function model

Parallel connection

Use the + operator or the parallel function to connect LTI models in parallel, for example:

gsconnectingmodels_02.png

In [ ]:
H = H1 + H2
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Float64, ComplexF64}}
   (1.0s + 2.6433981132056608)(1.0s + 0.7566018867943395)
5.0------------------------------------------------------
               (1.0s + 3.0)(1.0s)(1.0s + 5.0)

Continuous-time transfer function model
In [ ]:
H = parallel(H1,H2)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Float64, ComplexF64}}
   (1.0s + 2.6433981132056608)(1.0s + 0.7566018867943395)
5.0------------------------------------------------------
               (1.0s + 3.0)(1.0s)(1.0s + 5.0)

Continuous-time transfer function model

Connection with feedback

Standard view of the system structure diagram with orate negative coupling:

gsconnectingmodels_03.png

To define a closed system use the function feedback.

In [ ]:
H = feedback(H1,H2)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Float64, ComplexF64}}
                                    1.0s + 5.0
2.0-----------------------------------------------------------------------------
   (1.0s + 5.663076827457541)(1.0s^2 + 2.3369231725424586s + 1.7658245340262375)

Continuous-time transfer function model

Note that the default feedback is negative. To make the feedback positive, use the following syntax:

In [ ]:
H = feedback(H1, H2, pos_feedback = true)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Float64, ComplexF64}}
                                   1.0s + 5.0
2.0---------------------------------------------------------------------------
   (1.0s^2 + 8.515690830166166s + 19.3914636736468)(1.0s - 0.5156908301661673)

Continuous-time transfer function model

Combining inputs and outputs

You can combine the inputs of two models H1 and H2 by entering:

In [ ]:
H = [H1 H2]
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
Input 1 to output 1
     1
2----------
 (s + 3)(s)

Input 2 to output 1
   1
5-----
 s + 5

Continuous-time transfer function model

The resulting model has two inputs and one output, which corresponds to the following diagram:

gsconnectingmodels_05.png

Similarly, you can merge the output of H1 and H2 , by entering:

In [ ]:
H = [ H1 ; H2 ]
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
Input 1 to output 1
     1
2----------
 (s + 3)(s)

Input 1 to output 2
   1
5-----
 s + 5

Continuous-time transfer function model

The resulting model H has two outputs and one input and corresponds to the following flowchart:

gsconnectingmodels_06.png

Finally, you can combine the inputs and outputs of the two models using:

In [ ]:
H = append(H1,H2)
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
Input 1 to output 1
     1
2----------
 (s + 3)(s)

Input 1 to output 2
 1
0-
 1

Input 2 to output 1
 1
0-
 1

Input 2 to output 2
   1
5-----
 s + 5

Continuous-time transfer function model

The resulting model H has two inputs and two outputs and corresponds to the structural diagram: gsconnectingmodels_07.png

You can use concatenation to build MIMO models from elementary SISO models, e.g.:

In [ ]:
[H1 -tf(10,[1, 10]); 0 H2]
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoZpk{Int64, Complex{Int64}}}
Input 1 to output 1
     1
2----------
 (s + 3)(s)

Input 1 to output 2
 1
0-
 1

Input 2 to output 1
     1
-10------
   s + 10

Input 2 to output 2
   1
5-----
 s + 5

Continuous-time transfer function model

You can also use the function array2mimo. For example,

In [ ]:
P = ss(-1,1,1,0);
sys_array = fill(P, 2, 2) # Создает массив систем
mimo_sys = array2mimo(sys_array)
Out[0]:
StateSpace{Continuous, Int64}
A = 
 -1   0   0   0
  0  -1   0   0
  0   0  -1   0
  0   0   0  -1
B = 
 1  0
 0  1
 1  0
 0  1
C = 
 1  1  0  0
 0  0  1  1
D = 
 0  0
 0  0

Continuous-time state-space model

Building models based on flowcharts

You can use combinations of functions and operations to build models of simple flowcharts. For example, consider the following flowchart:

gsconnectingmodels_09.png with the following data for blocks F, C, G, S:

In [ ]:
s = tf('s');
F = 1/(s + 1);
G = 100/(s^2 + 5*s + 100);
C = 20*(s^2 + s + 60)/s/(s^2 + 40*s + 400);
S = 10/(s + 10);

You can determine the transfer function of a closed-loop system from r to y as follows:

In [ ]:
T = F * feedback(G*C,S)
plot(step(T,10))
Out[0]:

But for more complex block diagrams, use the function connect of the library RobustAndOptimalControl.jl. To use connect, follow the steps below:

  • Identify all blocks in the diagram, including summing blocks;
  • Name all input and output channels of the blocks;
  • Match the outputs (outputs) of the system blocks with the corresponding inputs (inputs) of the blocks.

Let's consider an example of using the function on the example of the following structural diagram. gsconnectingmodels_11.png

Import and connect the library RobustAndOptimalControl.jl.

In [ ]:
import Pkg
Pkg.add("RobustAndOptimalControl")
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using RobustAndOptimalControl

Use the function named_ss, to set the names of input and output signals for each unit.

In [ ]:
F1 = named_ss(F, x=:xF, u=:r, y=:u_f)
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 -1.0
B = 
 1.0
C = 
 1.0
D = 
 0.0

Continuous-time state-space model
With state  names: xF
     input  names: r
     output names: u_f
In [ ]:
G1 = named_ss(G, x=:xG, u=:u, y=:y_m)
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
  0.0   16.0
 -6.25  -5.0
B = 
 0.0
 2.0
C = 
 3.125  0.0
D = 
 0.0

Continuous-time state-space model
With state  names: xG1 xG2
     input  names: u
     output names: y_m
In [ ]:
C1 = named_ss(C, x=:xC, u=:e, y=:u_c)
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 0.0    4.0    0.0
 0.0    0.0   16.0
 0.0  -25.0  -40.0
B = 
 0.0
 0.0
 8.0
C = 
 2.34375  0.15625  2.5
D = 
 0.0

Continuous-time state-space model
With state  names: xC1 xC2 xC3
     input  names: e
     output names: u_c
In [ ]:
S1 = named_ss(S, x=:xS, u=:y_m, y=:y)
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 -10.0
B = 
 4.0
C = 
 2.5
D = 
 0.0

Continuous-time state-space model
With state  names: xS
     input  names: y_m
     output names: y

Designate the totalisers using the function sumblock.

In [ ]:
Sum1 = sumblock("e = r - y")
Out[0]:
sumblock: NamedStateSpace{Continuous, Float64}
D = 
 1.0  -1.0

Continuous-time state-space model
With state  names: 
     input  names: r y
     output names: e
In [ ]:
Sum2 = sumblock("u = u_f + u_c")
Out[0]:
sumblock: NamedStateSpace{Continuous, Float64}
D = 
 1.0  1.0

Continuous-time state-space model
With state  names: 
     input  names: u_f u_c
     output names: u

It is important to mark the connections carefully. Connections are formed by the principle that the output of one block is connected to the input of another block. For example, the signal е is an output of Sum1, but it is an input to the block C.

In [ ]:
connections = [
    :e => :e # output e Sum1 to input C
    :y => :y # output y S to input Sum1
    :u => :u # output u Sum2 to input G
    :u_f => :u_f # output u_f F to input Sum2
    :u_c => :u_c # output u_c C to input Sum2
    :y_m => :y_m # output G to input S
]
Out[0]:
6-element Vector{Pair{Symbol, Symbol}}:
   :e => :e
   :y => :y
   :u => :u
 :u_f => :u_f
 :u_c => :u_c
 :y_m => :y_m

It is also important to define the input signal w1 and the output signal z1.

In [ ]:
w1 = [:r]
z1 = [:y_m]
Out[0]:
1-element Vector{Symbol}:
 :y_m

Feed all calculated data to the input connect. You can learn more about all the function parameters in the Julia System Integration documentation.

In [ ]:
P = connect([F1, C1, G1, S1, Sum1, Sum2], connections; w1,z1,unique = false)
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 -1.0  0.0       0.0       0.0   0.0    0.0    0.0
  0.0  0.0       4.0       0.0   0.0    0.0    0.0
  0.0  0.0       0.0      16.0   0.0    0.0    0.0
  0.0  0.0     -25.0     -40.0   0.0    0.0  -20.0
  0.0  0.0       0.0       0.0   0.0   16.0    0.0
  2.0  4.6875    0.3125    5.0  -6.25  -5.0    0.0
  0.0  0.0       0.0       0.0  12.5    0.0  -10.0
B = 
 1.0
 0.0
 0.0
 8.0
 0.0
 0.0
 0.0
C = 
 0.0  0.0  0.0  0.0  3.125  0.0  0.0
D = 
 0.0

Continuous-time state-space model
With state  names: xF##feedback#587 xC1##feedback#587 xC2##feedback#587 xC3##feedback#587 xG1##feedback#587 xG2##feedback#587 xS##feedback#587
     input  names: r
     output names: y_m

Let's construct the transient process of the obtained closed-loop system.

In [ ]:
plot(stepinfo(step(P,5)))
Out[0]:

Conclusion

In this article we have looked at ways to connect models. You can learn more about functions for transforming structural diagrams in Building Systems.