|
378 | 378 |
|
379 | 379 |
|
380 | 380 | ## DIVISION ##
|
381 |
| -/(sys1::AbstractStateSpace, sys2::AbstractStateSpace) = sys1*inv(sys2) |
| 381 | + |
| 382 | + |
| 383 | +""" |
| 384 | + /(sys1::AbstractStateSpace{TE}, sys2::AbstractStateSpace{TE}; atol::Real = 0, atol1::Real = atol, atol2::Real = atol, rtol::Real = max(size(sys1.A, 1), size(sys2.A, 1)) * eps(real(float(one(numeric_type(sys1))))) * iszero(min(atol1, atol2))) |
| 385 | +
|
| 386 | +Compute `sys1 / sys2 = sys1 * inv(sys2)` in a way that tries to handle situations in which the inverse `sys2` is non-proper, but the resulting system `sys1 / sys2` is proper. |
| 387 | +
|
| 388 | +See `ControlSystemsBase.MatrixPencils.isregular` for keyword arguments `atol`, `atol1`, `atol2`, and `rtol`. |
| 389 | +""" |
| 390 | +function Base.:(/)(sys1::AbstractStateSpace{TE}, sys2::AbstractStateSpace{TE}; |
| 391 | + atol::Real = 0, atol1::Real = atol, atol2::Real = atol, |
| 392 | + rtol::Real = max(size(sys1.A,1),size(sys2.A,1))*eps(real(float(one(numeric_type(sys1)))))*iszero(min(atol1,atol2))) where {TE<:ControlSystemsBase.TimeEvolution} |
| 393 | + T1 = float(numeric_type(sys1)) |
| 394 | + T2 = float(numeric_type(sys2)) |
| 395 | + T = promote_type(T1,T2) |
| 396 | + timeevol = common_timeevol(sys1, sys2) |
| 397 | + ny2, nu2 = sys2.ny, sys2.nu |
| 398 | + nu2 == ny2 || error("The system sys2 must be square") |
| 399 | + ny1, nu1 = sys1.ny, sys1.nu |
| 400 | + nu1 == nu2 || error("The systems sys1 and sys2 must have the same number of inputs") |
| 401 | + nx1 = sys1.nx |
| 402 | + nx2 = sys2.nx |
| 403 | + if nx2 > 0 |
| 404 | + A, B, C, D = ssdata([sys2; sys1]) |
| 405 | + Ai = [A B; C[1:ny2,:] D[1:ny2,:]] |
| 406 | + Ei = [I zeros(T,nx1+nx2,ny2); zeros(T,ny2,nx1+nx2+ny2)] |> Matrix # TODO: rm call to Matrix when type piracy in https://github.com/JuliaLinearAlgebra/LinearMaps.jl/issues/219 is fixed |
| 407 | + MatrixPencils.isregular(Ai, Ei; atol1, atol2, rtol) || |
| 408 | + error("The system sys2 is not invertible") |
| 409 | + Ci = [C[ny2+1:ny1+ny2,:] D[ny2+1:ny1+ny2,:]] |
| 410 | + Bi = [zeros(T,nx1+nx2,nu1); -I] |> Matrix # TODO: rm call to Matrix when type piracy in https://github.com/JuliaLinearAlgebra/LinearMaps.jl/issues/219 is fixed |
| 411 | + Di = zeros(T,ny1,nu1) |
| 412 | + Ai, Ei, Bi, Ci, Di = MatrixPencils.lsminreal(Ai, Ei, Bi, Ci, Di; fast = true, atol1 = 0, atol2, rtol, contr = true, obs = true, noseig = true) |
| 413 | + if Ei != I |
| 414 | + luE = lu!(Ei, check=false) |
| 415 | + issuccess(luE) || throw(ArgumentError("The system sys2 is not invertible")) |
| 416 | + Ai = luE\Ai |
| 417 | + Bi = luE\Bi |
| 418 | + end |
| 419 | + else |
| 420 | + D2 = T.(sys2.D) |
| 421 | + LUD = lu(D2) |
| 422 | + (norm(D2,Inf) <= atol1 || rcond(LUD.U) <= 10*nu1*eps(real(float(one(T))))) && |
| 423 | + error("The system sys2 is not invertible") |
| 424 | + Ai, Bi, Ci, Di = ssdata(sys1) |
| 425 | + rdiv!(Bi,LUD); rdiv!(Di,LUD) |
| 426 | + end |
| 427 | + |
| 428 | + return StateSpace{TE, T}(Ai, Bi, Ci, Di, timeevol) |
| 429 | +end |
382 | 430 |
|
383 | 431 | function /(n::Number, sys::ST) where ST <: AbstractStateSpace
|
384 | 432 | # Ensure s.D is invertible
|
|
0 commit comments