Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions docs/src/man/creating_systems.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,19 +268,6 @@ P = ssrand(2,3,1) # A random 2×3 MIMO system
sys_array = getindex.(Ref(P), 1:P.ny, (1:P.nu)')
```

### Creating arrays with different types of systems
When calling `hcat/vcat`, Julia automatically tries to promote the types to the smallest common supertype, this means that creating an array with one continuous and one discrete-time system fails
```@example MIMO
P_cont = ssrand(2,3,1)
P_disc = ssrand(2,3,1, Ts=1)
@test_throws ErrorException [P_cont, P_disc] # ERROR: Sampling time mismatch
```
You can explicitly tell Julia that you want a particular supertype, e.g,
```@example MIMO
StateSpace[P_cont, P_disc]
```
The type `StateSpace` is abstract, since the type parameters are not specified.

## Demo systems
The module `ControlSystemsBase.DemoSystems` contains a number of demo systems demonstrating different kinds of dynamics.

Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/src/ControlSystemsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ function __init__()
print(io, " for automatic discretization (applicable to systems without delays or nonlinearities only).")
end
plots_id = Base.PkgId(UUID("91a5bcdd-55d7-5caf-9e0b-520d859cae80"), "Plots")
if nameof(exc.f) === :plot && parentmodule(argtypes[1]) == @__MODULE__() && !haskey(Base.loaded_modules, plots_id)
if exc.f !== nothing && nameof(exc.f) === :plot && parentmodule(argtypes[1]) == @__MODULE__() && !haskey(Base.loaded_modules, plots_id)
printstyled(io, "\nPlotting is not available unless Plots.jl is loaded manually. Call `using Plots` before plotting.", color=:green, bold=true)
elseif (exc.f == /) && argtypes[2] <: DelayLtiSystem
print(io, "A delayed system can not be inverted. Consider use of the function `feedback`.")
Expand Down
10 changes: 10 additions & 0 deletions lib/ControlSystemsBase/src/connections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ end
Base.typed_hcat(::Type{S}, X::Number...) where {S<:LTISystem} = hcat(convert.(S, X)...)
Base.typed_hcat(::Type{S}, X::Union{AbstractArray{<:Number,1}, AbstractArray{<:Number,2}}...) where {S<:LTISystem} = hcat(convert.(S, X)...)

## Mixed-type array creation
# When creating an array of systems, an error may be thrown if the default Base.vect is called that tries to promote all systems to a common type. E.g., when using non-proper transfer functions and statespace systems. We thus opt out of the conversion with the method below
function Base.vect(X::LTISystem...)
LTISystem[X...]
end

function Base.vect(X::T...) where T <: LTISystem
T[X...]
end

"""
add_input(sys::AbstractStateSpace, B2::AbstractArray, D2 = 0)

Expand Down
8 changes: 7 additions & 1 deletion lib/ControlSystemsBase/src/types/StateSpace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,13 @@ end
## Approximate ##
function isapprox(sys1::ST1, sys2::ST2; kwargs...) where {ST1<:AbstractStateSpace,ST2<:AbstractStateSpace}
fieldnames(ST1) == fieldnames(ST2) || (return false)
return all(isapprox(getfield(sys1, f), getfield(sys2, f); kwargs...) for f in fieldnames(ST1))
return all(fieldnames(ST1)) do f
if fieldtype(ST1, f) <: Union{Number, AbstractArray{<:Number}, LTISystem}
isapprox(getfield(sys1, f), getfield(sys2, f); kwargs...)
else
getfield(sys1, f) == getfield(sys2, f)
end
end
end

## ADDITION ##
Expand Down
4 changes: 3 additions & 1 deletion lib/ControlSystemsBase/src/types/TransferFunction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ isrational(::TransferFunction) = true
#####################################################################

## EQUALITY ##
function ==(G1::TransferFunction, G2::TransferFunction)
function ==(G1::T, G2::T) where T<:TransferFunction
fields = (:timeevol, :ny, :nu, :matrix)
for field in fields
if getproperty(G1, field) != getproperty(G2, field)
Expand All @@ -115,6 +115,8 @@ function ==(G1::TransferFunction, G2::TransferFunction)
return true
end

==(G1::TransferFunction, G2::TransferFunction) = ==(promote(G1,G2)...)

## Approximate ##
function isapprox(G1::TransferFunction, G2::TransferFunction; kwargs...)
G1, G2 = promote(G1, G2)
Expand Down
4 changes: 2 additions & 2 deletions lib/ControlSystemsBase/src/types/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ function siso_tf_to_ss(T::Type, f::SisoRational)
num0, den0 = numvec(f), denvec(f)
# Normalize the numerator and denominator to allow realization of transfer functions
# that are proper, but not strictly proper
num = num0 / den0[1]
den = den0 / den0[1]
num = num0 ./ den0[1]
den = den0 ./ den0[1]

N = length(den) - 1 # The order of the rational function f

Expand Down
10 changes: 9 additions & 1 deletion lib/ControlSystemsBase/test/test_connections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,15 @@ P = ss(-1.0, 2.0, 3.0, 4.0)
@test [2.5 P 3.5] == ss(-1.0, [0.0 2.0 0.0], 3.0, [2.5 4.0 3.5])
@test [2.5; P; 3.5] == ss(-1.0, 2.0, [0.0; 3.0; 0.0], [2.5; 4.0; 3.5])


# Test vector creation
v = [ssrand(1,1,1), tf(1)]
@test v isa Vector{LTISystem}
@test v[1] isa StateSpace{Continuous, Float64}
@test v[2] isa TransferFunction{Continuous, ControlSystemsBase.SisoRational{Int64}}

# Test vector creation
v = [tf(1), tf(1)]
@test v isa Vector{TransferFunction{Continuous, ControlSystemsBase.SisoRational{Int64}}}

# Combination tfRational and sisoZpk
Czpk_111 = zpk([-2],[-5],1)
Expand Down
2 changes: 1 addition & 1 deletion lib/ControlSystemsBase/test/test_zpk.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ k = 0.3
@test eltype(fill(zpk(1,0.005)/zpk(2, 0.005),2)) <: TransferFunction
@test eltype(fill(zpk(1)+1,2)) <: TransferFunction

@test eltype([tf(1,1), zpk(1,1)]) <: TransferFunction
@test eltype([tf(1,1), zpk(1,1)]) <: LTISystem

zpk(tf([1 2; 3 4])) == zpk([1 2; 3 4])

Expand Down
Loading