Skip to content

Commit 972f004

Browse files
committed
More work and test on feedback interconnections.
1 parent 8e9aa11 commit 972f004

File tree

3 files changed

+74
-28
lines changed

3 files changed

+74
-28
lines changed

src/connections.jl

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -267,33 +267,42 @@ end
267267
feedback(s1::AbstractStateSpace, s2::AbstractStateSpace;
268268
U1=1:size(s1,2), Y1=1:size(s1,1), U2=1:size(s2,2), Y2=1:size(s2,1),
269269
W1=1:size(s1,2), Z1=1:size(s1,1), W2=Int[], Z2=Int[],
270-
w_reorder=nothing, z_reorder=nothing,
271-
neg_feeback::Bool=true)
270+
w_reorder=nothing, z_reorder=nothing,n
271+
pos_feeback::Bool=false)
272272
273273
274274
`U1`, `Y1`, `U2`, `Y2` contains the indices of the signals that should be connected.
275275
`W1`, `Z1`, `W2`, `Z2` contains the signal indices of `s1` and `s2` that should be kept.
276276
277-
Specify `Wreorder` and `Zreorder` to reorder [W1; W2] and [Z1; Z2] after matrix multiplications.
277+
Specify `Wperm` and `Zperm` to reorder [W1; W2] and [Z1; Z2] in the resulting statespace model.
278278
279-
Negative feedback is the default. Specify `neg_feedback=false` for positive feedback.
279+
Negative feedback is the default. Specify `pos_feedback=true` for positive feedback.
280280
281281
See Zhou etc. for similar (somewhat less symmetric) formulas.
282282
"""
283283
function feedback(s1::AbstractStateSpace, s2::AbstractStateSpace;
284284
U1=1:size(s1,2), Y1=1:size(s1,1), U2=1:size(s2,2), Y2=1:size(s2,1),
285285
W1=1:size(s1,2), Z1=1:size(s1,1), W2=Int[], Z2=Int[],
286-
w_reorder=nothing, z_reorder=nothing,
287-
neg_feedback::Bool=true)
286+
Wperm=nothing, Zperm=nothing,
287+
pos_feedback::Bool=false)
288288

289-
if !(allunique(Y1) && allunique(Y2))
290-
warning("Connecting a single output to multiple inputs.")
289+
290+
291+
if !allunique(Y1); @warn "Connecting single output to multiple inputs Y1=$Y1"; end
292+
if !allunique(Y2); @warn "Connecting single output to multiple inputs Y2=$Y2"; end
293+
if !allunique(U1); @warn "Connecting multiple outputs to a single input U1=$U1"; end
294+
if !allunique(U2); @warn "Connecting a single output to multiple inputs U2=$U2"; end
295+
296+
if length(U1) != length(Y2)
297+
error("Dimensions of input u1 ($(length(U1))) and output y2 ($(length(Y2))) must be equal")
291298
end
292-
if !(allunique(U1) && allunique(U2))
293-
warning("Connecting multiple outputs to a single input.")
299+
if length(U2) != length(Y1)
300+
error("Dimensions of input u2 ($(length(U2))) and output y1 ($(length(Y2))) must be equal")
294301
end
295302

296-
α = neg_feedback ? -1 : 1 # The sign of feedback
303+
304+
305+
α = pos_feedback ? 1 : -1 # The sign of feedback
297306

298307
s1_B1 = s1.B[:,W1]
299308
s1_B2 = s1.B[:,U1]
@@ -339,9 +348,9 @@ function feedback(s1::AbstractStateSpace, s2::AbstractStateSpace;
339348
s2_D12*R2*s1_D21 s2_D11 + α*s2_D12*R2*s1_D22*s2_D21]
340349
end
341350
# Return while reorganizing into the desired order
342-
return StateSpace(A, isnothing(w_reorder) ? B : B[:, w_reorder],
343-
isnothing(z_reorder) ? C : C[z_reorder,:],
344-
isnothing(w_reorder) && isnothing(z_reorder) ? D : D[z_reorder, w_reorder])
351+
return StateSpace(A, isnothing(Wperm) ? B : B[:, Wperm],
352+
isnothing(Zperm) ? C : C[Zperm,:],
353+
isnothing(Wperm) && isnothing(Zperm) ? D : D[Zperm, Wperm])
345354
#return StateSpace(A, B_tmp, C_tmp, D_tmp)
346355
end
347356

@@ -373,9 +382,9 @@ function lft(G, Δ, type=:l) # QUESTION: Or lft_u, and lft_l instead?
373382
end
374383

375384
if type == :l
376-
feedback(G, Δ, U1=G.nu-Δ.ny+1:G.nu, Y1=G.ny-Δ.nu+1:G.ny, W1=1:G.ny-Δ.nu, Z1=1:G.nu-Δ.ny, neg_feedback=false)
385+
feedback(G, Δ, U1=G.nu-Δ.ny+1:G.nu, Y1=G.ny-Δ.nu+1:G.ny, W1=1:G.ny-Δ.nu, Z1=1:G.nu-Δ.ny, pos_feedback=true)
377386
elseif type == :u
378-
feedback(G, Δ, U1=1:Δ.ny, Y1=1:Δ.nu, W1=Δ.nu+1:G.ny, Z1=Δ.nu+1:G.ny, neg_feedback=false)
387+
feedback(G, Δ, U1=1:Δ.ny, Y1=1:Δ.nu, W1=Δ.nu+1:G.ny, Z1=Δ.nu+1:G.ny, pos_feedback=true)
379388
else
380389
error("Invalid type of lft ($type). Specify type=:l (:u) for lower (upper) lft.")
381390
end
@@ -392,13 +401,8 @@ Compute the Redheffer star product.
392401
For details, see Chapter 9.3 in
393402
**Zhou, K. and JC Doyle**. Essentials of robust control, Prentice hall (NJ), 1998
394403
"""
395-
function starprod(G1, G2, dimy::Int, dimu::Int)
396-
feedback(G1, G2, U1=G1.nu-dimu+1:G1.nu, Y1=G1.ny-dimy+1:G1.ny, W1=1:G1.nu-dimu, Z1=1:G1.ny-dimy,
397-
U2=1:dimy, Y2=1:dimu, W2=dimy+1:G2.nu, Z2=dimu+1:G2.ny,
398-
neg_feedback=false)
399-
end
400-
function starprod(sys1, sys2)
401-
nu = size(sys2, 2)
402-
ny = size(sys2, 1)
403-
starp(sys1, sys2, nu, ny)
404-
end
404+
starprod(G1, G2, dimy::Int, dimu::Int) = feedback(G1, G2,
405+
U1=G1.nu-dimu+1:G1.nu, Y1=G1.ny-dimy+1:G1.ny, W1=1:G1.nu-dimu, Z1=1:G1.ny-dimy,
406+
U2=1:dimy, Y2=1:dimu, W2=dimy+1:G2.nu, Z2=dimu+1:G2.ny,
407+
pos_feedback=true)
408+
starprod(sys1, sys2) = lft(sys1, sys2, :l)

