Skip to content

Commit f7fe55f

Browse files
Merge pull request #1 from aytekinar/newtypes
WIP: A proposal for `c2d`
2 parents 94a1817 + 6f712cc commit f7fe55f

File tree

1 file changed

+136
-100
lines changed

1 file changed

+136
-100
lines changed

src/c2d.jl

+136-100
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,122 @@
1+
module Discretization
2+
3+
abstract Method
4+
5+
immutable ZOH <: Method
6+
end
7+
8+
@compat function (m::ZOH){T}(s::StateSpace{T,Siso{true}}, Ts::Real)
9+
A, B, C, D = s.A, s.B, s.C, s.D
10+
ny, nu = size(s)
11+
nx = numstates(s)
12+
M = expm([A*Ts B*Ts;
13+
zeros(nu, nx + nu)])
14+
Ad = M[1:nx, 1:nx]
15+
Bd = M[1:nx, nx+1:nx+nu]
16+
Cd = C
17+
Dd = D
18+
x0map = [speye(nx) spzeros(nx, nu)]
19+
Ad, Bd, Cd, Dd, Ts, x0map
20+
end
21+
22+
immutable FOH <: Method
23+
end
24+
25+
@compat function (m::FOH){T}(s::StateSpace{T,Continuous{true}}, Ts::Real)
26+
A, B, C, D = s.A, s.B, s.C, s.D
27+
ny, nu = size(s)
28+
nx = numstates(s)
29+
M = expm([A*Ts B*Ts zeros(nx, nu);
30+
zeros(nu, nx + nu) eye(nu);
31+
zeros(nu, nx + 2*nu)])
32+
M1 = M[1:nx, nx+1:nx+nu]
33+
M2 = M[1:nx, nx+nu+1:nx+2*nu]
34+
Ad = M[1:nx, 1:nx]
35+
Bd = Ad*M2 + M1 - M2
36+
Cd = C
37+
Dd = D + C*M2
38+
x0map = [eye(nx) -M2]
39+
Ad, Bd, Cd, Dd, Ts, x0map
40+
end
41+
42+
immutable GeneralizedBilinear{T} <: Method
43+
α::T
44+
@compat function (::Type{GeneralizedBilinear}){T}(α::T = 0.5)
45+
# TODO: Any assertions needed?
46+
new{T}(α)
47+
end
48+
end
49+
50+
@compat function (m::GeneralizedBilinear){T}(s::StateSpace{T,Siso{true}}, Ts::Real)
51+
A, B, C, D = s.A, s.B, s.C, s.D
52+
ny, nu = size(s)
53+
nx = numstates(s)
54+
α = m.α
55+
ima = eye(nx) - α*Ts*A
56+
Ad = ima\(eye(nx) + (1.0-α)*Ts*A)
57+
Bd = ima\(Ts*B)
58+
Cd = (ima.'\C.').'
59+
Dd = D + α*(C*Bd)
60+
x0map = [eye(nx) zeros(nx, nu)]
61+
Ad, Bd, Cd, Dd, Ts, x0map
62+
end
63+
64+
immutable ForwardEuler <: Method
65+
end
66+
67+
@compat function (m::ForwardEuler){T}(s::StateSpace{T,Siso{true}}, Ts::Real)
68+
A, B, C, D = s.A, s.B, s.C, s.D
69+
ny, nu = size(s)
70+
nx = numstates(s)
71+
Ad = eye(nx) + Ts*A
72+
Bd = Ts*B
73+
Cd = C
74+
Dd = D
75+
x0map = [eye(nx) zeros(nx, nu)]
76+
Ad, Bd, Cd, Dd, Ts, x0map
77+
end
78+
79+
immutable BackwardEuler <: Method
80+
end
81+
82+
@compat function (m::BackwardEuler){T}(s::StateSpace{T,Siso{true}}, Ts::Real)
83+
A, B, C, D = s.A, s.B, s.C, s.D
84+
ny, nu = size(s)
85+
nx = numstates(s)
86+
ima = eye(nx) - Ts*A
87+
Ad = ima\eye(nx)
88+
Bd = ima\(Ts*B)
89+
Cd = (ima.'\C.').'
90+
Dd = D + C*Bd
91+
x0map = [eye(nx) zeros(nx, nu)]
92+
Ad, Bd, Cd, Dd, Ts, x0map
93+
end
94+
95+
# TODO: Discretization.Method implementations for s::LtiSystem
96+
# TODO: A brainstorming regarding support for any callable objects:
97+
# - Do we need to specialize c2d on RationalTF and ZeroPoleGain, as well,
98+
# and document the method, accordingly, or,
99+
# - Do we just require the method to use s::LtiSystem, no matter what, but
100+
# use a type assertion inside c2d such that the return value of the method
101+
# is a SISO/MIMO discrete system (whichever is suitable for the function
102+
# call)?
103+
104+
end
105+
1106
"""
2-
c2d(s, Ts, method[, α])
107+
c2d(s, Ts[, method])
3108
4109
Convert the continuous system `s` into a discrete system with sample time
5110
`Ts`, using the provided discretization method with zero-order-hold as default.
6111
112+
`method` can be any callable object with a signature `method(s, Ts)`.
113+
114+
`c2d` also supports `do ... end` block calls in the form
115+
116+
c2d(s, Ts) do s, Ts
117+
# Your transformation based on `s` and `Ts`
118+
end
119+
7120
For a system in state space form, returns the discretized system as well as a
8121
matrix `x0map` that transforms the initial conditions to the discrete domain by
9122
`x0_discrete = x0map*[x0; u0]`.
@@ -13,117 +126,40 @@ is returned.
13126
14127
Discretization methods:
15128
16-
- zero-order-hold (`:zoh`)
17-
- first-order-hold (`:foh`)
18-
- bilinear transform (`:bilinear` or `:tustin`)
19-
- forward euler (`:euler` or `:forward_diff`)
20-
- backward euler (`:backward_diff`)
21-
- generalized bilinear transform (`:gbt`)
129+
- zero-order-hold (`Discretization.ZOH()`)
130+
- first-order-hold (`Discretization.FOH()`)
131+
- bilinear transform (`Discretization.Bilinear()`)
132+
- forward Euler (`Discretization.ForwardEuler()`)
133+
- backward Euler (`Discretization.BackwardEuler()`)
134+
- generalized bilinear transform (`Discretization.Bilinear(α::Real)`)
22135
23-
The generalized bilinear transform uses the additional parameter α and is based on [1].
136+
The generalized bilinear transform uses the parameter α and is based on [1].
24137
25138
- [1] G. Zhang, X. Chen, and T. Chen, Digital redesign via the generalized
26139
bilinear transformation, Int. J. Control, vol. 82, no. 4, pp. 741-754, 2009.
27140
"""
28-
function c2d{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real, method::Symbol=:zoh,
29-
α::Real=zero(Float64))
30-
if method == :zoh
31-
return c2dzoh(s, Ts)
32-
elseif method == :foh
33-
return c2dfoh(s, Ts)
34-
elseif method == :bilinear || method == :tustin
35-
return c2dgbt(s, Ts, 0.5)
36-
elseif method == :euler || method == :forward_diff
37-
return c2dforward(s, Ts)
38-
elseif method == :backward_diff
39-
return c2dbackward(s, Ts)
40-
elseif method == :gbt
41-
return c2dgbt(s, Ts, α)
42-
else
43-
error("Unsupported method: ", method)
44-
end
45-
end
46-
47-
# Internal methods
48-
function c2dzoh{S}(s::StateSpace{S,Continuous{true}}, Ts::Real)
49-
A, B, C, D = s.A, s.B, s.C, s.D
50-
ny, nu = size(s)
51-
nx = s.nx
52-
M = expm([A*Ts B*Ts;
53-
zeros(nu, nx + nu)])
54-
Ad = M[1:nx, 1:nx]
55-
Bd = M[1:nx, nx+1:nx+nu]
56-
Cd = C
57-
Dd = D
58-
x0map = [speye(nx) spzeros(nx, nu)]
59-
ss(Ad, Bd, Cd, Dd, Ts), x0map
141+
function c2d(s::StateSpace{Siso{true},Continuous{true}}, Ts::Real,
142+
method = Discretization.ZOH())
143+
@assert Ts > zero(Ts) && !isinf(Ts) "c2d: Ts must be a positive number"
144+
Ad, Bd, Cd, Dd, Ts, x0map = method(s, Ts)
145+
ss(Ad, Bd, Cd, Dd[1], Ts), x0map
60146
end
61147

