I have this piece of code that applies a Bessel filter:
One-shot version:
import scipy.signal
fc_bessel = 0.14 # [Hz]
ordre_bessel = 3
b,a = scipy.signal.bessel(ordre_bessel, fc_bessel, 'low', analog=False, output='ba', fs=300)
filter_once = scipy.signal.lfilter(b, a, input_data)
As I will in the end receive my data in real-time, I need to adapt this code to take each input_data
on the fly, so I need to maintain the filter state in a zi
variable. So I wrote:
Iterative version:
import scipy.signal
fc_bessel = 0.14 # [Hz]
ordre_bessel = 3
b,a = scipy.signal.bessel(ordre_bessel, fc_bessel, 'low', analog=False, output='ba', fs=300)
z = scipy.signal.lfilter_zi(b, a)
filter_iter = []
for input_value in input_data:
filtered_value, z = scipy.signal.lfilter(b, a, [input_value], zi=z)
filter_iter.append(filtered_value[0])
However, the outputs are completly different (if first value is a 0, filter_once[0]
is 0
but filter_iter[0]
is 0.999...)
I'm not totally sure if this is right; this is my first time working in this area of SciPy, but I think this is not working because of the different initial conditions of lfilter()
vs lfilter_zi()
.
The docs for lfilter_zi()
say
Construct initial conditions for lfilter for step response steady-state.
i.e. assume that a large step in the input has just occurred.
The docs for lfilter()
say
If zi is None or is not given then initial rest is assumed. See lfiltic for more information.
Reading the documentation for lfiltic()
, you can construct a filter state which assumes initial rest like so:
z = scipy.signal.lfiltic(b, a, 0)
This z
value causes your iterative solution to exactly match your all at once solution.
Inspecting z
, it is just zeros, so you can simplify this to:
z = np.zeros(3)
I can't comment on whether you should use a step response initial state or a rest initial state, but this causes the the two solutions to give the same output.