Skip to content

Commit

Permalink
Make SOS filtfilt give the same result as PolynomialRatio filtfilt
Browse files Browse the repository at this point in the history
- Extrapolate by 3 x the filter order (perhaps +3 if the filter
  order is actually odd) instead of just 6 points
- Run the chained filter in the forward and reverse directions instead
  of running each biquad forward and backward, and adjust steady state
  computation to account for this

Fixes #106
  • Loading branch information
simonster committed May 13, 2015
1 parent 9454663 commit 58354fc
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 575 deletions.
43 changes: 18 additions & 25 deletions src/Filters/filt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -278,31 +278,20 @@ end
# Zero phase digital filtering for second order sections
function filtfilt{T,G,S}(f::SecondOrderSections{T,G}, x::AbstractArray{S})
zi = filt_stepstate(f)
zi2 = zeros(2)
zitmp = zeros(2)
pad_length = 3*size(zi, 1)
zitmp = similar(zi)
pad_length = 6 * length(f.biquads)
t = Base.promote_type(T, G, S)
extrapolated = Array(t, size(x, 1)+pad_length*2)
out = similar(x, t)

istart = 1
for i = 1:size(x, 2)
# First biquad
for i = 1:Base.trailingsize(x, 2)
extrapolate_signal!(extrapolated, 1, x, istart, size(x, 1), pad_length)
f2 = f.biquads[1]*f.g
reverse!(filt!(extrapolated, f2, extrapolated, biquad_si!(zitmp, zi, 1, extrapolated[1])))
reverse!(filt!(extrapolated, f2, extrapolated, biquad_si!(zitmp, zi, 1, extrapolated[1])))

# Subsequent biquads
for j = 2:length(f.biquads)
f2 = f.biquads[j]
extrapolate_signal!(extrapolated, 1, extrapolated, pad_length+1, size(x, 1), pad_length)
reverse!(filt!(extrapolated, f2, extrapolated, biquad_si!(zitmp, zi, j, extrapolated[1])))
reverse!(filt!(extrapolated, f2, extrapolated, biquad_si!(zitmp, zi, j, extrapolated[1])))
reverse!(filt!(extrapolated, f, extrapolated, scale!(zitmp, zi, extrapolated[1])))
filt!(extrapolated, f, extrapolated, scale!(zitmp, zi, extrapolated[1]))
for j = 1:size(x, 1)
@inbounds out[j, i] = extrapolated[end-pad_length+1-j]
end

# Copy to output
copy!(out, istart, extrapolated, pad_length+1, size(x, 1))
istart += size(x, 1)
end

Expand Down Expand Up @@ -345,16 +334,20 @@ function filt_stepstate{T<:Number}(b::Union(AbstractVector{T}, T), a::Union(Abst
function filt_stepstate{T}(f::SecondOrderSections{T})
biquads = f.biquads
si = Array(T, 2, length(biquads))
y = one(T)
for i = 1:length(biquads)
biquad = biquads[i]
A = [one(T)+biquad.a1 -one(T)
+biquad.a2 one(T)]
B = [biquad.b1 - biquad.a1*biquad.b0,
biquad.b2 - biquad.a2*biquad.b0]
si[:, i] = A \ B
# At steady state, we have:
# y = s1 + b0*x
# s1 = s2 + b1*x - a1*y
# s2 = b2*x - a2*y
# where x is the input and y is the output
si[1, i] = (-(biquad.a1 + biquad.a2)*biquad.b0 + biquad.b1 + biquad.b2)/
(biquad.a1 + biquad.a2 + 1)*y
si[2, i] = (biquad.a1*biquad.b2 - biquad.a2*(biquad.b0 + biquad.b1) + biquad.b2)/
(biquad.a1 + biquad.a2 + 1)*y
y = si[1, i] + biquad.b0*y
end
si[1, 1] *= f.g
si[2, 1] *= f.g
si
end

Expand Down

0 comments on commit 58354fc

Please sign in to comment.