62-
c2dzoh{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real) = c2dzoh(ss(s),Ts)[1]
63-
64-
function c2dfoh{S}(s::StateSpace{S,Continuous{true}}, Ts::Real)
65-
A, B, C, D = s.A, s.B, s.C, s.D
66-
ny, nu = size(s)
67-
nx = s.nx
68-
M = expm([A*Ts B*Ts zeros(nx, nu);
69-
zeros(nu, nx + nu) eye(nu);
70-
zeros(nu, nx + 2*nu)])
71-
M1 = M[1:nx, nx+1:nx+nu]
72-
M2 = M[1:nx, nx+nu+1:nx+2*nu]
73-
Ad = M[1:nx, 1:nx]
74-
Bd = Ad*M2 + M1 - M2
75-
Cd = C
76-
Dd = D + C*M2
77-
x0map = [eye(nx) -M2]
148+
function c2d(s::StateSpace{Siso{false},Continuous{true}}, Ts::Real,
149+
method = Discretization.ZOH())
150+
@assert Ts > zero(Ts) && !isinf(Ts) "c2d: Ts must be a positive number"
151+
Ad, Bd, Cd, Dd, Ts, x0map = method(s, Ts)
78152
ss(Ad, Bd, Cd, Dd, Ts), x0map
79153
end
80154

