Filter Classes¶
The following introduces the concept of the pyfar filter classes. See
filter classes
for a complete documentation.
Types¶
There are three types of Filter objects:
FIR Filter: Finite Impulse Response (FIR) filters are non-recursive filters. FIR filters are very flexible and can have arbitrary magnitude and phase responses.
IIR Filter: Infinite Impulse Response (IIR) filters are recursive filters. They can achieve steeper filter slopes than FIR filters of the same order but are less flexible with respect to the phase response.
SOS Filter: Second Order Section (SOS) filters are cascaded 2nd order recursive filters. They are often more robust against numerical errors than IIR filters of the same order.
Initializing a Filter Object¶
A filter object is initialized at least with the coefficients and a sampling rate
import pyfar as pf
filter = pf.FilterFIR([[3, -1]], 44100)
Applying a time-invariant Filter¶
To filter an audio signal, pass it to the filters process function
input = pf.Signal([1, 2, 3, 4], 44100)
output = filter.process(input)
The output is output.time = [[3, 5, 7, 9]]
and has the same number of
samples as the input.
The output will be the same no matter how often process
is called. This
default behavior is often desired. In some cases, a different functionality can
be useful. For blockwise processing of input signals, the filter object can
track the state of the filter. The initial state can be passed during
initialization or typical states can be set using
filter.init_state(input.cshape, state='zeros')
The above initializes the state with zeros, and if the filter is called with blocks of the input
block_one = filter.process(input[0, 0:2])
block_two = filter.process(input[0, 2:4])
the blockwise output yields the same as the complete output output
seen
above, i.e., block_one.time = [[3, 5]]
, block_two.time = [[7, 9]]
.
This is the case because initializing the state also makes the filter object
track the state across multiple calls of the process
functions.
Another option for initialization is
filter.init_state(input.cshape, state='step')
which makes sure that the first sample of the output is the same as the first sample of the input.
To disable tracking the state, call process
with reset=True
output = filter.process(input, reset=True)
or simply do not initialize the state at all as done by
filter = pf.FilterFIR([[3, -1]], 44100, state=None)
which is the default.
Applying a time-variant Filter¶
In some cases it is necessary to mimic time-variant systems. This can be done by exchanging the filter coefficients
# input signal
input = pf.Signal([1, 2, 3, 4], 44100)
# initialize filter and state
filter = pf.FilterFIR([[2, -2]], 44100)
filter.init_state(input.cshape, state='zeros')
# process first block
output_1 = filter.process(input[..., :2])
# update filter coefficients
filter.coefficients = [[2, -1.9]]
# process second block
output_2 = filter.process(input[..., 2:])
Note that this only works for filters of the same length and after initializing the state. Otherwise, discontinuities will appear between the output blocks.