Skip to content

Commit 892dcc1

Browse files
authored
Removed the matrix type parameter from StateSpace, closes #413 (#437)
* Removed the matrix type parameter from StateSpace, closes #413 * Added some tests for conversions and promotion * Improved TransferFunction -> StateSpace conversion
1 parent 8457abd commit 892dcc1

13 files changed

+164
-224
lines changed

docs/src/man/creating_systems.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ ControlSystems._string_mat_with_headers(a::SizedArray) = ControlSystems._string_
9191
Notice the different matrix types used
9292
```jldoctest HSS
9393
julia> sys = ss([-5 0; 0 -5],[2; 2],[3 3],[0])
94-
StateSpace{Continuous,Int64,Array{Int64,2}}
94+
StateSpace{Continuous,Int64}
9595
A =
9696
-5 0
9797
0 -5

src/types/DelayLtiSystem.jl

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Represents an LTISystem with internal time-delay. See `?delay` for a convenience constructor.
55
"""
66
struct DelayLtiSystem{T,S<:Real} <: LTISystem
7-
P::PartionedStateSpace{StateSpace{Continuous,T,Matrix{T}}}
7+
P::PartionedStateSpace{StateSpace{Continuous,T}}
88
Tau::Vector{S} # The length of the vector tau implicitly defines the partitionging of P
99

1010
# function DelayLtiSystem(P::StateSpace{Continuous,T, MT}, Tau::Vector{T})
@@ -33,19 +33,19 @@ function DelayLtiSystem{T,S}(sys::StateSpace, Tau::AbstractVector{S} = Float64[]
3333
throw(ArgumentError("The delay vector of length $length(Tau) is too long."))
3434
end
3535

36-
psys = PartionedStateSpace{StateSpace{Continuous,T,Matrix{T}}}(sys, nu, ny)
36+
psys = PartionedStateSpace{StateSpace{Continuous,T}}(sys, nu, ny)
3737
DelayLtiSystem{T,S}(psys, Tau)
3838
end
3939
# For converting DelayLtiSystem{T,S} to different T
40-
DelayLtiSystem{T}(sys::DelayLtiSystem) where {T} = DelayLtiSystem{T}(PartionedStateSpace{StateSpace{Continuous,T,Matrix{T}}}(sys.P), Float64[])
40+
DelayLtiSystem{T}(sys::DelayLtiSystem) where {T} = DelayLtiSystem{T}(PartionedStateSpace{StateSpace{Continuous,T}}(sys.P), Float64[])
4141
DelayLtiSystem{T}(sys::StateSpace) where {T} = DelayLtiSystem{T, Float64}(sys, Float64[])
4242

4343
# From StateSpace, infer type
44-
DelayLtiSystem(sys::StateSpace{Continuous,T,MT}, Tau::Vector{S}) where {T, MT,S} = DelayLtiSystem{T,S}(sys, Tau)
45-
DelayLtiSystem(sys::StateSpace{Continuous,T,MT}) where {T, MT} = DelayLtiSystem{T,T}(sys, T[])
44+
DelayLtiSystem(sys::StateSpace{Continuous,T}, Tau::Vector{S}) where {T,S} = DelayLtiSystem{T,S}(sys, Tau)
45+
DelayLtiSystem(sys::StateSpace{Continuous,T}) where {T} = DelayLtiSystem{T,T}(sys, T[])
4646

4747
# From TransferFunction, infer type TODO Use proper constructor instead of convert here when defined
48-
DelayLtiSystem(sys::TransferFunction{TE,S}) where {TE,T,S<:SisoTf{T}} = DelayLtiSystem{T}(convert(StateSpace{Continuous,T, Matrix{T}}, sys))
48+
DelayLtiSystem(sys::TransferFunction{TE,S}) where {TE,T,S<:SisoTf{T}} = DelayLtiSystem{T}(convert(StateSpace{Continuous,T}, sys))
4949

5050

5151
# TODO: Think through these promotions and conversions
@@ -69,7 +69,7 @@ end
6969
Base.convert(::Type{<:DelayLtiSystem}, sys::TransferFunction) = DelayLtiSystem(sys)
7070
# Catch convertsion between T
7171
Base.convert(::Type{V}, sys::DelayLtiSystem) where {T, V<:DelayLtiSystem{T}} =
72-
sys isa V ? sys : V(StateSpace{Continuous,T,Matrix{T}}(sys.P.P), sys.Tau)
72+
sys isa V ? sys : V(StateSpace{Continuous,T}(sys.P.P), sys.Tau)
7373

7474

7575

@@ -109,6 +109,13 @@ function /(anything, sys::DelayLtiSystem)
109109
/(anything, sys.P.P) # If all delays are zero, invert the inner system
110110
end
111111

112+
113+
# Test equality (of realizations)
114+
function ==(sys1::DelayLtiSystem, sys2::DelayLtiSystem)
115+
all(getfield(sys1, f) == getfield(sys2, f) for f in fieldnames(DelayLtiSystem))
116+
end
117+
118+
112119
ninputs(sys::DelayLtiSystem) = size(sys.P.P, 2) - length(sys.Tau)
113120
noutputs(sys::DelayLtiSystem) = size(sys.P.P, 1) - length(sys.Tau)
114121
nstates(sys::DelayLtiSystem) = nstates(sys.P.P)

src/types/PartionedStateSpace.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,8 @@ end
220220
function Base.convert(::Type{<:PartionedStateSpace}, sys::T) where T<: StateSpace
221221
PartionedStateSpace(sys,sys.nu,sys.ny)
222222
end
223+
224+
# Test equality (of realizations)
225+
function ==(sys1::PartionedStateSpace, sys2::PartionedStateSpace)
226+
all(getfield(sys1, f) == getfield(sys2, f) for f in fieldnames(PartionedStateSpace))
227+
end

src/types/StateSpace.jl

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,28 @@ end
2424

2525
abstract type AbstractStateSpace{TE<:TimeEvolution} <: LTISystem end
2626

27-
struct StateSpace{TE, T, MT<:AbstractMatrix{T}} <: AbstractStateSpace{TE}
28-
A::MT
29-
B::MT
30-
C::MT
31-
D::MT
27+
struct StateSpace{TE, T} <: AbstractStateSpace{TE}
28+
A::Matrix{T}
29+
B::Matrix{T}
30+
C::Matrix{T}
31+
D::Matrix{T}
3232
timeevol::TE
33-
function StateSpace{TE, T, MT}(A::MT, B::MT, C::MT, D::MT, timeevol::TE) where {TE<:TimeEvolution, T, MT <: AbstractMatrix{T}}
33+
function StateSpace{TE, T}(A::Matrix{T}, B::Matrix{T}, C::Matrix{T}, D::Matrix{T}, timeevol::TE) where {TE<:TimeEvolution, T}
3434
state_space_validation(A,B,C,D)
35-
new{TE, T, MT}(A, B, C, D, timeevol)
35+
new{TE, T}(A, B, C, D, timeevol)
3636
end
37-
function StateSpace(A::MT, B::MT, C::MT, D::MT, timeevol::TE) where {TE<:TimeEvolution, T, MT <: AbstractMatrix{T}}
37+
function StateSpace(A::Matrix{T}, B::Matrix{T}, C::Matrix{T}, D::Matrix{T}, timeevol::TE) where {TE<:TimeEvolution, T}
3838
state_space_validation(A,B,C,D)
39-
new{TE, T, MT}(A, B, C, D, timeevol)
39+
new{TE, T}(A, B, C, D, timeevol)
4040
end
4141
end
4242
# Constructor for Discrete system
43-
function StateSpace(A::MT, B::MT, C::MT, D::MT, Ts::Number) where {T, MT <: AbstractMatrix{T}}
43+
function StateSpace(A::Matrix{T}, B::Matrix{T}, C::Matrix{T}, D::Matrix{T}, Ts::Number) where {T}
4444
state_space_validation(A,B,C,D)
4545
StateSpace(A, B, C, D, Discrete(Ts))
4646
end
4747
# Constructor for Continuous system
48-
function StateSpace(A::MT, B::MT, C::MT, D::MT) where {T, MT <: AbstractMatrix{T}}
48+
function StateSpace(A::Matrix{T}, B::Matrix{T}, C::Matrix{T}, D::Matrix{T}) where {T}
4949
state_space_validation(A,B,C,D)
5050
StateSpace(A, B, C, D, Continuous())
5151
end
@@ -72,19 +72,19 @@ end
7272
const AbstractNumOrArray = Union{Number, AbstractVecOrMat}
7373

7474
# Explicit construction with different types
75-
function StateSpace{TE,T,MT}(A::AbstractNumOrArray, B::AbstractNumOrArray, C::AbstractNumOrArray, D::AbstractNumOrArray, timeevol::TimeEvolution) where {TE, T, MT <: AbstractMatrix{T}}
75+
function StateSpace{TE,T}(A::AbstractNumOrArray, B::AbstractNumOrArray, C::AbstractNumOrArray, D::AbstractNumOrArray, timeevol::TimeEvolution) where {TE, T}
7676
D = fix_D_matrix(T, B, C, D)
77-
return StateSpace{TE, T,Matrix{T}}(MT(to_matrix(T, A)), MT(to_matrix(T, B)), MT(to_matrix(T, C)), MT(D), TE(timeevol))
77+
return StateSpace{TE, T}(to_matrix(T, A), to_matrix(T, B), to_matrix(T, C), to_matrix(T, D), TE(timeevol))
7878
end
7979

8080
# Explicit conversion
81-
function StateSpace{TE,T,MT}(sys::StateSpace) where {TE, T, MT <: AbstractMatrix{T}}
82-
StateSpace{TE,T,MT}(sys.A,sys.B,sys.C,sys.D,sys.timeevol)
81+
function StateSpace{TE,T}(sys::StateSpace) where {TE, T}
82+
StateSpace{TE,T}(sys.A,sys.B,sys.C,sys.D,sys.timeevol)
8383
end
8484

8585
function StateSpace(A::AbstractNumOrArray, B::AbstractNumOrArray, C::AbstractNumOrArray, D::AbstractNumOrArray, timeevol::TimeEvolution)
8686
A, B, C, D, T = to_similar_matrices(A,B,C,D)
87-
return StateSpace{typeof(timeevol),T,Matrix{T}}(A, B, C, D, timeevol)
87+
return StateSpace{typeof(timeevol),T}(A, B, C, D, timeevol)
8888
end
8989
# General Discrete constructor
9090
StateSpace(A::AbstractNumOrArray, B::AbstractNumOrArray, C::AbstractNumOrArray, D::AbstractNumOrArray, Ts::Number) =
@@ -115,13 +115,13 @@ StateSpace(sys::LTISystem) = convert(StateSpace, sys)
115115
"""
116116
`sys = ss(A, B, C, D [,Ts])`
117117
118-
Create a state-space model `sys::StateSpace{TE, T, MT<:AbstractMatrix{T}}`
119-
where `MT` is the type of matrixes `A,B,C,D`, `T` the element type and TE is Continuous or Discrete.
118+
Create a state-space model `sys::StateSpace{TE, T}`
119+
with matrix element type `T` and TE is `Continuous` or `<:Discrete`.
120120
121121
This is a continuous-time model if `Ts` is omitted.
122-
Otherwise, this is a discrete-time model with sampling period Ts.
122+
Otherwise, this is a discrete-time model with sampling period `Ts`.
123123
124-
`sys = ss(D [, Ts])` specifies a static gain matrix D.
124+
`sys = ss(D [, Ts])` specifies a static gain matrix `D`.
125125
"""
126126
ss(args...;kwargs...) = StateSpace(args...;kwargs...)
127127

@@ -214,7 +214,7 @@ function isapprox(sys1::ST1, sys2::ST2; kwargs...) where {ST1<:AbstractStateSpac
214214
end
215215

216216
## ADDITION ##
217-
function +(s1::StateSpace{TE,T,MT}, s2::StateSpace{TE,T,MT}) where {TE,T, MT}
217+
function +(s1::StateSpace{TE,T}, s2::StateSpace{TE,T}) where {TE,T}
218218
#Ensure systems have same dimensions
219219
if size(s1) != size(s2)
220220
error("Systems have different shapes.")
@@ -227,7 +227,7 @@ function +(s1::StateSpace{TE,T,MT}, s2::StateSpace{TE,T,MT}) where {TE,T, MT}
227227
C = [s1.C s2.C;]
228228
D = [s1.D + s2.D;]
229229

230-
return StateSpace{TE,T,MT}(A, B, C, D, timeevol)
230+
return StateSpace{TE,T}(A, B, C, D, timeevol)
231231
end
232232

233233
function +(s1::HeteroStateSpace, s2::HeteroStateSpace)
@@ -258,7 +258,7 @@ end
258258
-(sys::ST) where ST <: AbstractStateSpace = ST(sys.A, sys.B, -sys.C, -sys.D, sys.timeevol)
259259

260260
## MULTIPLICATION ##
261-
function *(sys1::StateSpace{TE,T,MT}, sys2::StateSpace{TE,T,MT}) where {TE,T, MT}
261+
function *(sys1::StateSpace{TE,T}, sys2::StateSpace{TE,T}) where {TE,T}
262262
#Check dimension alignment
263263
#Note: sys1*sys2 = y <- sys1 <- sys2 <- u
264264
if sys1.nu != sys2.ny
@@ -271,7 +271,7 @@ function *(sys1::StateSpace{TE,T,MT}, sys2::StateSpace{TE,T,MT}) where {TE,T, MT
271271
B = [sys1.B*sys2.D ; sys2.B]
272272
C = [sys1.C sys1.D*sys2.C;]
273273
D = [sys1.D*sys2.D;]
274-
return StateSpace{TE,T,MT}(A, B, C, D, timeevol)
274+
return StateSpace{TE,T}(A, B, C, D, timeevol)
275275
end
276276

277277
function *(sys1::HeteroStateSpace, sys2::HeteroStateSpace)

src/types/conversion.jl

Lines changed: 58 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,34 @@
1919
# Base.convert(::Type{<:TransferFunction{<:SisoRational}}, b::Number) = tf(b)
2020
# Base.convert(::Type{<:TransferFunction{<:SisoZpk}}, b::Number) = zpk(b)
2121
#
22-
Base.convert(::Type{TransferFunction{TE,SisoZpk{T1, TR1}}}, b::AbstractMatrix{T2}) where {TE, T1, TR1, T2<:Number} =
23-
zpk(T1.(b), undef_sampletime(TE))
24-
Base.convert(::Type{TransferFunction{TE,SisoRational{T1}}}, b::AbstractMatrix{T2}) where {TE, T1, T2<:Number} =
25-
tf(T1.(b), undef_sampletime(TE))
22+
Base.convert(::Type{TransferFunction{TE,SisoZpk{T1, TR1}}}, D::AbstractMatrix{T2}) where {TE, T1, TR1, T2<:Number} =
23+
zpk(convert(Matrix{T1}, D), undef_sampletime(TE))
24+
Base.convert(::Type{TransferFunction{TE,SisoRational{T1}}}, D::AbstractMatrix{T2}) where {TE, T1, T2<:Number} =
25+
tf(Matrix{T1}(D), undef_sampletime(TE))
2626

27-
function convert(::Type{StateSpace{TE,T,MT}}, D::AbstractMatrix{<:Number}) where {TE,T, MT}
27+
function convert(::Type{StateSpace{TE,T}}, D::AbstractMatrix{<:Number}) where {TE,T}
2828
(ny, nu) = size(D)
29-
A = MT(fill(zero(T), (0,0)))
30-
B = MT(fill(zero(T), (0,nu)))
31-
C = MT(fill(zero(T), (ny,0)))
32-
D = convert(MT, D)
33-
return StateSpace{TE,T,MT}(A,B,C,D,undef_sampletime(TE))
29+
A = fill(zero(T), (0,0))
30+
B = fill(zero(T), (0,nu))
31+
C = fill(zero(T), (ny,0))
32+
D = convert(Matrix{T}, D)
33+
return StateSpace{TE,T}(A,B,C,D,undef_sampletime(TE))
3434
end
3535

3636
# TODO We still dont have TransferFunction{..}(number/array) constructors
37-
Base.convert(::Type{TransferFunction{TE,SisoRational{T}}}, b::Number) where {TE, T} =
38-
tf(T(b), undef_sampletime(TE))
39-
Base.convert(::Type{TransferFunction{TE,SisoZpk{T,TR}}}, b::Number) where {TE, T, TR} =
40-
zpk(T(b), undef_sampletime(TE))
41-
Base.convert(::Type{StateSpace{TE,T,MT}}, b::Number) where {TE, T, MT} =
42-
convert(StateSpace{TE,T,MT}, fill(b, (1,1)))
37+
Base.convert(::Type{TransferFunction{TE,SisoRational{T}}}, d::Number) where {TE, T} =
38+
tf(T(d), undef_sampletime(TE))
39+
40+
Base.convert(::Type{TransferFunction{TE,SisoZpk{T,TR}}}, d::Number) where {TE, T, TR} =
41+
zpk(T(d), undef_sampletime(TE))
42+
43+
Base.convert(::Type{StateSpace{TE,T}}, d::Number) where {TE, T} =
44+
convert(StateSpace{TE,T}, fill(d, (1,1)))
4345
#
4446
# Base.convert(::Type{TransferFunction{Continuous,<:SisoRational{T}}}, b::Number) where {T} = tf(T(b), Continuous())
4547
# Base.convert(::Type{TransferFunction{Continuous,<:SisoZpk{T, TR}}}, b::Number) where {T, TR} = zpk(T(b), Continuous())
4648
# Base.convert(::Type{StateSpace{Continuous,T, MT}}, b::Number) where {T, MT} = convert(StateSpace{Continuous,T, MT}, fill(b, (1,1)))
4749

48-
#
49-
# Base.convert(::Type{<:TransferFunction{<:SisoZpk}}, s::TransferFunction) = zpk(s)
50-
# Base.convert(::Type{<:TransferFunction{<:SisoRational}}, s::TransferFunction) = tf(s)
51-
52-
#
5350
# function Base.convert{T<:Real,S<:TransferFunction}(::Type{S}, b::VecOrMat{T})
5451
# r = Matrix{S}(size(b,2),1)
5552
# for j=1:size(b,2)
@@ -64,16 +61,16 @@ function convert(::Type{TransferFunction{TE,S}}, G::TransferFunction) where {TE,
6461
return TransferFunction{TE,eltype(Gnew_matrix)}(Gnew_matrix, TE(G.timeevol))
6562
end
6663

67-
function convert(::Type{S}, sys::AbstractStateSpace) where {T, MT, TE, S <:StateSpace{TE,T,MT}}
68-
if sys isa S
64+
function convert(::Type{StateSpace{TE,T}}, sys::AbstractStateSpace) where {TE, T}
65+
if sys isa StateSpace{TE, T}
6966
return sys
7067
else
71-
return StateSpace{TE, T,MT}(convert(MT, sys.A), convert(MT, sys.B), convert(MT, sys.C), convert(MT, sys.D), TE(sys.timeevol))
68+
return StateSpace{TE, T}(convert(Matrix{T}, sys.A), convert(Matrix{T}, sys.B), convert(Matrix{T}, sys.C), convert(Matrix{T}, sys.D), TE(sys.timeevol))
7269
end
7370
end
7471

7572
# TODO Maybe add convert on matrices
76-
Base.convert(::Type{HeteroStateSpace{TE1,AT,BT,CT,DT}}, s::StateSpace{TE2,T,MT}) where {TE1,TE2,T,MT,AT,BT,CT,DT} =
73+
Base.convert(::Type{HeteroStateSpace{TE1,AT,BT,CT,DT}}, s::StateSpace{TE2,T}) where {TE1,TE2,T,AT,BT,CT,DT} =
7774
HeteroStateSpace{TE1,AT,BT,CT,DT}(s.A,s.B,s.C,s.D,TE1(s.timeevol))
7875

7976
Base.convert(::Type{HeteroStateSpace}, s::StateSpace) = HeteroStateSpace(s)
@@ -84,45 +81,41 @@ Base.convert(::Type{StateSpace}, s::HeteroStateSpace{Continuous}) = StateSpace(s
8481
function Base.convert(::Type{StateSpace}, G::TransferFunction{TE,<:SisoTf{T0}}) where {TE,T0<:Number}
8582

8683
T = Base.promote_op(/,T0,T0)
87-
convert(StateSpace{TE,T,Matrix{T}}, G)
84+
convert(StateSpace{TE,T}, G)
8885
end
8986

90-
91-
function Base.convert(::Type{StateSpace{TE,T,MT}}, G::TransferFunction) where {TE,T<:Number, MT<:AbstractArray{T}}
87+
function Base.convert(::Type{StateSpace{TE,T}}, G::TransferFunction) where {TE,T<:Number}
9288
if !isproper(G)
9389
error("System is improper, a state-space representation is impossible")
9490
end
9591

96-
# TODO : These are added due to scoped for blocks, but is a hack. This
97-
# could be much cleaner.
98-
#T = Base.promote_op(/, T0, T0)
99-
100-
Ac = Bc = Cc = Dc = A = B = C = D = Array{T}(undef, 0, 0)
101-
for i=1:ninputs(G)
102-
for j=1:noutputs(G)
103-
a, b, c, d = siso_tf_to_ss(T, G.matrix[j, i])
104-
if j > 1
105-
# vcat
106-
Ac = blockdiag(Ac, a)
107-
Bc = vcat(Bc, b)
108-
Cc = blockdiag(Cc, c)
109-
Dc = vcat(Dc, d)
110-
else
111-
Ac, Bc, Cc, Dc = a, b, c, d
112-
end
113-
end
114-
if i > 1
115-
# hcat
116-
A = blockdiag(A, Ac)
117-
B = blockdiag(B, Bc)
118-
C = hcat(C, Cc)
119-
D = hcat(D, Dc)
120-
else
121-
A, B, C, D = Ac, Bc, Cc, Dc
92+
ny, nu = size(G)
93+
94+
# A, B, C, D matrices for each element of the transfer function matrix
95+
abcd_vec = [siso_tf_to_ss(T, g) for g in G.matrix[:]]
96+
97+
# Number of states for each transfer function element realization
98+
nvec = [size(abcd[1], 1) for abcd in abcd_vec]
99+
ntot = sum(nvec)
100+
101+
A = zeros(T, (ntot, ntot))
102+
B = zeros(T, (ntot, nu))
103+
C = zeros(T, (ny, ntot))
104+
D = zeros(T, (ny, nu))
105+
106+
inds = -1:0
107+
for j=1:nu
108+
for i=1:ny
109+
k = (j-1)*ny + i
110+
111+
# states correpsonding to the transfer function element (i,j)
112+
inds = (inds.stop+1):(inds.stop+nvec[k])
113+
114+
A[inds,inds], B[inds,j:j], C[i:i,inds], D[i:i,j:j] = abcd_vec[k]
122115
end
123116
end
124117
# A, B, C = balance_statespace(A, B, C)[1:3] NOTE: Use balance?
125-
return StateSpace{TE,T,MT}(A, B, C, D, TE(G.timeevol))
118+
return StateSpace{TE,T}(A, B, C, D, TE(G.timeevol))
126119
end
127120

128121
siso_tf_to_ss(T::Type, f::SisoTf) = siso_tf_to_ss(T, convert(SisoRational, f))
@@ -131,8 +124,8 @@ siso_tf_to_ss(T::Type, f::SisoTf) = siso_tf_to_ss(T, convert(SisoRational, f))
131124
function siso_tf_to_ss(T::Type, f::SisoRational)
132125

133126
num0, den0 = numvec(f), denvec(f)
134-
# Normalize the numerator and denominator,
135-
# To allow realization of transfer functions that are proper, but now strictly proper
127+
# Normalize the numerator and denominator to allow realization of transfer functions
128+
# that are proper, but not strictly proper
136129
num = num0 / den0[1]
137130
den = den0 / den0[1]
138131

@@ -141,22 +134,22 @@ function siso_tf_to_ss(T::Type, f::SisoRational)
141134
# Get numerator coefficient of the same order as the denominator
142135
bN = length(num) == N+1 ? num[1] : 0
143136

144-
if N==0 #|| num == zero(Polynomial{T})
145-
A = fill(zero(T), 0, 0)
146-
B = fill(zero(T), 0, 1)
147-
C = fill(zero(T), 1, 0)
137+
if N == 0 #|| num == zero(Polynomial{T})
138+
A = zeros(T, (0, 0))
139+
B = zeros(T, (0, 1))
140+
C = zeros(T, (1, 0))
148141
else
149-
A = diagm(1 => fill(one(T), N-1))
142+
A = diagm(1 => ones(T, N-1))
150143
A[end, :] .= -reverse(den)[1:end-1]
151144

152-
B = fill(zero(T), N, 1)
145+
B = zeros(T, (N, 1))
153146
B[end] = one(T)
154147

155-
C = fill(zero(T), 1, N)
148+
C = zeros(T, (1, N))
156149
C[1:min(N, length(num))] = reverse(num)[1:min(N, length(num))]
157150
C[:] -= bN * reverse(den)[1:end-1] # Can index into polynomials at greater inddices than their length
158151
end
159-
D = fill(bN, 1, 1)
152+
D = fill(bN, (1, 1))
160153

161154
return A, B, C, D
162155
end

0 commit comments

Comments
 (0)