Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP system types updated #14

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
27 changes: 22 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,30 @@ language: julia
os:
- linux
- osx
- windows

arch:
- x64
- x86
- arm64

julia:
- 0.5
- 0.6
- 0.7
- 1.1
- nightly

matrix:
exclude:
- os: osx
arch: x86
- os: osx
arch: arm64
- os: windows
arch: arm64
- julia: nightly
arch: arm64
fast_finish: true
allow_failures:
- julia: nightly
Expand All @@ -23,11 +40,11 @@ notifications:
on_failure: change
on_start: never

script:
- julia -e 'Pkg.clone(pwd()); Pkg.build("LTISystems")'
- julia --check-bounds=yes --inline=no -e 'Pkg.test("LTISystems",
coverage=true)'
#script:
# - julia -e 'Pkg.clone(pwd()); Pkg.build("LTISystems")'
# - julia --check-bounds=yes --inline=no -e 'Pkg.test("LTISystems",
# coverage=true)'

after_success:
- julia -e 'cd(Pkg.dir("LTISystems")); Pkg.add("Coverage"); using Coverage;
- julia -e 'using Pkg; Pkg.dir("LTISystems"); Pkg.add("Coverage"); using Coverage;
Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
20 changes: 20 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name = "LTISystems"
uuid = "67f030dc-aa52-5f83-ac42-e4024659685c"
authors = ["Arda Aytekin <[email protected]>, Niklas Everitt <[email protected]>"]

[deps]
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
PolynomialMatrices = "68ae48f1-ae9d-5916-b516-bab924cb4d98"
Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
RationalFunctions = "a89fc88f-fc1e-5208-8949-7a3f8ddd21cd"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"

[compat]
Compat = "≥ 0.18.0"
OrdinaryDiffEq = "≥ 1.0.0"
PolynomialMatrices = "≥ 0.1.1"
RationalFunctions = "≥ 0.1.1"
julia = "≥ 0.7.0"
13 changes: 8 additions & 5 deletions src/LTISystems.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__precompile__(true)
#__precompile__(true)

module LTISystems

Expand All @@ -17,6 +17,9 @@ using PolynomialMatrices
# Polynomials-related things
using Polynomials

# Linear Algebra related things
using LinearAlgebra

# RationalFunctions-related things
using RationalFunctions
import RationalFunctions: poles
Expand All @@ -31,16 +34,16 @@ import Base: convert, promote_rule
import Base: one, zero

# Import num, den for getting numerator and denominator polynomials
import Base: num, den
import Base: numerator, denominator

# Import inv and zeros
import Base: inv, zeros

# Indexing
import Base: getindex, setindex!, endof
import Base: getindex, setindex!, firstindex, lastindex

# Import iteration interface functions
import Base: start, next, done, eltype, length, size
import Base: iterate, IteratorSize, IteratorEltype, eltype, length, size

# Import printing functions
import Base: summary
Expand All @@ -49,7 +52,7 @@ import Base: summary
import Base: step

# Import mathematical operations for overloading
import Base: +, .+, -, .-, *, .*, /, ./, ==, !=, isapprox, transpose
import Base: +, -, *, /, ==, !=, isapprox, transpose

