@@ -16,6 +16,26 @@ Base.filt(f::PolynomialRatio, x, si=_zerosi(f, x)) = filt(coefb(f), coefa(f), x,
1616_zerosi {T,G,S} (f:: SecondOrderSections{T,G} , x:: AbstractArray{S} ) =
1717 zeros (promote_type (T, G, S), 2 , length (f. biquads))
1818
19+ # filt! algorithm (no checking, returns si)
20+ function _filt! {S,N} (out:: AbstractArray , si:: AbstractArray{S,N} , f:: SecondOrderSections ,
21+ x:: AbstractArray , col:: Int )
22+ g = f. g
23+ biquads = f. biquads
24+ n = length (biquads)
25+ @inbounds for i = 1 : size (x, 1 )
26+ yi = x[i, col]
27+ for fi = 1 : n
28+ biquad = biquads[fi]
29+ xi = yi
30+ yi = si[1 , fi] + biquad. b0* xi
31+ si[1 , fi] = si[2 , fi] + biquad. b1* xi - biquad. a1* yi
32+ si[2 , fi] = biquad. b2* xi - biquad. a2* yi
33+ end
34+ out[i, col] = yi* g
35+ end
36+ si
37+ end
38+
1939function Base. filt! {S,N} (out:: AbstractArray , f:: SecondOrderSections , x:: AbstractArray ,
2040 si:: AbstractArray{S,N} = _zerosi (f, x))
2141 biquads = f. biquads
@@ -26,19 +46,10 @@ function Base.filt!{S,N}(out::AbstractArray, f::SecondOrderSections, x::Abstract
2646 error (" si must be 2 x nbiquads or 2 x nbiquads x nsignals" )
2747
2848 initial_si = si
49+ g = f. g
50+ n = length (biquads)
2951 for col = 1 : ncols
30- si = initial_si[:, :, N > 2 ? col : 1 ]
31- @inbounds for i = 1 : size (x, 1 )
32- yi = x[i, col]
33- for fi = 1 : length (biquads)
34- biquad = biquads[fi]
35- xi = yi
36- yi = si[1 , fi] + biquad. b0* xi
37- si[1 , fi] = si[2 , fi] + biquad. b1* xi - biquad. a1* yi
38- si[2 , fi] = biquad. b2* xi - biquad. a2* yi
39- end
40- out[i, col] = yi* f. g
41- end
52+ _filt! (out, initial_si[:, :, N > 2 ? col : 1 ], f, x, col)
4253 end
4354 out
4455end
@@ -50,6 +61,20 @@ Base.filt{T,G,S<:Number}(f::SecondOrderSections{T,G}, x::AbstractArray{S}, si=_z
5061_zerosi {T,S} (f:: Biquad{T} , x:: AbstractArray{S} ) =
5162 zeros (promote_type (T, S), 2 )
5263
64+ # filt! algorithm (no checking, returns si)
65+ function _filt! (out:: AbstractArray , si1:: Number , si2:: Number , f:: Biquad ,
66+ x:: AbstractArray , col:: Int )
67+ @inbounds for i = 1 : size (x, 1 )
68+ xi = x[i, col]
69+ yi = si1 + f. b0* xi
70+ si1 = si2 + f. b1* xi - f. a1* yi
71+ si2 = f. b2* xi - f. a2* yi
72+ out[i, col] = yi
73+ end
74+ (si1, si2)
75+ end
76+
77+ # filt! variant that preserves si
5378function Base. filt! {S,N} (out:: AbstractArray , f:: Biquad , x:: AbstractArray ,
5479 si:: AbstractArray{S,N} = _zerosi (f, x))
5580 ncols = Base. trailingsize (x, 2 )
@@ -60,15 +85,7 @@ function Base.filt!{S,N}(out::AbstractArray, f::Biquad, x::AbstractArray,
6085
6186 initial_si = si
6287 for col = 1 : ncols
63- si1 = initial_si[1 , N > 1 ? col : 1 ]
64- si2 = initial_si[2 , N > 1 ? col : 1 ]
65- @inbounds for i = 1 : size (x, 1 )
66- xi = x[i, col]
67- yi = si1 + f. b0* xi
68- si1 = si2 + f. b1* xi - f. a1* yi
69- si2 = f. b2* xi - f. a2* yi
70- out[i, col] = yi
71- end
88+ _filt! (out, initial_si[1 , N > 1 ? col : 1 ], initial_si[2 , N > 1 ? col : 1 ], f, x, col)
7289 end
7390 out
7491end
@@ -80,6 +97,88 @@ Base.filt{T,S<:Number}(f::Biquad{T}, x::AbstractArray{S}, si=_zerosi(f, x)) =
8097Base. filt (f:: FilterCoefficients , x) = filt (convert (SecondOrderSections, f), x)
8198Base. filt! (out, f:: FilterCoefficients , x) = filt! (out, convert (SecondOrderSections, f), x)
8299
100+ #
101+ # Direct form II transposed filter with state
102+ #
103+
104+ immutable DF2TFilter{T<: FilterCoefficients ,S<: Array }
105+ coef:: T
106+ state:: S
107+
108+ function DF2TFilter (coef:: PolynomialRatio , state:: Vector )
109+ length (state) == length (coef. a)- 1 == length (coef. b)- 1 ||
110+ throw (ArgumentError (" length of state vector must match filter order" ))
111+ new (coef, state)
112+ end
113+ function DF2TFilter (coef:: SecondOrderSections , state:: Matrix )
114+ (size (state, 1 ) == 2 && size (state, 2 ) == length (coef. biquads)) ||
115+ throw (ArgumentError (" state must be 2 x nbiquads" ))
116+ new (coef, state)
117+ end
118+ function DF2TFilter (coef:: Biquad , state:: Vector )
119+ length (state) == 2 || throw (ArgumentError (" length of state must be 2" ))
120+ new (coef, state)
121+ end
122+ end
123+
124+ # # PolynomialRatio
125+ DF2TFilter {T,S} (coef:: PolynomialRatio{T} ,
126+ state:: Vector{S} = zeros (T, max (length (coef. a), length (coef. b))- 1 )) =
127+ DF2TFilter {PolynomialRatio{T}, Vector{S}} (coef, state)
128+
129+ function Base. filt! {T,S} (out:: AbstractVector , f:: DF2TFilter{PolynomialRatio{T},Vector{S}} , x:: AbstractVector )
130+ length (x) != length (out) && throw (ArgumentError (" out size must match x" ))
131+
132+ si = f. state
133+ # Note: these are in the Polynomials.jl convention, which is
134+ # reversed WRT the usual DSP convention
135+ b = f. coef. b. a
136+ a = f. coef. a. a
137+ n = length (b)
138+ if n == 1
139+ scale! (out, x, b[1 ])
140+ else
141+ @inbounds for i= 1 : length (x)
142+ xi = x[i]
143+ val = si[1 ] + b[n]* xi
144+ for j= 1 : n- 2
145+ si[j] = si[j+ 1 ] + b[n- j]* xi - a[n- j]* val
146+ end
147+ si[n- 1 ] = b[1 ]* xi - a[1 ]* val
148+ out[i] = val
149+ end
150+ end
151+ out
152+ end
153+
154+ # # SecondOrderSections
155+ DF2TFilter {T,G,S} (coef:: SecondOrderSections{T,G} ,
156+ state:: Matrix{S} = zeros (promote_type (T, G), 2 , length (coef. biquads))) =
157+ DF2TFilter {SecondOrderSections{T,G}, Matrix{S}} (coef, state)
158+
159+ function Base. filt! {T,G,S} (out:: AbstractVector , f:: DF2TFilter{SecondOrderSections{T,G},Matrix{S}} , x:: AbstractVector )
160+ length (x) != length (out) && throw (ArgumentError (" out size must match x" ))
161+ _filt! (out, f. state, f. coef, x, 1 )
162+ out
163+ end
164+
165+ # # Biquad
166+ DF2TFilter {T,S} (coef:: Biquad{T} , state:: Vector{S} = zeros (T, 2 )) =
167+ DF2TFilter {Biquad{T}, Vector{S}} (coef, state)
168+ function Base. filt! {T,S} (out:: AbstractVector , f:: DF2TFilter{Biquad{T},Vector{S}} , x:: AbstractVector )
169+ length (x) != length (out) && throw (ArgumentError (" out size must match x" ))
170+ si = f. state
171+ (si[1 ], si[2 ]) = _filt! (out, si[1 ], si[2 ], f. coef, x, 1 )
172+ out
173+ end
174+
175+ # Variant that allocates the output
176+ Base. filt {T,S<:Array} (f:: DF2TFilter{T,S} , x:: AbstractVector ) =
177+ filt! (Array (eltype (S), length (x)), f, x)
178+
179+ # Fall back to SecondOrderSections
180+ DF2TFilter (coef:: FilterCoefficients ) = DF2TFilter (convert (SecondOrderSections, coef))
181+
83182#
84183# filtfilt
85184#
0 commit comments