81-
c2dfoh{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real) = c2dfoh(s,Ts)[1]
82-
83-
function c2dgbt{S}(s::StateSpace{S,Continuous{true}}, Ts::Real,
84-
α::Real=zero(Float64))
85-
A, B, C, D = s.A, s.B, s.C, s.D
86-
ny, nu = size(s)
87-
nx = s.nx
88-
ima = eye(nx) - α*Ts*A
89-
Ad = ima\(eye(nx) + (1.0-α)*Ts*A)
90-
Bd = ima\(Ts*B)
91-
Cd = (ima.'\C.').'
92-
Dd = D + α*(C*Bd)
93-
x0map = [eye(nx) zeros(nx, nu)]
94-
ss(Ad, Bd, Cd, Dd, Ts), x0map
95-
end
96-
97-
c2dgbt{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real, α::Real=zero(Float64)) = c2dgbt(s,Ts,α)[1]
98-
99-
function c2dforward{S}(s::StateSpace{S,Continuous{true}}, Ts::Real)
100-
A, B, C, D = s.A, s.B, s.C, s.D
101-
ny, nu = size(s)
102-
nx = s.nx
103-
Ad = eye(nx) + Ts*A
104-
Bd = Ts*B
105-
Cd = C
106-
Dd = D
107-
x0map = [eye(nx) zeros(nx, nu)]
108-
ss(Ad, Bd, Cd, Dd, Ts), x0map
109-
end
110-
111-
c2dforward{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real) = c2dforward(ss(s),Ts)[1]
112-
113-
function c2dbackward{S}(s::StateSpace{S,Continuous{true}}, Ts::Real)
114-
A, B, C, D = s.A, s.B, s.C, s.D
115-
ny, nu = size(s)
116-
nx = s.nx
117-
ima = eye(nx) - Ts*A
118-
Ad = ima\eye(nx)
119-
Bd = ima\(Ts*B)
120-
Cd = (ima.'\C.').'
121-
Dd = D + C*Bd
122-
x0map = [eye(nx) zeros(nx, nu)]
123-
ss(Ad, Bd, Cd, Dd, Ts), x0map
155+
c2d{T}(s::LtiSystem{T,Continuous{true}}, Ts::Real,
156+
method = Discretization.ZOH())
157+
@assert Ts > zero(Ts) && !isinf(Ts) "c2d: Ts must be a positive number"
158+
method(s, Ts)::LtiSystem{T,Continuous{false}}
124159
end
125160

126-
c2dbackward{S}(s::LtiSystem{S,Continuous{true}}, Ts::Real) = c2dbackward(ss(s),Ts)[1]
161+
c2d{T}(method::Function, s::StateSpace{T,Continuous{true}}, Ts::Real) = c2d(s, Ts, method)
162+
c2d{T}(method::Function, s::LtiSystem{T,Continuous{true}}, Ts::Real) = c2d(s, Ts, method)
127163

128164
# Zhai, Guisheng, et al. "An extension of generalized bilinear transformation for digital redesign."
129165
# International Journal of Innovative Computing, Information and Control 8.6 (2012): 4071-4081.

0 commit comments

Comments
 (0)