Skip to content

Commit fc0bd85

Browse files
committed
handle MIMO tf feedback and division by converting to ss
1 parent 23982a4 commit fc0bd85

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

lib/ControlSystemsBase/src/connections.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ feedback(P1::TransferFunction, P2::TransferFunction; pos_feedback::Bool = false)
259259

260260
function feedback(G1::TransferFunction{<:TimeEvolution,<:SisoRational}, G2::TransferFunction{<:TimeEvolution,<:SisoRational}; pos_feedback::Bool = false)
261261
if !issiso(G1) || !issiso(G2)
262-
error("MIMO TransferFunction feedback isn't implemented.")
262+
@warn("MIMO TransferFunction feedback isn't implemented yet, converting to a state-space object and back. Consider converting your transfer functions to state-space form using `ss` as soon as possible.")
263+
return tf(feedback(ss(G1), ss(G2); pos_feedback))
263264
end
264265
G1num = numpoly(G1)[]
265266
G1den = denpoly(G1)[]
@@ -274,7 +275,8 @@ end
274275
#Efficient implementations
275276
function feedback(L::TransferFunction{<:TimeEvolution,T}) where T<:SisoRational
276277
if size(L) != (1,1)
277-
error("MIMO TransferFunction feedback isn't implemented, use L/(1+L)")
278+
@warn("MIMO TransferFunction feedback isn't implemented yet, converting to a state-space object and back. Consider converting your transfer functions to state-space form using `ss` as soon as possible.")
279+
return tf(feedback(ss(L)))
278280
end
279281
P = numpoly(L)
280282
Q = denpoly(L)
@@ -283,7 +285,8 @@ end
283285

284286
function feedback(L::TransferFunction{TE, T}) where {TE<:TimeEvolution, T<:SisoZpk}
285287
if size(L) != (1,1)
286-
error("MIMO TransferFunction feedback isn't implemented, use L/(1+L)")
288+
@warn("MIMO TransferFunction feedback isn't implemented yet, converting to a state-space object and back. Consider converting your transfer functions to state-space form using `ss` as soon as possible.")
289+
return tf(feedback(ss(L)))
287290
end
288291
#Extract polynomials and create P/(P+Q)
289292
k = L.matrix[1].k

lib/ControlSystemsBase/src/types/TransferFunction.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,22 @@ function /(n::Number, G::TransferFunction)
227227
matrix = fill(entry, 1, 1)
228228
return TransferFunction(matrix, G.timeevol)
229229
else
230-
error("MIMO TransferFunction inversion isn't implemented yet")
230+
error("MIMO TransferFunction inversion isn't implemented yet, consider converting your transfer functions to state-space form using `ss`")
231231
end
232232
end
233233
/(G::TransferFunction, n::Number) = G*(1/n)
234-
/(G1::TransferFunction, G2::TransferFunction) = G1*(1/G2)
235234
Base.:(/)(sys1::LTISystem, sys2::TransferFunction) = *(promote(sys1, ss(1/sys2))...) # This special case is needed to properly handle improper inverse transfer function (1/s)
235+
function /(f1::TransferFunction, f2::TransferFunction)
236+
if issiso(f2)
237+
T = numeric_type(f2)
238+
One = one(1/one(T)) # This gymatics is to ensure that we get floats out of integer system division. We will always get floats for ss division in the branch below, so this is required for type stability
239+
f1*(One/f2)
240+
else
241+
@warn "MIMO TransferFunction inversion isn't implemented yet, converting to state-space object and back. Consider converting your transfer functions to state-space form using `ss` as soon as possible."
242+
tf(ss(f1) / ss(f2))
243+
end
244+
end
245+
236246

237247

238248
#####################################################################

lib/ControlSystemsBase/test/test_transferfunction.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,22 @@ if VERSION >= v"1.8.0-rc1"
271271
@test @test_logs (:warn, r"deprecated") tf(1).Ts == 0
272272
end
273273

274+
# Test MIMO TransferFunction feedback behavior
275+
@test_logs (:warn, r"MIMO TransferFunction feedback isn't implemented yet") feedback(C_222)
276+
@test_logs (:warn, r"MIMO TransferFunction feedback isn't implemented yet") feedback(C_222, C_222)
277+
# Test that feedback returns state-space for MIMO
278+
fb_result = @test_logs (:warn, r"MIMO TransferFunction feedback isn't implemented yet") feedback(C_222)
279+
@test fb_result isa TransferFunction
280+
fb_result2 = @test_logs (:warn, r"MIMO TransferFunction feedback isn't implemented yet") feedback(C_222, C_222)
281+
@test fb_result2 isa TransferFunction
282+
283+
# Test MIMO TransferFunction division behavior
284+
Ci_222 = tf(ssrand(2,2,2))
285+
# Test that division returns state-space for MIMO
286+
div_result = @test_logs (:warn, r"MIMO TransferFunction inversion isn't implemented yet") C_222 / Ci_222
287+
@test div_result isa TransferFunction
288+
289+
# Test improved error messages in MIMO TransferFunction inversion
290+
@test_throws ErrorException("MIMO TransferFunction inversion isn't implemented yet, consider converting your transfer functions to state-space form using `ss`") 1 / Ci_222
291+
274292
end

0 commit comments

Comments
 (0)