Skip to content

Commit 0f85ae3

Browse files
committed
add notes on converting transfer functions in docs
1 parent a716bda commit 0f85ae3

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

docs/src/API/linear_analysis.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Linear analysis refers to the process of linearizing a nonlinear model and analy
77

88
- [`get_sensitivity`](@ref) get the [sensitivity function (wiki)](https://en.wikipedia.org/wiki/Sensitivity_(control_systems)), $S(s)$, as defined in the field of control theory.
99
- [`get_comp_sensitivity`](@ref) get the complementary sensitivity function $T(s) : S(s)+T(s)=1$.
10-
- [`get_looptransfer`](@ref) get the (open) loop-transfer function where the loop starts and ends in the analysis point.
11-
- [`linearize`](@ref) can be called with two analysis points denoting the input and output of the linearized system. Parts of the model not appearing between the input and output will be removed.
10+
- [`get_looptransfer`](@ref) get the (open) loop-transfer function where the loop starts and ends in the analysis point. For a typical simple feedback connection with a plant $P(s)$ and a controller $C(s)$, the loop-transfer function at the plant output is $P(s)C(s)$.
11+
- [`linearize`](@ref) can be called with two analysis points denoting the input and output of the linearized system.
1212
- [`open_loop`](@ref) return a new (nonlinear) system where the loop has been broken in the analysis point, i.e., the connection the analysis point usually implies has been removed.
1313

1414
An analysis point can be created explicitly using the constructor [`AnalysisPoint`](@ref), or automatically when connecting two causal components using `connect`:
@@ -52,7 +52,7 @@ We create `ControlSystemsBase.StateSpace` objects using
5252
using ControlSystemsBase, Plots
5353
S = ss(matrices_S...)
5454
T = ss(matrices_T...)
55-
bodeplot([S, T], lab=["S" "" "T" ""])
55+
bodeplot([S, T], lab=["S" "" "T" ""], plot_title="Bode plot of sensitivity functions", margin=5Plots.mm)
5656
```
5757

5858
The sensitivity functions obtained this way should be equivalent to the ones obtained with the code below
@@ -79,14 +79,28 @@ L = P*(-C) # Add the minus sign to build the negative feedback into the controll
7979

8080
To obtain the transfer function between two analysis points, we call `linearize`
8181
```@example LINEAR_ANALYSIS
82-
matrices_P = linearize(sys, :plant_input, :plant_output)[1]
82+
matrices_PS = linearize(sys, :plant_input, :plant_output)[1]
8383
```
84-
this particular transfer function should be equivalent to the linear system `P`, i.e., equivalent to this call
85-
```@example LINEAR_ANALYSIS
86-
@unpack input, output = P # To get the correct namespace
87-
linearize(P, [input.u], [output.u])[1]
84+
this particular transfer function should be equivalent to the linear system `P(s)S(s)`, i.e., equivalent to
85+
```@example LINEAR_ANALYSIS_CS
86+
feedback(P, C)
87+
```
88+
89+
### Obtaining transfer functions
90+
A statespace system from [ControlSystemsBase](https://juliacontrol.github.io/ControlSystems.jl/latest/man/creating_systems/) can be converted to a transfer function using the function `tf`:
91+
```@example LINEAR_ANALYSIS_CS
92+
tf(S)
8893
```
8994

95+
## Gain and phase margins
96+
Further linear analysis can be performed using the [analysis methods from ControlSystemsBase](https://juliacontrol.github.io/ControlSystems.jl/latest/lib/analysis/). For example, calculating the gain and phase margins of a system can be done using
97+
```@example LINEAR_ANALYSIS_CS
98+
margin(P)
99+
```
100+
(they are infinite for this system). A Nyquist plot can be produced using
101+
```@example LINEAR_ANALYSIS_CS
102+
nyquistplot(P)
103+
```
90104
## Index
91105
```@index
92106
Pages = ["linear_analysis.md"]

test/Blocks/test_analysis_points.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ eqs = [connect(P.output, C.input)
1414
connect(C.output, ap, P.input)]
1515
sys = ODESystem(eqs, t, systems = [P, C], name = :hej)
1616

17-
ssys = structural_simplify(expand_analysis_points(sys))
17+
ssys = structural_simplify(sys)
1818
prob = ODEProblem(ssys, [P.x => 1], (0, 10))
1919
sol = solve(prob, Rodas5())
2020
@test norm(sol[1]) >= 1
@@ -120,8 +120,7 @@ eqs = [connect(r.output, F.input)
120120
connect(F.output, sys_inner.add.input1)]
121121
sys_outer = ODESystem(eqs, t, systems = [F, sys_inner, r], name = :outer)
122122

123-
# test first that the structural_simplify ∘ expand_analysis_points works correctly
124-
#ssys = structural_simplify(expand_analysis_points(sys_outer))
123+
# test first that the structural_simplify works correctly
125124
ssys = structural_simplify(sys_outer)
126125
prob = ODEProblem(ssys, [P.x => 1], (0, 10))
127126
# sol = solve(prob, Rodas5())
@@ -140,7 +139,7 @@ lsyso = sminreal(ss(matrices_So...))
140139
@test lsys == lsyso || lsys == -1 * lsyso * (-1) # Output and input sensitivites are equal for SISO systems
141140

142141
## A more complicated test case
143-
using ModelingToolkit, OrdinaryDiffEq, Plots, LinearAlgebra
142+
using ModelingToolkit, OrdinaryDiffEq, LinearAlgebra
144143
using ModelingToolkitStandardLibrary.Mechanical.Rotational
145144
using ModelingToolkitStandardLibrary.Blocks: t, Sine, PID, SecondOrder, Step, RealOutput
146145
using ModelingToolkit: connect

0 commit comments

Comments
 (0)