# Real-time modulated IIR filter

I've been learning to implement an IIR filter for a synthesizer project. It is now more or less stable when the parameters are constant, but ultimately I want the parameters to be arbitrarily modulated.

I figured it would be too slow to compute new recursion coefficients every sample, so instead I'm computing them every "chunk" (a piece of 256 or so samples which the synthesizer produces in a batch and then sends to the audio driver). This brings me to my question:

How should I approach hotswapping the recursion coefficients? Or is there a more correct way of modulating IIR filters?

I am curently linearly interpolating the output of the model generated in the last chunk with the one generated in the current. (at the beginning of the chunk, the output is 100% from the old one, and at the end 100% from the new one) This isn't enough, since the new filter needs to be initialized somehow. I have tried some things with various degrees of success:

• The new filter is initialized with signal history pulled from the old one.

This sounds the best, but when too heavy modulation is applied (for example, the cutoff frequency changes too much at once), the new filter might initially output an uncontrollable spike which then peaks. This mostly happens along with a discontinuity in the input signal.

Here's a 60 Hz saw wave LP-filtered using a cutoff oscillating at 20 Hz. (the filter is configured to have two biquads). Such a spike never occurs when the cutoff frequency is kept constant.

• The filter history is initialized in a stable state. (e.g. constant signal in and out at the intensity of the last seen sample for LP, or plain zero)

This causes some audible rattle when modulating, no matter how I try to fade in the new filter gradually. The new filter never quite reaches the old one's state.

All ideas and advice are welcome.

Edit:

I have implemented the biquads in a lattice topology, as per Robert's suggestion. Modulation now works great, but raising the cutoff frequency too high (or too low for a high pass filter) breaks something. This should be a single biquad low pass filter with cutoff $\frac{3}{4}\pi$:

The direct form parameters, from which the lattice is derived, work just fine. It is certainly possible, that there is some error in my equations for the conversion. I also noticed that the shape of the frequency response isn't quite as steep as with the direct form. I am suspecting it has something to do with the "tap" coefficients..

What could be going on now? Perhaps I should make a new question with details about my implementation, as the original issue is now more or less solved.

• i think the more correct way to modulate IIR filters is to use the Lattice form or Normalized Ladder form. You can equate it directly to the Direct I or Direct II forms and derive the coefficients from the transfer function. the Lattice form is much more friendly to modulation. – robert bristow-johnson Apr 2 '18 at 0:52
• @robertbristow-johnson I searched around a bit, but found nothing definitive. Any recommendations on material explaining how the coefficients are calculated? – ollpu Apr 2 '18 at 13:04
• i stumbled upon this presentation. it does not solve for the coefficients, but it spells out the structure pretty well. you might have to do this yourself, but if you go to the very last slide and cut off the section that makes this 3rd-order (cut off everything that is left of $B_3(z)$), you will have a general 2nd-order lattice. you will notice exactly 5 independent parameters in that 2nd-order lattice and in a 2nd-order IIR transfer function there are also 5 independent parameters. you need to solve that. – robert bristow-johnson Apr 2 '18 at 18:36
• Along with a couple other materials, I figured it out. Aside from different gain behaviour (which was fairly straightforward to solve), it sounds and modulates great now. There is still some weird behaviour with cutoff frequencies higher than half the nyqist which I need to investigate. Anyways, thanks a lot! – ollpu Apr 3 '18 at 11:56
• @robertbristow-johnson Any clue about what could be going on with the high cutoff? I've updated my question. – ollpu Apr 4 '18 at 14:34

okay, using the snipping tool, i tried to put in just the 2nd-order IIR lattice in the following drawing. $x[n]$ is being input in the upper left. the numbering for the $v_*$ coefficients is horrible, but i just cut this drawing out from somewhere else.

now the transfer function i get for this is

$$H(z) = \frac{Y(z)}{X(z)} = \frac{v_4 + v_3(-k_1 + z^{-1}) + v_2\big(-k_2+k_1(k_2-1)z^{-1} + z^{-2}\big)}{1 + k_1(k_2-1) z^{-1} - k_2 z^{-2}}$$

and if you compare that to the standard direct form

$$H(z) = \frac{b_0 + b_1 z^{-1} + b_2 z^{-2}}{1 + a_1 z^{-1} + a_2 z^{-2}}$$

you should have equivalence when

\begin{align} k_2 &= -a_2 \\ k_1 &= -\frac{a_1}{a_2+1} \\ \\ v_2 &= b_2 \\ v_3 &= b_1 - a_1 b_2 \\ v_4 &= b_0 - \frac{a_1}{a_2+1} b_1 + \left( \frac{a_1^2}{a_2+1} - a_2 \right)b_2 \\ \end{align}

i would appreciate it if someone else would check my work. i could well have fucked up a sign or something.

so, wherever you get your five Direct Form $a_k$ and $b_k$ coefficients (e.g., the Cookbook, but remember to divide everything by $a_0$), you can convert them to the five Lattice Form coefficients with the above equations (assuming i didn't mess it up).

• Yup, I just got mine working right, it was just a case of different materials messing up the signs of the k-parameters. Compared to mine however, your k_1 looks different: I get k_1=\frac{a_1-a_1*a_2}{a_2^2-1} (although I have different signs on a:s, could've messed up converting as well) – ollpu Apr 4 '18 at 18:51
• so you have $$k_1=\frac{a_1-a_1 a_2}{a_2^2-1} = \frac{a_1(1-a_2)}{(a_2+1)(a_2-1)}$$ then factor the top and bottom. you will see a common $a_2-1$ factor in both numerator and denominator. – robert bristow-johnson Apr 4 '18 at 18:56
• Ah sure! Could've tested for equality before commenting. I checked the rest and they are equivalent to mine, which at least according to my testing, works perfect. – ollpu Apr 4 '18 at 19:12
• @ollpu, thanks for checking my equations. BTW, "$v_4$" should be relabeled $v_0$ and "$v_3$" should be relabeled $v_1$. so did you notice what $k_1$ came out to be?? that is very important. using the Cookbook, $$k_1 = \cos(\omega_0)$$ so $k_1$ solely determines the resonant frequency. – robert bristow-johnson Apr 4 '18 at 21:50
• $k_1$ does indeed simplify nicely, but I'm not seeing why $k_2$ couldn't affect the resonant frequency as well. I tried different values and it does seem to hold. What am I missing? – ollpu Apr 5 '18 at 22:16