Skip to content

Commit 18a2f9c

Browse files
committed
Add open_loop
depends on SciML/ModelingToolkit.jl#1824
1 parent f839206 commit 18a2f9c

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

src/Blocks/Blocks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export PI, LimPI, PID, LimPID
2727
include("continuous.jl")
2828

2929
export AnalysisPoint, expand_analysis_points, get_sensitivity, get_comp_sensitivity,
30-
get_looptransfer
30+
get_looptransfer, open_loop
3131
include("analysis_points.jl")
3232

3333
end

src/Blocks/analysis_points.jl

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ connect(in, :ap_name, out)
2121
- `out`: A connector of type [`RealInput`](@ref).
2222
- `name`: The name of the analysis point.
2323
24-
See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`get_looptransfer`](@ref)
24+
See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`get_looptransfer`](@ref), [`open_loop`](@ref)
2525
2626
# Example
2727
```julia
@@ -184,12 +184,10 @@ Compute the (linearized) loop-transfer function in analysis point `ap`, from `ap
184184
# Arguments:
185185
- `kwargs`: Are sent to `ModelingToolkit.linearize`
186186
187-
See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref).
187+
See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`open_loop`](@ref).
188188
"""
189189
function get_looptransfer(sys, ap::AnalysisPoint; kwargs...)
190190
t = get_iv(sys)
191-
@variables u(t) = 0
192-
@variables y(t) = 0
193191
new_eqs = map(get_eqs(sys)) do eq
194192
eq.rhs == ap || (return eq)
195193
0 ~ 0 # we just want to open the connection
@@ -198,8 +196,36 @@ function get_looptransfer(sys, ap::AnalysisPoint; kwargs...)
198196
ModelingToolkit.linearize(sys, [ap.out.u], [ap.in.u]; kwargs...)
199197
end
200198

199+
"""
200+
open_sys = open_loop(sys, ap::AnalysisPoint; kwargs)
201+
open_sys = open_loop(sys, ap_name::Symbol; kwargs)
202+
203+
Open the loop at analysis point `ap` by breaking the connection through `ap`.
204+
205+
`open_sys` will have `ap.out` as input and `ap.in` as output.
206+
207+
# Arguments:
208+
- `kwargs`: Are sent to `ModelingToolkit.linearize`
209+
210+
See also [`get_sensitivity`](@ref), [`get_comp_sensitivity`](@ref), [`get_looptransfer`](@ref).
211+
"""
212+
function open_loop(sys, ap::AnalysisPoint; kwargs...)
213+
t = get_iv(sys)
214+
@variables u(t)=0 [input = true]
215+
@variables y(t)=0 [output = true]
216+
new_eqs = map(get_eqs(sys)) do eq
217+
eq.rhs == ap || (return [eq])
218+
[ap.out.u ~ u
219+
ap.in.u ~ y]
220+
end
221+
new_eqs = reduce(vcat, new_eqs)
222+
@set! sys.eqs = new_eqs
223+
@set! sys.states = [states(sys); u; y]
224+
sys
225+
end
226+
201227
# Add a method to get_sensitivity that accepts the name of an AnalysisPoint
202-
for f in [:get_sensitivity, :get_comp_sensitivity, :get_looptransfer]
228+
for f in [:get_sensitivity, :get_comp_sensitivity, :get_looptransfer, :open_loop]
203229
@eval function $f(sys, ap_name::Symbol, args...; kwargs...)
204230
$f(sys, find_analysis_point(sys, ap_name), args...; kwargs...)
205231
end

test/Blocks/test_analysis_points.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,13 @@ P = tf(1.0, [1, 1])
6767
C = -1
6868
L = P*C
6969
=#
70+
71+
# Open loop
72+
open_sys = Blocks.open_loop(sys, :plant_input)
73+
@unpack u, y = open_sys
74+
75+
# Linearizing the open-loop system should yield the same system as get_looptransfer
76+
matrices, _ = linearize(open_sys, [u], [y])
77+
@test matrices.A[] == -1
78+
@test matrices.B[] * matrices.C[] == -1 # either one negative
79+
@test matrices.D[] == 0

0 commit comments

Comments
 (0)