From fd11780d5b5e30f570f6231416162790a8efa97e Mon Sep 17 00:00:00 2001 From: DSVarga Date: Sat, 18 Jan 2025 16:56:08 +0100 Subject: [PATCH] New show function and some new system constructors for discrete-time gains. --- Project.toml | 4 +- ReleaseNotes.md | 4 + docs/make.jl | 4 - ext/ps_Fourier.jl | 7 + src/ps.jl | 79 ++++- src/types/PeriodicStateSpace.jl | 592 +++----------------------------- test/test_psutils.jl | 13 +- 7 files changed, 139 insertions(+), 564 deletions(-) diff --git a/Project.toml b/Project.toml index e767ada..bc7fd52 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,10 @@ name = "PeriodicSystems" uuid = "5decd0d0-8a5f-11ec-2edd-87b25cbcd17e" authors = ["Andreas Varga "] -version = "1.0.0" +version = "1.0.1" [deps] DescriptorSystems = "a81e2ce2-54d1-11eb-2c75-db236b00f339" -FastLapackInterface = "29a986be-02c6-4525-aec4-84b980013641" IRKGaussLegendre = "58bc7355-f626-4c51-96f2-1f8a038f95a2" Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -37,7 +36,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] ApproxFun = "0.13" DescriptorSystems = "1.4" -FastLapackInterface = "2.0" IRKGaussLegendre = "0.2" Interpolations = "0.15" LinearAlgebra = "1" diff --git a/ReleaseNotes.md b/ReleaseNotes.md index c29f2cb..34d3a3f 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,9 @@ # Release Notes +## Version 1.0.1 + +Implement some new system constructors via the function `ps` for discrete time-varying gains and a new unique version of `show` for periodic systems based on the new `show` functions of `PeriodicMatrices`. + ## Version 1.0.0 Breaking release, which concludes the integration of `PeriodicMatrices` and `PeriodicMatrixEquations` packages as separate supporting packages. This version also achieves the splitting of the `ApproxFun` package as an optional package. diff --git a/docs/make.jl b/docs/make.jl index a720bd6..8988cdc 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,10 +2,6 @@ using Documenter, PeriodicSystems using DocumenterInterLinks DocMeta.setdocmeta!(PeriodicSystems, :DocTestSetup, :(using PeriodicSystems); recursive=true) -# links = InterLinks( -# "PeriodicMatrixEquations" => ("https://andreasvarga.github.io/PeriodicMatrixEquations.jl/dev/", -# "https://andreasvarga.github.io/PeriodicMatrixEquations.jl/dev/objects.inv"), -# ); links = InterLinks( "PeriodicMatrixEquations" => "https://andreasvarga.github.io/PeriodicMatrixEquations.jl/dev/", ); diff --git a/ext/ps_Fourier.jl b/ext/ps_Fourier.jl index 780a030..f7cc519 100644 --- a/ext/ps_Fourier.jl +++ b/ext/ps_Fourier.jl @@ -4,3 +4,10 @@ # Ts == 0 || error("only continuous periodic matrix types allowed") # ps(PMT(sys.A,period), PMT(sys.B,period), PMT(sys.C,period), PMT(sys.D,period)) # end +# function ps(D::PM) where {PM <: FourierFunctionMatrix} +# error("This function is not available for FourierFunctionMatrix type") +# # p, m = size(D,1), size(D,2) +# # ps(FourierFunctionMatrix(zeros(T,0,0),D.period), +# # FourierFunctionMatrix(zeros(T,0,m),D.period), +# # FourierFunctionMatrix(zeros(T,p,0),D.period), D) +# end diff --git a/src/ps.jl b/src/ps.jl index 157295a..6d6a828 100644 --- a/src/ps.jl +++ b/src/ps.jl @@ -113,18 +113,83 @@ ps(A::APMorVM, B::APMorVM, C::APMorVM, period::Real) = ps(PMT::Type, A::APMorVM, B::APMorVM, C::APMorVM, period::Real) = ps(PMT, set_period(A,period), set_period(B,period), set_period(C,period)) -function ps(D::PM) where {PM <: AbstractPeriodicArray} - p, m = size(D,1), size(D,2) - PMT = typeof(D).name.wrapper - ps(convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(0,0),D.period)), - convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(0,m),D.period)), - convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(p,0),D.period)), D) +#function ps(D::PM) where {PM <: AbstractPeriodicArray{:c,T}} where {T} +function ps(D::PM) where {PM <: Union{PeriodicFunctionMatrix, PeriodicSymbolicMatrix, HarmonicArray, + PeriodicTimeSeriesMatrix, PeriodicSwitchingMatrix}} + p, m = size(D,1), size(D,2) + T = eltype(D) + PMT = typeof(D).name.wrapper + ps(convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,0,0),D.period)), + convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,0,m),D.period)), + convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,p,0),D.period)), D) +end +function ps(D::PM) where {PM <: FourierFunctionMatrix} + error("This function is not available for FourierFunctionMatrix type") + # p, m = size(D,1), size(D,2) + # ps(FourierFunctionMatrix(zeros(T,0,0),D.period), + # FourierFunctionMatrix(zeros(T,0,m),D.period), + # FourierFunctionMatrix(zeros(T,p,0),D.period), D) +end + +# function ps(D::PM) where {PM <: AbstractPeriodicArray{:d,T}} where {T} +# p, m = size(D,1), size(D,2) +# (maximum(p) == minimum(p) && maximum(m) == minimum(m)) || +# throw(DimensionMismatch("only constant dimensions allowed for a feedthrough matrix")) +# PMT = typeof(D).name.wrapper +# @show T +# # ps(convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,0,0),D.period)), +# # convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,0,m),D.period)), +# # convert(PMT,PeriodicMatrices.PeriodicFunctionMatrix(zeros(T,p,0),D.period)), D) +# if PMT == PeriodicMatrix || PMT == PeriodicArray +# ps(PMT(zeros(T,0,0),D.period), +# PMT(zeros(T,0,m[1]),D.period), +# PMT(zeros(T,p[1],0),D.period), D) +# else +# ns = [length(D)] +# ps(PMT(zeros(T,0,0),D.period), +# PMT(zeros(T,0,m[1]),D.period), +# PMT(zeros(T,p[1],0),D.period), D) +# end +# end +function ps(D::PM) where {PM <: PeriodicMatrix{:d,T}} where {T} + p, m = size(D,1), size(D,2) + (maximum(p) == minimum(p) && maximum(m) == minimum(m)) || + throw(DimensionMismatch("only constant dimensions allowed for a feedthrough matrix")) + PMT = typeof(D).name.wrapper + ps(PMT(PeriodicMatrices.pmzeros(T,[0],[0]),D.period;nperiod = D.dperiod), + PMT(PeriodicMatrices.pmzeros(T,[0],[m[1]]),D.period;nperiod = D.dperiod), + PMT(PeriodicMatrices.pmzeros(T,[p[1]],[0]),D.period;nperiod = D.dperiod), D) +end +function ps(D::PM) where {PM <: SwitchingPeriodicMatrix{:d,T}} where {T} + p, m = size(D,1), size(D,2) + (maximum(p) == minimum(p) && maximum(m) == minimum(m)) || + throw(DimensionMismatch("only constant dimensions allowed for a feedthrough matrix")) + PMT = typeof(D).name.wrapper + ns = [1] + ps(PMT(PeriodicMatrices.pmzeros(T,[0],[0]),ns,D.period;nperiod = D.dperiod), + PMT(PeriodicMatrices.pmzeros(T,[0],[m[1]]),ns,D.period;nperiod = D.dperiod), + PMT(PeriodicMatrices.pmzeros(T,[p[1]],[0]),ns,D.period;nperiod = D.dperiod), D) +end +function ps(D::PM) where {PM <: PeriodicArray{:d,T}} where {T} + p, m = size(D,1), size(D,2) + PMT = typeof(D).name.wrapper + ps(PMT(zeros(T,0,0),D.period;nperiod = D.dperiod), + PMT(zeros(T,0,m[1]),D.period;nperiod = D.dperiod), + PMT(zeros(T,p[1],0),D.period;nperiod = D.dperiod), D) +end +function ps(D::PM) where {PM <: SwitchingPeriodicArray{:d,T}} where {T} + p, m = size(D,1), size(D,2) + PMT = typeof(D).name.wrapper + ns = [1] + ps(PMT(zeros(T,0,0,1),ns,D.period;nperiod = D.dperiod), + PMT(zeros(T,0,m[1],1),ns,D.period;nperiod = D.dperiod), + PMT(zeros(T,p[1],0,1),ns,D.period;nperiod = D.dperiod), D) end function ps(sys::DST, period::Real; ns::Int = 1) where {DST <: DescriptorStateSpace} sys.E == I || error("only standard state-spece models supported") function ps1(A::T) where {T <: PeriodicFunctionMatrix} - return typeof(A) + return typeof(A) end Ts = sys.Ts if Ts == 0 diff --git a/src/types/PeriodicStateSpace.jl b/src/types/PeriodicStateSpace.jl index 3d1f7c0..e16546a 100644 --- a/src/types/PeriodicStateSpace.jl +++ b/src/types/PeriodicStateSpace.jl @@ -1,43 +1,3 @@ -# Base.promote_rule(PeriodicFunctionMatrix, PeriodicSymbolicMatrix) = PeriodicFunctionMatrix{:c,T} -# Base.promote_rule(PeriodicFunctionMatrix, HarmonicArray) = PeriodicFunctionMatrix -# function promote_period(PM1,args...; ndigits = 4) -# nlim = 2^ndigits -# if typeof(PM1) <: AbstractVecOrMat -# period = nothing -# isconst = true -# else -# period = PM1.period -# isconst = isconstant(PM1) -# end -# for a in args -# typeof(a) <: AbstractVecOrMat && continue -# if isconstant(a) -# if isconst -# if isnothing(period) -# period = a.period -# else -# #period = max(period,a.period) -# peri = a.period -# r = rationalize(period/peri) -# num = numerator(r) -# den = denominator(r) -# num <= nlim || den <= nlim || error("incommensurate periods") -# period = period*den -# end -# end -# continue -# end -# isconst && (isconst = false; period = a.period; continue) -# peri = a.period -# r = rationalize(period/peri) -# num = numerator(r) -# den = denominator(r) -# num <= nlim || den <= nlim || error("incommensurate periods") -# period = period*den -# end -# return period -# end - function promote_Ts(PM1,args...) Ts = PM1.Ts isconst = PeriodicMatrices.isconstant(PM1) @@ -139,8 +99,9 @@ The different periods must be commensurate (i.e., their ratios must be rational numerators and denominators up to at most 4 decimal digits). All periodic matrix objects must have the same type `PM`, where `PM` stays for one of the supported periodic matrix types, i.e., -`PeriodicMatrix`, `PeriodicArray`, `PeriodicFunctionMatrix`, `PeriodicSymbolicMatrix`, -`HarmonicArray`, `FourierFunctionMatrix` or `PeriodicTimeSeriesMatrix`. +`PeriodicMatrix`, `SwitchingPeriodicMatrix`, `PeriodicArray`, `SwitchingPeriodicArray`, +`PeriodicFunctionMatrix`, `PeriodicSymbolicMatrix`, +`HarmonicArray`, `FourierFunctionMatrix`, `PeriodicTimeSeriesMatrix` or `PeriodicSwitchingMatrix`. """ function PeriodicStateSpace(A::PFM1, B::PFM2, C::PFM3, D::PFM4) where {PFM1 <: PeriodicFunctionMatrix, PFM2 <: PeriodicFunctionMatrix, PFM3 <: PeriodicFunctionMatrix, PFM4 <: PeriodicFunctionMatrix} period = ps_validation(A, B, C, D) @@ -151,16 +112,6 @@ function PeriodicStateSpace(A::PFM1, B::PFM2, C::PFM3, D::PFM4) where {PFM1 <: P (period == D.period && T == eltype(D)) ? D : PeriodicFunctionMatrix{:c,T}(D,period), Float64(period)) end -# function PeriodicStateSpace(A::FFM1, B::FFM2, C::FFM3, D::FFM4) where {FFM1 <: FourierFunctionMatrix, FFM2 <: FourierFunctionMatrix, FFM3 <: FourierFunctionMatrix, FFM4 <: FourierFunctionMatrix} -# period = ps_validation(A, B, C, D) -# T = promote_type(eltype(A),eltype(B),eltype(C),eltype(D)) -# PeriodicStateSpace{FourierFunctionMatrix{:c,T}}((period == A.period && T == eltype(A)) ? A : FourierFunctionMatrix{:c,T}(A,period), -# (period == B.period && T == eltype(B)) ? B : FourierFunctionMatrix{:c,T}(B,period), -# (period == C.period && T == eltype(C)) ? C : FourierFunctionMatrix{:c,T}(C,period), -# (period == D.period && T == eltype(D)) ? D : FourierFunctionMatrix{:c,T}(D,period), -# Float64(period)) -# end - function PeriodicStateSpace(A::PSM, B::PSM, C::PSM, D::PSM) where {PSM <: PeriodicSymbolicMatrix} period = ps_validation(A, B, C, D) PeriodicStateSpace(period == A.period ? A : set_period(A,period), @@ -396,510 +347,59 @@ end # display sys Base.print(io::IO, sys::PeriodicStateSpace) = show(io, sys) -Base.show(io::IO, sys::PeriodicStateSpace{PM}) where - {PM <: Union{PeriodicMatrix,PeriodicArray,PeriodicTimeSeriesMatrix,PeriodicSymbolicMatrix,PeriodicFunctionMatrix,HarmonicArray}} = +Base.show(io::IO, sys::PeriodicStateSpace{PM}) where {PM <: AbstractPeriodicArray} = show(io, MIME("text/plain"), sys) -# function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:FourierFunctionMatrix}) -# summary(io, sys); println(io) -# n = size(sys.A,1) -# p, m = size(sys.D) -# T = eltype(sys) -# if n > 0 -# nperiod = sys.A.nperiod -# println(io, "\nState matrix A::$T($n×$n): subperiod: $(sys.A.period/nperiod) #subperiods: $nperiod ") -# PeriodicMatrices.isconstant(sys.A) ? show(io, mime, sys.A.M(0)) : show(io, mime, sys.A.M) -# if m > 0 -# nperiod = sys.B.nperiod -# println(io, "\n\nInput matrix B::$T($n×$m): $(sys.B.period/nperiod) #subperiods: $nperiod ") -# PeriodicMatrices.isconstant(sys.B) ? show(io, mime, sys.B.M(0)) : show(io, mime, sys.B.M) -# else -# println(io, "\n\nEmpty input matrix B.") -# end - -# if p > 0 -# nperiod = sys.C.nperiod -# println(io, "\n\nOutput matrix C::$T($p×$n): $(sys.C.period/nperiod) #subperiods: $nperiod ") -# PeriodicMatrices.isconstant(sys.C) ? show(io, mime, sys.C.M(0)) : show(io, mime, sys.C.M) -# else -# println(io, "\n\nEmpty output matrix C.") -# end -# if m > 0 && p > 0 -# nperiod = sys.D.nperiod -# println(io, "\n\nFeedthrough matrix D::$T($p×$m): $(sys.D.period/nperiod) #subperiods: $nperiod ") -# PeriodicMatrices.isconstant(sys.D) ? show(io, mime, sys.D.M(0)) : show(io, mime, sys.D.M) -# else -# println(io, "\n\nEmpty feedthrough matrix D.") -# end -# println(io, "\n\nContinuous-time periodic state-space model.") -# elseif m > 0 && p > 0 -# nperiod = sys.D.nperiod -# println(io, "\nFeedthrough matrix D::$T($p×$m): $(sys.D.period/nperiod) #subperiods: $nperiod ") -# PeriodicMatrices.isconstant(sys.D) ? show(io, mime, sys.D.M(0)) : show(io, mime, sys.D.M) -# println(io, "\n\nTime-varying gain.") -# else -# println(io, "\nEmpty state-space model.") -# end -# end - -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:HarmonicArray}) - summary(io, sys); println(io) - n = sys.nx - p, m = size(sys) - period = sys.period - if n > 0 - nharmonics, nperiod = size(sys.A.values,3)-1, sys.A.nperiod - subperiod = period/nperiod - println(io, "\nState matrix A: subperiod: $subperiod #subperiods: $nperiod #harmonics: $nharmonics") - ts = 2*pi*nperiod/period - if nharmonics >= 0 - println("Constant term") - display(mime, real(sys.A.values[:,:,1])) - end - for i in [1:min(4,nharmonics); nharmonics-2:nharmonics] - i <= 0 && break - println("cos($(i*ts)t) factor") - display(mime, real(sys.A.values[:,:,i+1])) - println("sin($(i*ts)t) factor") - display(mime, imag(sys.A.values[:,:,i+1])) - i == 4 && nharmonics > 4 && println(" ⋮") - end - if m > 0 - nharmonics, nperiod = size(sys.B.values,3)-1, sys.B.nperiod - subperiod = period/nperiod - println(io, "\nInput matrix B: subperiod: $subperiod #subperiods: $nperiod #harmonics: $nharmonics") - ts = 2*pi*nperiod/period - if nharmonics >= 0 - println("Constant term") - display(mime, real(sys.B.values[:,:,1])) - end - for i in [1:min(4,nharmonics); nharmonics-2:nharmonics] - i <= 0 && break - println("cos($(i*ts)t) factor") - display(mime, real(sys.B.values[:,:,i+1])) - println("sin($(i*ts)t) factor") - display(mime, imag(sys.B.values[:,:,i+1])) - i == 4 && nharmonics > 4 && println(" ⋮") - end - else +function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{PM}) where + {PM <: AbstractPeriodicArray} + # {PM <: Union{PeriodicFunctionMatrix,HarmonicArray,PeriodicSymbolicMatrix,PeriodicTimeSeriesMatrix,PeriodicSwitchingMatrix, + # PeriodicMatrix}} + summary(io, sys); println(io) + n = maximum(sys.nx) + p, m = size(sys) + if n > 0 + println(io, "\nState matrix A") + display(sys.A) + if m > 0 + println(io, "\nInput matrix B") + display(sys.B) + else println(io, "\n\nEmpty input matrix B.") - end - if p > 0 - nharmonics, nperiod = size(sys.C.values,3)-1, sys.C.nperiod - subperiod = period/nperiod - println(io, "\nOutput matrix C: subperiod: $subperiod #subperiods: $nperiod #harmonics: $nharmonics") - ts = 2*pi*nperiod/period - if nharmonics >= 0 - println("Constant term") - display(mime, real(sys.C.values[:,:,1])) - end - for i in [1:min(4,nharmonics); nharmonics-2:nharmonics] - i <= 0 && break - println("cos($(i*ts)t) factor") - display(mime, real(sys.C.values[:,:,i+1])) - println("sin($(i*ts)t) factor") - display(mime, imag(sys.C.values[:,:,i+1])) - i == 4 && nharmonics > 4 && println(" ⋮") - end + end + if p > 0 + println(io, "\nOutput matrix C") + display(sys.C) else println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - nharmonics, nperiod = size(sys.D.values,3)-1, sys.D.nperiod - subperiod = period/nperiod - println(io, "\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod #harmonics: $nharmonics") - ts = 2*pi*nperiod/period - if nharmonics >= 0 - println("Constant term") - display(mime, real(sys.D.values[:,:,1])) - end - for i in [1:min(4,nharmonics); nharmonics-2:nharmonics] - i <= 0 && break - println("cos($(i*ts)t) factor") - display(mime, real(sys.D.values[:,:,i+1])) - println("sin($(i*ts)t) factor") - display(mime, imag(sys.C.values[:,:,i+1])) - i == 4 && nharmonics > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Periodic continuous-time state-space model.") - elseif m > 0 && p > 0 - nharmonics, nperiod = size(sys.D.values,3)-1, sys.D.nperiod - subperiod = period/nperiod - println(io, "\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod #harmonics: $nharmonics") - ts = 2*pi*nperiod/period - if nharmonics >= 0 - println("Constant term") - display(mime, real(sys.D.values[:,:,1])) - end - for i in [1:min(4,nharmonics); nharmonics-2:nharmonics] - i <= 0 && break - println("cos($(i*ts)t) factor") - display(mime, real(sys.D.values[:,:,i+1])) - println("sin($(i*ts)t) factor") - display(mime, imag(sys.D.values[:,:,i+1])) - i == 4 && nharmonics > 4 && println("⋮") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") + end + if m > 0 && p > 0 + println(io, "\nFeedthrough matrix D") + display(sys.D) + else + println(io, "\nEmpty feedthrough matrix D.") + end + println(io, "\nSystem period: $(sys.period) second(s).") + if iscontinuous(sys) + println(io, "Periodic continuous-time state-space model.") + else + println(io, "Periodic discrete-time state-space model.") + end + elseif m > 0 && p > 0 + println(io, "\nFeedthrough matrix D") + display(sys.D) + println(io, "\nSystem period: $(sys.period) second(s).") println(io, "Time-varying gains.") - else - println(io, "\nEmpty Periodic continuous-time state-space model.") - end -end - -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:PeriodicFunctionMatrix}) - summary(io, sys); println(io) - n = size(sys.A,1) - p, m = size(sys.D) - T = eltype(sys) - if n > 0 - nperiod = sys.A.nperiod - println(io, "\nState matrix A::$T($n×$n): subperiod: $(sys.A.period/nperiod) #subperiods: $nperiod ") - PeriodicMatrices.isconstant(sys.A) ? show(io, mime, sys.A.f(0)) : show(io, mime, sys.A.f) - if m > 0 - nperiod = sys.B.nperiod - println(io, "\n\nInput matrix B::$T($n×$m): $(sys.B.period/nperiod) #subperiods: $nperiod ") - PeriodicMatrices.isconstant(sys.B) ? show(io, mime, sys.B.f(0)) : show(io, mime, sys.B.f) - else - println(io, "\n\nEmpty input matrix B.") - end - - if p > 0 - nperiod = sys.C.nperiod - println(io, "\n\nOutput matrix C::$T($p×$n): $(sys.C.period/nperiod) #subperiods: $nperiod ") - PeriodicMatrices.isconstant(sys.C) ? show(io, mime, sys.C.f(0)) : show(io, mime, sys.C.f) - else - println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - nperiod = sys.D.nperiod - println(io, "\n\nFeedthrough matrix D::$T($p×$m): $(sys.D.period/nperiod) #subperiods: $nperiod ") - PeriodicMatrices.isconstant(sys.D) ? show(io, mime, sys.D.f(0)) : show(io, mime, sys.D.f) - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Continuous-time periodic state-space model.") - elseif m > 0 && p > 0 - nperiod = sys.D.nperiod - println(io, "\nFeedthrough matrix D::$T($p×$m): $(sys.D.period/nperiod) #subperiods: $nperiod ") - PeriodicMatrices.isconstant(sys.D) ? show(io, mime, sys.D.f(0)) : show(io, mime, sys.D.f) - println(io, "Period: $(sys.period) second(s).") - println(io, "\n\nTime-varying gain.") - else - println(io, "\nEmpty state-space model.") - end + else + if iscontinuous(sys) + println(io, "Empty periodic continuous-time state-space model.") + else + println(io, "Empty periodic discrete-time state-space model.") + end + end end -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:PeriodicSymbolicMatrix}) - summary(io, sys); println(io) - n = size(sys.A,1) - p, m = size(sys.D) - if n > 0 - nperiod = sys.A.nperiod - println(io, "\nState matrix A: subperiod: $(sys.A.period/nperiod) #subperiods: $nperiod ") - show(io, mime, sys.A.F) - if m > 0 - nperiod = sys.B.nperiod - println(io, "\n\nInput matrix B: $(sys.B.period/nperiod) #subperiods: $nperiod ") - show(io, mime, sys.B.F) - else - println(io, "\n\nEmpty input matrix B.") - end - - if p > 0 - nperiod = sys.C.nperiod - println(io, "\n\nOutput matrix C: $(sys.C.period/nperiod) #subperiods: $nperiod ") - show(io, mime, sys.C.F) - else - println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - nperiod = sys.D.nperiod - println(io, "\n\nFeedthrough matrix D: $(sys.D.period/nperiod) #subperiods: $nperiod ") - show(io, mime, sys.D.F) - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Continuous-time periodic state-space model.") - elseif m > 0 && p > 0 - nperiod = sys.D.nperiod - println(io, "\nFeedthrough matrix D: $(sys.D.period/nperiod) #subperiods: $nperiod ") - show(io, mime, sys.D.F) - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Time-varying gain.") - else - println(io, "\nEmpty state-space model.") - end -end -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:PeriodicTimeSeriesMatrix}) - summary(io, sys); println(io) - n = sys.nx - N = length(sys.A) - p, m = size(sys) - period = sys.period - if n > 0 - dperiod, nperiod = length(sys.A), sys.A.nperiod - subperiod = period/nperiod - Ts = subperiod/dperiod - println(io, "\nState matrix A: subperiod: $subperiod #subperiods: $nperiod ") - if dperiod == 1 - println(io, "time values: t[1:$dperiod] = [$(0*Ts)]") - else - println(io, "time values: t[1:$dperiod] = [$(0*Ts) $(Ts) ... $((dperiod-1)*Ts)]") - end - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $((i-1)*Ts)") - display(mime, sys.A.values[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - if m > 0 - dperiod, nperiod = length(sys.B), sys.B.nperiod - subperiod = period/nperiod - Ts = subperiod/dperiod - println(io, "\n\nInput matrix B: subperiod: $subperiod #subperiods: $nperiod ") - if dperiod == 1 - println(io, "time values: t[1:$dperiod] = [$(0*Ts)]") - else - println(io, "time values: t[1:$dperiod] = [$(0*Ts) $(Ts) ... $((dperiod-1)*Ts)]") - end - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $((i-1)*Ts)") - display(mime, sys.B.values[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty input matrix B.") - end - if p > 0 - dperiod, nperiod = length(sys.C), sys.C.nperiod - subperiod = period/nperiod - Ts = subperiod/dperiod - println(io, "\n\nOutput matrix C: subperiod: $subperiod #subperiods: $nperiod ") - if dperiod == 1 - println(io, "time values: t[1:$dperiod] = [$(0*Ts)]") - else - println(io, "time values: t[1:$dperiod] = [$(0*Ts) $(Ts) ... $((dperiod-1)*Ts)]") - end - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $((i-1)*Ts)") - display(mime, sys.C.values[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - dperiod, nperiod = length(sys.D), sys.D.nperiod - subperiod = period/nperiod - Ts = subperiod/dperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - if dperiod == 1 - println(io, "time values: t[1:$dperiod] = [$(0*Ts)]") - else - println(io, "time values: t[1:$dperiod] = [$(0*Ts) $(Ts) ... $((dperiod-1)*Ts)]") - end - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $((i-1)*Ts)") - display(mime, sys.D.values[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Periodic continuous-time state-space model.") - elseif m > 0 && p > 0 - dperiod, nperiod = length(sys.D), sys.D.nperiod - subperiod = period/nperiod - Ts = subperiod/dperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod] = [$(0*Ts) $(Ts) ... $((dperiod-1)*Ts)]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $((i-1)*Ts)") - display(mime, sys.D.values[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Time-varying gains.") - else - println(io, "\nEmpty Periodic continuous-time state-space model.") - end -end - -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:PeriodicMatrix}) - summary(io, sys); println(io) - n = sys.nx - N = sys.A.dperiod - p, m = size(sys) - period = sys.period - Ts = sys.A.Ts - if any(n .> 0) - dperiod, nperiod = sys.A.dperiod, sys.A.nperiod - subperiod = period/nperiod - println(io, "\nState matrix A: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.A.M[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - if m > 0 - dperiod, nperiod = sys.B.dperiod, sys.B.nperiod - subperiod = period/nperiod - println(io, "\n\nInput matrix B: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.B.M[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty input matrix B.") - end - if p > 0 - dperiod, nperiod = sys.C.dperiod, sys.C.nperiod - subperiod = period/nperiod - println(io, "\n\nOutput matrix C: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.C.M[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - dperiod, nperiod = sys.D.dperiod, sys.D.nperiod - subperiod = period/nperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.D.M[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Sample time: $Ts second(s).") - println(io, "Periodic discrete-time state-space model.") - elseif m > 0 && p > 0 - dperiod, nperiod = sys.D.dperiod, sys.D.nperiod - subperiod = period/nperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.D.M[i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Sample time: $Ts second(s).") - println(io, "Time-varying gains.") - else - println(io, "\nEmpty Periodic discrete-time state-space model.") - end -end -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, sys::PeriodicStateSpace{<:PeriodicArray}) - summary(io, sys); println(io) - n = sys.nx - N = sys.A.dperiod - p, m = size(sys) - period = sys.period - Ts = sys.A.Ts - if any(n .> 0) - dperiod, nperiod = sys.A.dperiod, sys.A.nperiod - subperiod = period/nperiod - println(io, "\nState matrix A: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.A.M[:,:,i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - if m > 0 - dperiod, nperiod = sys.B.dperiod, sys.B.nperiod - subperiod = period/nperiod - println(io, "\n\nInput matrix B: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.B.M[:,:,i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty input matrix B.") - end - if p > 0 - dperiod, nperiod = sys.C.dperiod, sys.C.nperiod - subperiod = period/nperiod - println(io, "\n\nOutput matrix C: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.C.M[:,:,i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty output matrix C.") - end - if m > 0 && p > 0 - dperiod, nperiod = sys.D.dperiod, sys.D.nperiod - subperiod = period/nperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.D.M[:,:,i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - else - println(io, "\n\nEmpty feedthrough matrix D.") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Sample time: $Ts second(s).") - println(io, "Periodic discrete-time state-space model.") - elseif m > 0 && p > 0 - dperiod, nperiod = sys.D.dperiod, sys.D.nperiod - subperiod = period/nperiod - println(io, "\n\nFeedthrough matrix D: subperiod: $subperiod #subperiods: $nperiod ") - println(io, "time values: t[1:$dperiod]") - for i in [1:min(4,dperiod); dperiod-2:dperiod] - i <= 0 && break - println("t[$i] = $(i*Ts)") - display(mime, sys.D.M[:,:,i]) - i == 4 && dperiod > 4 && println(" ⋮") - end - println(io, "\n\nPeriod: $(sys.period) second(s).") - println(io, "Sample time: $Ts second(s).") - println(io, "Time-varying gains.") - else - println(io, "\nEmpty Periodic discrete-time state-space model.") - end -end index2range(ind1, ind2) = (index2range(ind1), index2range(ind2)) index2range(ind::T) where {T<:Number} = ind:ind diff --git a/test/test_psutils.jl b/test/test_psutils.jl index 18d7d6f..3ae653d 100644 --- a/test/test_psutils.jl +++ b/test/test_psutils.jl @@ -29,10 +29,7 @@ ts = (0:K-1)*Δ psys = ps(A,B,C,D); psys = ps(A,B,C); -ps(A); -ps(B); -ps(C); -ps(D); +display(ps(D)) psys = ps(A,B,C,D,4*pi); psys = ps(A,B,C,4*pi); psys = ps(HarmonicArray,A,B,C,D,4*pi); @@ -100,6 +97,7 @@ psys = PeriodicStateSpace(convert(HarmonicArray,A), convert(HarmonicArray,C), convert(HarmonicArray,D)); print(psys); +print(ps(psys.D)) convert(PeriodicStateSpace{PeriodicSymbolicMatrix},psys); convert(PeriodicStateSpace{PeriodicTimeSeriesMatrix},psys); convert(PeriodicStateSpace{PeriodicFunctionMatrix},psys); @@ -122,6 +120,7 @@ Ct = PeriodicTimeSeriesMatrix(convert(PeriodicFunctionMatrix,C).f.(ts),C.period) Dt = PeriodicTimeSeriesMatrix(convert(PeriodicFunctionMatrix,D).f.(ts),D.period); psys = PeriodicStateSpace(At, Bt, Ct, Dt); print(psys); +print(ps(psys.D)) convert(PeriodicStateSpace{PeriodicFunctionMatrix},psys); convert(PeriodicStateSpace{PeriodicSymbolicMatrix},psys); convert(PeriodicStateSpace{HarmonicArray},psys); @@ -136,6 +135,7 @@ psys = PeriodicStateSpace(convert(FourierFunctionMatrix,A), convert(FourierFunctionMatrix,C), convert(FourierFunctionMatrix,D)); print(psys); +@test_throws "not available" print(ps(psys.D)) convert(PeriodicStateSpace{PeriodicFunctionMatrix},psys); convert(PeriodicStateSpace{HarmonicArray},psys); convert(PeriodicStateSpace{PeriodicTimeSeriesMatrix},psys); @@ -174,6 +174,7 @@ Cd = PeriodicMatrix( [[ 1 1 ], [ 1 ]] ,2); Dd = PeriodicMatrix( [[ 1 ]], 1); psys = PeriodicStateSpace(Ad,Bd,Cd,Dd); print(psys); +print(ps(psys.D)) convert(PeriodicStateSpace{PeriodicArray},psys); convert(PeriodicStateSpace{PeriodicTimeSeriesMatrix},psys); @@ -187,6 +188,7 @@ Cd = PeriodicArray(rand(1,2,3),3); Dd = PeriodicArray(rand(1,1,1), 1); psys = PeriodicStateSpace(Ad,Bd,Cd,Dd); print(psys); +print(ps(psys.D)) convert(PeriodicStateSpace{PeriodicMatrix},psys) convert(PeriodicStateSpace{PeriodicTimeSeriesMatrix},psys) @@ -195,6 +197,9 @@ psys = ps(Ad,Bd,Cd); psys = ps(convert(PeriodicMatrix,Ad), Bd, convert(PeriodicMatrix,Cd), Dd); psys = ps(convert(PeriodicMatrix,Ad), Bd, convert(PeriodicMatrix,Cd)); +print(ps(SwitchingPeriodicArray(rand(1,2,3),[2,4,6],10))) + +print(ps(SwitchingPeriodicMatrix(PeriodicMatrices.pmzeros([1,1],[2,2]),[5,10],10))) end end