src/types/Lti.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ abstract type LTISystem <: AbstractSystem end
2929
# TODO We should have proper fallbacks for matrices too
3030

3131
feedback(sys1::Union{LTISystem,Number,AbstractMatrix{<:Number}},
32-
sys2::Union{LTISystem,Number,AbstractMatrix{<:Number}}) = feedback(promote(sys1, sys2)...)
32+
sys2::Union{LTISystem,Number,AbstractMatrix{<:Number}}; kwargs...) = feedback(promote(sys1, sys2)...; kwargs...)
3333

3434
Base.inv(G::LTISystem) = 1/G
3535

test/test_connections.jl

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,56 @@ arr4[1] = ss(0); arr4[2] = ss(1); arr4[3] = ss(2)
153153

154154

155155

156-
# Test lft
156+
157157
G1 = ss(-9, [2 3], [4; 5], 0)
158158
G2 = ss(-6, 7, 8, 0)
159159

160+
K1 = ss(-1, 1, 1, 0)
161+
162+
G3 = ss(-1, 1, 1, 1) # Not strictly proper
163+
164+
# Test general feedback interconnections
165+
166+
@test feedback(G1, K1, U1=[1], Y1=[1], W1=[2], Z1=[2]) == ss([-9 -2; 4 -1], [3; 0], [5 0], 0)
167+
@test feedback(G1, K1, U1=[1], Y1=[1], W1=[1], Z1=[1]) == ss([-9 -2; 4 -1], [2; 0], [4 0], 0)
168+
@test feedback(G1, K1, U1=[2], Y1=[2], W1=[1], Z1=[1]) == ss([-9 -3; 5 -1], [2; 0], [4 0], 0)
169+
170+
@test feedback(K1, G1, W1=Int[], Z1=Int[], U2=[1], Y2=[1], W2=[2], Z2=[2]) == ss([-1 -4; 2 -9], [0; 3], [0 5], 0)
171+
172+
173+
@test_broken feedback(G3, 1) == ss(-1.5, 2, , 0.5)
174+
175+
176+
feedback(G3, 1) == ss(-1.5, 2, )
177+
178+
@test_throws ErrorException feedback(G1, K1, U1=1:2, Y2=1)
179+
180+
#@test_warn feedback(G1, K1, U1=1:2, Y1=[2], Y2=[1, 1])
181+
#@test_logs feedback(G1, K1, U1=1:2, Y1=[2], Y2=[1, 1])
182+
183+
184+
185+
@test feedback(G1, K1, U1=[1], Y1=[1], W1=[2], Z1=[2], pos_feedback=true) == ss([-9 2; 4 -1], [3; 0], [5 0], 0)
186+
@test feedback(G2, 1, pos_feedback=true) == ss(50, 7, 8, 0)
187+
188+
189+
feedback(G1, K1, U1=[1], Y1=[1], W1=[2], Z1=[2], pos_feedback=true)
190+
191+
# Linear fractional transformations
192+
160193
@test lft(G1, G2) == ss([-9 24; 35 -6], [2; 0], [4 0], 0)
161194
@test lft(G1, G2, :l) == ss([-9 24; 35 -6], [2; 0], [4 0], 0)
162195
@test lft(G1, G2, :u) == ss([-9 16; 28 -6], [3; 0], [5 0], 0)
163196

197+
@test_throws ErrorException lft(G2, G1)
198+
@test_throws ErrorException lft(G2, G1, :l)
199+
@test_throws ErrorException lft(G2, G1, :u)
200+
@test_throws ErrorException lft(G1, G2, :x) # Invalid type of lft
201+
202+
G4 = ss(-6, [7 8], [11; 12], 0)
203+
@test starprod(G1, G4, 1, 1) == ss([-9 33; 35 -6], [2 0; 0 8], [4 0; 0 12], zeros(2,2))
204+
205+
164206
#FIXME: Add more tests
165207

166208

0 commit comments

Comments
 (0)