kfrlib / kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
https://www.kfrlib.com
GNU General Public License v2.0
1.65k stars 253 forks source link

How to set a non-zero filter initial state ? #78

Closed BenjaminNavarro closed 4 months ago

BenjaminNavarro commented 4 years ago

Is it possible to force the initial value of a filter to be non-zero? I couldn't find a way to do it with the current API.

It's a nice thing to do when, for instance, you low pass a signal having a large offset since it allows to skip the possibly long convergence.

dancazarin commented 4 years ago

For FIR filters, you can fill fir_state with values, pass it to fir function with placeholder, then convert to filter.

fir_state<float> state;
// fill state with taps and delay line, set delayline_cursor = 0
auto expr = fir(state, placeholder()); // construct expression without data source
expression_filter<float> filter = to_filter(expr); // convert to filter
// use filter.apply(...)

For biquad filters (and IIR) you can change internal state of expression_biquads after constructing biquad expression but before passing any data to it. You can convert biquad expression using to_filter too.

More convenient and universal method to set initial state would be good for future versions.

slarew commented 4 years ago

I too recently ran into this issue of setting a non-zero initial filter state. My solution was as @dlevin256 proposed. Namely, I fill the FIR state object's delay line with my past samples and then I pass the initialized state to the fir() expression. I stream

// At program startup, initilize fir_state with filter taps.
fir_state my_fir_state(taps);

// Initialize filter state when necessary (e.g. discontinuous input)
my_fir_state.delayline.ringbuf_write(my_fir_state.delayline_cursor, initial_state.data(), initial_state.size());

// Filter input (taking absolute value of filter output as an example) with initialized delayline state.
filtered_output = abs(fir(my_filter_state, input));

Formally documenting these technique, perhaps with a convenience method to initialize the delay line, would be nice.

dancazarin commented 4 months ago

The requested feature has been implemented in KFR 6. Refer to iir_state struct.