# Export only the useful functions
export
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/mfd2ss.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# realization (Kailath, 1980, Section 6.4.1).
# NOTE: Base this function on the SLICOT routine TC04AD.
# NOTE: Is it necessary to make a SISO version of this function?
function _mfd2ss{S,M1,M2}(mfd::MatrixFractionDescription{Val{:mimo},S,Val{:rfd},M1,M2})
function _mfd2ss(mfd::MatrixFractionDescription{Val{:mimo},S,Val{:rfd},M1,M2}) where {S,M1,M2}
Den, Num = colred(mfd.D, mfd.N)
kden, Phc = high_col_deg_matrix(Den)
knum = col_degree(Num)
Expand Down Expand Up @@ -82,7 +82,7 @@ function _mfd2ss{S,M1,M2}(mfd::MatrixFractionDescription{Val{:mimo},S,Val{:rfd},
return A, B, C, D
end

function _mfd2ss{S,M1,M2}(mfd::MatrixFractionDescription{Val{:mimo},S,Val{:lfd},M1,M2})
function _mfd2ss(mfd::MatrixFractionDescription{Val{:mimo},S,Val{:lfd},M1,M2}) where {S,M1,M2}
Den, Num = rowred(mfd.D,mfd.N)
kden, Phr = high_row_deg_matrix(Den)
knum = row_degree(Num)
Expand Down
12 changes: 6 additions & 6 deletions src/conversions/ss2mfd.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Generates a right MatrixFractionDescription whose transfer function coincides with that
# of an observable state-space model.
function _ss2rfd{T,S}(sys::StateSpace{Val{T},Val{S}}, var::Symbol)
function _ss2rfd(sys::StateSpace{Val{T},Val{S}}, var::Symbol) where {T,S}
n = numstates(sys)
nu = numinputs(sys)
ny = numoutputs(sys)

# Construct system matrix (Rosenbrock, 1970)
Dₗ = PolyMatrix(vcat(sys.A, -eye(sys.A)), (n,n), Val{_pmvaltype(sys)})
Dₗ = PolyMatrix(vcat(sys.A, -I(sys.A)), (n,n), Val{_pmvaltype(sys)})
Nₗ = PolyMatrix(sys.B, (n,nu), Val{_pmvaltype(sys)})

# Write (sI-A)^{-1} B as a left MatrixFractionDescription and convert to right MatrixFractionDescription
Expand All @@ -33,13 +33,13 @@ rfd(sys::StateSpace{Val{:mimo},Val{:cont}}) =
rfd(sys::StateSpace{Val{:mimo},Val{:disc}}) =
rfd(_ss2rfd(sys,:z)...,samplingtime(sys))

function _ss2lfd{T,S}(sys::StateSpace{Val{T},Val{S}}, var::Symbol)
function _ss2lfd(sys::StateSpace{Val{T},Val{S}}, var::Symbol) where {T,S}
n = numstates(sys)
nu = numinputs(sys)
ny = numoutputs(sys)

# Construct system matrix (Rosenbrock, 1970)
Dᵣ = PolyMatrix(vcat(-sys.A, eye(sys.A)), (n,n), Val{_pmvaltype(sys)})
Dᵣ = PolyMatrix(vcat(-sys.A, I(sys.A)), (n,n), Val{_pmvaltype(sys)})
Nᵣ = PolyMatrix(sys.C, (ny,n), Val{_pmvaltype(sys)})
# Write C(sI-A)^{-1} as a right MatrixFractionDescription and convert to left MatrixFractionDescription
R,U = rtriang(vcat(-Dᵣ, Nᵣ))
Expand All @@ -64,5 +64,5 @@ lfd(sys::StateSpace{Val{:mimo},Val{:cont}}) =
lfd(sys::StateSpace{Val{:mimo},Val{:disc}}) =
lfd(_ss2lfd(sys,:z)...,samplingtime(sys))

_pmvaltype{T}(s::LtiSystem{Val{T},Val{:cont}}) = :s
_pmvaltype{T}(s::LtiSystem{Val{T},Val{:disc}}) = :z
_pmvaltype(s::LtiSystem{Val{T},Val{:cont}}) where {T} = :s
_pmvaltype(s::LtiSystem{Val{T},Val{:disc}}) where {T} = :z
32 changes: 16 additions & 16 deletions src/conversions/tf2mfd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,47 @@

# s = R(s)*inv(D(s)) where D(s) is diagonal with the product of all denominators
# of column i in D[i,i]
# R[i,j] is num(s[i,j]) times all denominators in den(s[:,j]) except den(s[i,j])
function _tf2rfd(s::LTISystems.TransferFunction)
# R[i,j] is num(s[i,j]) times all denominators in denominator(s[:,j]) except denominator(s[i,j])
function _tf2rfd(s::TransferFunction)
mat = s.mat
n,m = size(mat)
dp = fill(zero(den(mat[1])), m)
R = map(num, mat)
map(num,s.mat)
dp = fill(zero(denominator(mat[1])), m)
R = map(numerator, mat)
map(numerator,s.mat)
for i in 1:m
dp[i] = Base.reduce(*, one(den(s.mat[1,i])), map(den,s.mat[:,i]))
dp[i] = Base.reduce(*, map(denominator,s.mat[:,i]), init=one(denominator(s.mat[1,i])))
for j in 1:n
for k in 1:n
k == j && continue
R[j,i] *= den(s.mat[k,i])
R[j,i] *= denominator(s.mat[k,i])
end
end
end
R = PolyMatrix(R)
D = PolyMatrix(diagm(dp))
D = PolyMatrix(Matrix{eltype(dp)}(Diagonal(dp)))
R, D
end

# s = inv(D(s))*R(s) where D(s) is diagonal with the product of all denominators
# of column i in D[i,i]
# R[i,j] is num(s[i,j]) times all denominators in den(s[j,:]) except den(s[i,j])
function _tf2lfd(s::LTISystems.TransferFunction)
# R[i,j] is num(s[i,j]) times all denominators in denominator(s[j,:]) except denominator(s[i,j])
function _tf2lfd(s::TransferFunction)
mat = s.mat
n,m = size(mat)
dp = fill(zero(den(mat[1])), n)
R = map(num, mat)
map(num,s.mat)
dp = fill(zero(denominator(mat[1])), n)
R = map(numerator, mat)
map(numerator,s.mat)
for i in 1:n
dp[i] = Base.reduce(*, one(den(s.mat[i,1])), map(den,s.mat[i,:]))
dp[i] = Base.reduce(*, map(denominator,s.mat[i,:]), init=one(denominator(s.mat[i,1])))
for j in 1:m
for k in 1:m
k == j && continue
R[i,j] *= den(s.mat[i,k])
R[i,j] *= denominator(s.mat[i,k])
end
end
end
R = PolyMatrix(R)
D = PolyMatrix(diagm(dp))
D = PolyMatrix(Matrix{eltype(dp)}(Diagonal(dp)))
R, D
end

Expand Down
4 changes: 2 additions & 2 deletions src/conversions/tf2ss.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ ss(s::TransferFunction{Val{:siso},Val{:disc}}) = minreal(ss(_tf2ss(s)..., s.Ts))
# TODO num(s) instead of num(s.mat[1])
# controllable canonical form
function _tf2ss(s::TransferFunction{Val{:siso}})
nump = RationalFunctions.num(s.mat[1])
denp = RationalFunctions.den(s.mat[1])
nump = RationalFunctions.numerator(s.mat[1])
denp = RationalFunctions.denominator(s.mat[1])
nump /= denp[end]
denp /= denp[end]
m = degree(nump)
Expand Down
10 changes: 5 additions & 5 deletions src/methods/feedback.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ Continuous time rational transfer function model
x^2 + 4x + 7
```
"""
function feedback{T1<:LtiSystem, T2<:LtiSystem}(s1::T1, s2::T2)
function feedback(s1::T1, s2::T2) where {T1<:LtiSystem, T2<:LtiSystem}
/(s1, parallel(one(s1), series(s1,s2)))
end

feedback{T1<:LtiSystem, T2<:Real}(s1::T1, n::T2) =
feedback(s1::T1, n::T2) where {T1<:LtiSystem, T2<:Real} =
/(s1, parallel(one(s1), series(s1, n)))
feedback{T1<:LtiSystem, T2<:Real}(n::T2, s1::T1) =
feedback(n::T2, s1::T1) where {T1<:LtiSystem, T2<:Real} =
/(n, parallel(one(s1), series(n, s1)))

feedback{T1<:LtiSystem, T2<:Real}(s1::T1, n::Matrix{T2}) =
feedback(s1::T1, n::Matrix{T2}) where {T1<:LtiSystem, T2<:Real} =
/(s1, parallel(one(s1), series(s1, n)))
feedback{T1<:LtiSystem, T2<:Real}(n::Matrix{T2}, s1::T1) =
feedback(n::Matrix{T2}, s1::T1) where {T1<:LtiSystem, T2<:Real} =
/(n, parallel(one(s1), series(n, s1)))

# # TODO: Implement the specific cases for speedup purposes. Take into account the
Expand Down
10 changes: 5 additions & 5 deletions src/methods/freqresp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ systems.

**See also:** `bode`, `nyquist`, `samplingtime`.
"""
freqresp{S}(sys::LtiSystem{Val{S},Val{:cont}}, x::Real) =
freqresp(sys::LtiSystem{Val{S},Val{:cont}}, x::Real) where {S} =
sys(1im*x)
freqresp{S,M<:Real}(sys::LtiSystem{Val{S},Val{:cont}}, X::AbstractArray{M}) =
freqresp(sys::LtiSystem{Val{S},Val{:cont}}, X::AbstractArray{M}) where {S,M<:Real} =
sys(1im*X)
freqresp{S}(sys::LtiSystem{Val{S},Val{:disc}}, x::Real) =
freqresp(sys::LtiSystem{Val{S},Val{:disc}}, x::Real) where {S} =
sys(exp(1im*samplingtime(sys)*x))
freqresp{S,M<:Real}(sys::LtiSystem{Val{S},Val{:disc}}, X::AbstractArray{M}) =
freqresp(sys::LtiSystem{Val{S},Val{:disc}}, X::AbstractArray{M}) where {S,M<:Real} =
sys(exp(1im*samplingtime(sys)*X))

# Implements algorithm found in:
Expand All @@ -45,7 +45,7 @@ function _eval(sys::StateSpace, x::Number)
convert(AbstractMatrix{Complex128}, sys.D + sys.C*(R\sys.B))
end

function _eval{M<:Number}(sys::StateSpace, X::AbstractArray{M})
function _eval(sys::StateSpace, X::AbstractArray{M}) where {M<:Number}
resp = Array{Complex128}(size(sys)..., size(X)...)
for idx in CartesianRange(indices(X))
resp[:, :, idx] = sys.D + sys.C*((X[idx]*I - sys.A)\sys.B)
Expand Down
6 changes: 3 additions & 3 deletions src/methods/minreal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ julia> Dm
0.0
```
"""
function minreal{M1<:AbstractMatrix,M2<:AbstractMatrix,M3<:AbstractMatrix,
M4<:AbstractMatrix}(A::M1, B::M2, C::M3, D::M4, tol::Float64 = zero(Float64))
function minreal(A::M1, B::M2, C::M3, D::M4, tol::Float64 = zero(Float64)) where {
M1<:AbstractMatrix,M2<:AbstractMatrix,M3<:AbstractMatrix,M4<:AbstractMatrix}
@assert size(A,1) == size(A,2) "minreal: A must be square"
@assert size(A,1) == size(B,1) "minreal: A and B must have the same row size"
@assert size(A,1) == size(C,2) "minreal: A and C must have the same column size"
Expand All @@ -72,7 +72,7 @@ function minreal{M1<:AbstractMatrix,M2<:AbstractMatrix,M3<:AbstractMatrix,
Tc, c = rosenbrock(A, B, tol)
ATemp = (Tc'*A*Tc)[n-c+1:n,n-c+1:n]
CTemp = (C*Tc)[:,n-c+1:n]
To, o = rosenbrock(ATemp.', CTemp.', tol)
To, o = rosenbrock(transpose(ATemp), transpose(CTemp), tol)

T = view(Tc, :, n-c+1:n)*To

Expand Down
10 changes: 5 additions & 5 deletions src/methods/parallel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Continuous time rational transfer function model
x + 2
```
"""
parallel{T1<:LtiSystem, T2<:LtiSystem}(s1::T1, s2::T2) = +(s1, s2)
parallel(s1::T1, s2::T2) where {T1<:LtiSystem, T2<:LtiSystem} = +(s1, s2)

parallel{T1<:LtiSystem, T2<:Real}(s1::T1, n::T2) = +(s1, n)
parallel{T1<:LtiSystem, T2<:Real}(n::T2, s1::T1) = +(n, s1)
parallel(s1::T1, n::T2) where {T1<:LtiSystem, T2<:Real} = +(s1, n)
parallel(n::T2, s1::T1) where {T1<:LtiSystem, T2<:Real} = +(n, s1)

parallel{T1<:LtiSystem, M2<:AbstractMatrix}(s1::T1, n::M2) = +(s1, n)
parallel{T1<:LtiSystem, M2<:AbstractMatrix}(n::M2, s1::T1) = +(n, s1)
parallel(s1::T1, n::M2) where {T1<:LtiSystem, M2<:AbstractMatrix} = +(s1, n)
parallel(n::M2, s1::T1) where {T1<:LtiSystem, M2<:AbstractMatrix} = +(n, s1)
14 changes: 7 additions & 7 deletions src/methods/pzmap.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
immutable PZData{T}
p::Vector{Complex128}
z::Vector{Complex128}
struct PZData{T}
p::Vector{Complex{Float64}}
z::Vector{Complex{Float64}}

function (::Type{PZData{Val{U}}}){T<:Number,S<:Number,U}(p::AbstractVector{T},
z::AbstractVector{S})
new{Val{U}}(convert(Vector{Complex128}, p), convert(Vector{Complex128}, z))
function (::Type{PZData{Val{U}}})(p::AbstractVector{T},
z::AbstractVector{S}) where {T<:Number,S<:Number,U}
new{Val{U}}(convert(Vector{Complex{Float64}}, p), convert(Vector{Complex{Float64}}, z))
end
end

Expand Down Expand Up @@ -37,7 +37,7 @@ However, plotting recipes are defined for `pzdata`, which allows for

**See also:** `poles`, `zeros`, `tzeros`.
"""
pzmap{T,S}(sys::LtiSystem{Val{T},Val{S}}) = PZData{Val{S}}(_pzmap(sys)...)
pzmap(sys::LtiSystem{Val{T},Val{S}}) where {T,S} = PZData{Val{S}}(_pzmap(sys)...)

@recipe function f{T}(pzdata::PZData{Val{T}}; stability = true)
@assert isa(stability, Bool) "plot(pzdata): `stability` must be a `Bool`"
Expand Down
Loading