Does anyone know if it works to interpolate IIR coefficients to go from one frequency & q to another?
Or is this unstable?
Does anyone know if it works to interpolate IIR coefficients to go from one frequency & q to another?
Or is this unstable?
This would probably be okay for small differences between one set of parameters and another, however for larger differences the filters would lilely become unstable.
A better approach might be to process the same audio with both sets of coefficients and interpolate between the two output signals. Almost like a cross-fade.
You can just interpolate the frequency or q and recalculate the coefs for each new value.
Yeah but with a lot of filters the calculation of the coefficients is extremely expensive compared to interpolation or processing the filter itself : (
If thatâ€™s the case (expensive coefs), you can either:
Hmm interesting yeah I like option 2 but im not sure the resolution Iâ€™d need to pre generateâ€¦ considering gain & q that could be a massive tableâ€¦
Only every X samples also creates slight aliasing type soundsâ€¦ Itâ€™s a tough one!
If I understand the problem correctly nothing beats calculating the coefficients per sample. Even then some filters are not audio rate modulation stable - in my experience - if thatâ€™s an issue.
Iâ€™ve seen solid dsp frameworks simply recalc the coefficients every 4 samples or so. FWIW nobody complained about aliasing but it may depend on the sample rate?
Iâ€™ve done that with the juce IIR where a fairly steep lowpass was required. It worked OK. Wasnâ€™t perfect, especially with rapid changes, and required coefficients to be calculated on a background thread too.
Why would you need a background thread to calculate the coefficients?
IIRC we used the designIIRLowpassHighOrderEllipticMethod from here:
https://docs.juce.com/master/structdsp_1_1FilterDesign.html
The coefficients have to be updated in a thread safe fashion. It was also switchable between IIR and FIR which is probably why we had the background thread thinking about it. Getting a bit off topic.
Iâ€™ve found that in say a SVF, cuttoff and Q are fairly independent. So rather than create a huge 2D lookup table, I was able to get away with 2 smaller ones. One for Cuttoff, another for Q.
In other filters, the expensive part might only be a few lines of code, e.g. the calculation of a trig function, so if you can replace that one part with a lookup, you make it possible to run the coef calculation at audio rate.
Iâ€™ve managed to get a SVF, a Moog-style filter, and a Korg style filter all running at audio rate with these techniques.
For standard biquad coefficients it is safe to interpolate linearly from one set to another, the intermediate filters can never be unstable if both sets are stable. There is an easy proof to this, imagine your recursive coefficients on the well know triangle of stable values for a1/a2, your interpolation values lie on a straight line between two points in this triangle and all points on that line are well within the triangle.
Amazing thank you I tried doing lookups and caching and both had negative trade offs to interpolation but I just wasnâ€™t confident I wouldnâ€™t get an unforeseen explosion out in the wild. Awesome!
Keep in mind there are really two kinds of unstable here:
The choice of coefficients lead to an unstable filter. This wonâ€™t happen when you interpolate between two sets of valid coefficients, as stenzel pointed out.
The change in the coefficients invalidates the state of the filter, causing it to blow up. This can happen to a direct-form biquad because of numerical instability issues, if the step is too large.
If you want to modulate a filter, best use an implementation that is numerically stable when confronted with rapid changes of the parameters. The TPT form used in the SVF class is your friend, itâ€™s also rather lightweight when it comes to calculating the coefficients. Iâ€™d advise against using any sort of direct form biquads. It sounds like you want to use more complicated filters though?
If this is the case, depending on the mapping of cutoff/q to each coefficient, you could try something more sophisticated than linear interpolation for the coefficients. Youâ€™ll always get in hells kitchen if small deviations between very large and very small numbers cause huge effects.
A more general note regarding optimization for performance: Nowadays, itâ€™s easy to sabotage the performance of your inner loops by introducing additional memory accesses or simply additional lines of code to run. It mostly comes down to cache and helping the compiler do its thing, as a rule of thumb. Do not measure this in debug builds, always profile release builds, and make sure the compiler does not â€śoptimize awayâ€ť the thing you want to measure.
For example, it can very well be the case that a lookup table for any sort of trigonometric function turns out more expensive than just going with the simple and straightforward inner loop thatâ€™s just calling the expensive op. Iâ€™ve seen this often when trying out â€śfastâ€ť versions of certain calculations that employ lookup tables or polynomial approximation or anything like that, and just as often it turned out that the leanest and most straightforward implementation of the thing I want to calculate turned out to be fastest.
A better approach might be to process the same audio with both sets of coefficients and interpolate between the two output signals. Almost like a cross-fade.
This only works properly with zero/linear phase filters. Also, the overlap add scheme you need for that will probably turn out more expensive than simply calculating the coefficients, and you get at least one more mul per sample for the windowing as well as a second filter evaluation.
My suggestion is to use SVF filters to create your filters you want to modulate. They have only two coefficients you need to calculate: cutoff frequency and resonance (aka â€śQâ€ť).
If I remember correctly, you calculate the cutoff coefficient like this:
cutoff_coefficient = Tan(PI*frequency / sample_rate)
And Q goes from 1.0 to 0.0:
1.0 = No resonance.
0.0 = Maximum resonance.
You can interpolate those values safely if you want to, no problem.
JUCEâ€™s DSP library has a really fast implementation of Tan(x). I suggest you use that per sample. Then you donâ€™t have to interpolate anything and youâ€™ll get audio rate modulated SVF based filters.