33#
44# filt and filt!
55#
6-
6+ using .. DSP : _filt_iir!
77
88# # PolynomialRatio
99_zerosi (f:: PolynomialRatio{:z,T} , :: AbstractArray{S} ) where {T,S} =
@@ -248,13 +248,13 @@ DF2TFilter(coef::FilterCoefficients{:z}, arg::Union{Matrix,Type}) =
248248# in place in output. The istart and n parameters determine the portion
249249# of the input signal x to extrapolate.
250250function extrapolate_signal! (out, ostart, sig, istart, n, pad_length)
251- length (out) >= n+ 2 * pad_length || throw (ArgumentError (" output is incorrectly sized" ))
252- x = 2 * sig[istart]
253- for i = 1 : pad_length
254- out[ostart+ i- 1 ] = x - sig[istart+ pad_length+ 1 - i]
251+ length (out) >= n + 2 * pad_length || throw (ArgumentError (" output is incorrectly sized" ))
252+ x = 2 * sig[istart]
253+ for i = 0 : pad_length- 1
254+ out[ostart+ i] = x - sig[istart+ pad_length- i]
255255 end
256256 copyto! (out, ostart+ pad_length, sig, istart, n)
257- x = 2 * sig[istart+ n- 1 ]
257+ x = 2 * sig[istart+ n- 1 ]
258258 for i = 1 : pad_length
259259 out[ostart+ n+ pad_length+ i- 1 ] = x - sig[istart+ n- 1 - i]
260260 end
@@ -263,36 +263,39 @@ end
263263
264264# Zero phase digital filtering by processing data in forward and reverse direction
265265function iir_filtfilt (b:: AbstractVector , a:: AbstractVector , x:: AbstractArray )
266- zi = filt_stepstate (b, a )
267- pad_length = 3 * ( max ( length (a), length (b)) - 1 )
268- t = Base. promote_eltype (b, a , x)
266+ pad_length = min ( 3 * ( max ( length (a), length (b)) - 1 ), size (x, 1 ) - 1 )
267+ zi, bn, an = filt_stepstate (b, a )
268+ t = Base. promote_eltype (bn, an , x)
269269 zitmp = similar (zi, t)
270- extrapolated = Vector {t} (undef, size (x, 1 )+ pad_length * 2 )
270+ extrapolated = Vector {t} (undef, size (x, 1 ) + 2 * pad_length )
271271 out = similar (x, t)
272272
273- istart = 1
274273 for i = 1 : Base. trailingsize (x, 2 )
274+ istart = 1 + (i - 1 ) * size (x, 1 )
275275 extrapolate_signal! (extrapolated, 1 , x, istart, size (x, 1 ), pad_length)
276- reverse! (filt! (extrapolated, b, a, extrapolated, mul! (zitmp, zi, extrapolated[1 ])))
277- filt! (extrapolated, b, a, extrapolated, mul! (zitmp, zi, extrapolated[1 ]))
276+ _filt_iir! (extrapolated, bn, an, extrapolated, mul! (zitmp, zi, extrapolated[1 ]), 1 )
277+ reverse! (extrapolated)
278+ _filt_iir! (extrapolated, bn, an, extrapolated, mul! (zitmp, zi, extrapolated[1 ]), 1 )
278279 for j = 1 : size (x, 1 )
279- @inbounds out[j, i] = extrapolated[end - pad_length+ 1 - j]
280+ out[j, i] = extrapolated[end - pad_length+ 1 - j]
280281 end
281- istart += size (x, 1 )
282282 end
283283
284284 out
285285end
286286
287287"""
288288 filtfilt(coef::FilterCoefficients, x::AbstractArray)
289+ filtfilt(b::AbstractVector, x::AbstractArray)
290+ filtfilt(b::AbstractVector, a::AbstractVector, x::AbstractArray)
289291
290- Filter `x` in the forward and reverse directions using filter
291- coefficients `coef`. The initial state of the filter is computed so
292+ Filter `x` in the forward and reverse directions using either a
293+ `FilterCoefficients` object `coef`, or the coefficients `b` and optionally `a`
294+ as in [`filt`](@ref). The initial state of the filter is computed so
292295that its response to a step function is steady state. Before
293296filtering, the data is extrapolated at both ends with an
294297odd-symmetric extension of length
295- `3*(max(length(b), length(a))-1)`.
298+ `min( 3*(max(length(b), length(a))-1), size(x, 1) - 1)`.
296299
297300Because `filtfilt` applies the given filter twice, the effective
298301filter order is twice the order of `coef`. The resulting signal has
@@ -368,31 +371,39 @@ filtfilt(f::PolynomialRatio{:z}, x) = filtfilt(coefb(f), coefa(f), x)
368371# # Initial filter state
369372
370373# Compute an initial state for filt with coefficients (b,a) such that its
371- # response to a step function is steady state.
372- function filt_stepstate (b:: Union{AbstractVector{T}, T} , a:: Union{AbstractVector{T}, T} ) where T<: Number
374+ # response to a step function is steady state. Also returns padded (b, a).
375+ function filt_stepstate (b:: AbstractVector{V} , a:: AbstractVector{V} ) where V<: Number
376+ T = typeof (one (V) / one (V))
373377 scale_factor = a[1 ]
374378 if ! isone (scale_factor)
375379 a = a ./ scale_factor
376380 b = b ./ scale_factor
381+ elseif T != = V
382+ a = convert .(T, a)
383+ b = convert .(T, b)
377384 end
378385
379386 bs = length (b)
380387 as = length (a)
381388 sz = max (bs, as)
382389 sz > 0 || throw (ArgumentError (" a and b must have at least one element each" ))
383- sz == 1 && return T[]
384390
385391 # Pad the coefficients with zeros if needed
386- bs< sz && (b = copyto! (zeros (eltype (b), sz), b))
387- as< sz && (a = copyto! (zeros (eltype (a), sz), a))
392+ bs < sz && (b = copyto! (zeros (T, sz), b))
393+ as < sz && (a = copyto! (zeros (T, sz), a))
394+ sz == 1 && return (T[], b, a)
388395
389396 # construct the companion matrix A and vector B:
390397 A = [- a[2 : end ] Matrix {T} (I, sz- 1 , sz- 2 )]
391398 B = @views @. muladd (a[2 : end ], - b[1 ], b[2 : end ])
392399 # Solve si = A*si + B
393400 # (I - A)*si = B
394- ((I - A) \ B) .*= scale_factor
395- end
401+ si = (((I - A) \ B) .*= scale_factor)
402+ return (si, b, a)
403+ end
404+
405+ filt_stepstate (b:: AbstractVector{<:Number} , a:: AbstractVector{<:Number} ) =
406+ filt_stepstate (promote (b, a)... )
396407
397408function filt_stepstate (f:: SecondOrderSections{:z,T} ) where T
398409 biquads = f. biquads
0 commit comments