Quantcast
Channel: KVR Audio
Viewing all articles
Browse latest Browse all 3350

DSP and Plugin Development • Re: How can I learn how to implement filters from scratch? (C++)

$
0
0
That sounds indeed desirable. How would the coefficient-computation and sample-processing have to be modified to achieve that? I really don't know enough about circuit modeling to understand how I would "take the highpass directly from the solver" etc.
There's actually no "circuit modelling" even required here, we can do it all purely in terms of abstract signals and integrators ... and even though Andy writes in terms of circuit quantities, I think that mostly just makes things more confusing for linear filters... but that's a matter of opinion I guess. I'll post the "purely in terms of signals" version here so you can compare equivalence to Andy's version to perhaps gain more insight.

Anyway, regarding HP the idea is that you take the ODE with 2-dimensions and add a third algebraic dimension for the HP node (ie. feedback summing opamp's output) turning the thing into DAE (which makes little difference in terms of solving; it's still just Ax=b, except now you only integrate some of the values; I'm not going to write that part out right now, but perhaps another day) ... and then if you solve for this new variable first, this thing (which I've posted many times) falls out:

Code:

            float hp = (in - (g+r)*z1 - z2) / (1 + g*(g+r));            float bp = z1 + g*hp;             float lp = z2 + g*bp;            // state variable update            z1 = 2*bp - z1;   // equivalent to: z1 += 2*g*hp            z2 = 2*lp - z2;    // equivalent to: z2 += 2*g*bp                        float out = a2*hp + a1*bp + a0*lp;
The coefficients are g=tan(pi*f/fs) and r=1/Q. The 1/(1+g*(g+r)) term (and optionally (g+r) term too) should be precomputed for static and perhaps even "modulation rate" filters (it's safe to interpolate, even though that results in a bit of extra damping); I left it here "as-is" just so it's easier to read and because for an audio-rate modulated filter you can just as well write it like this directly.

For emphasis, this isn't really different from Andy's filter, you can obtain one from the other simply by rearranging the terms, but I like this form because it's sort of clear in terms of what is going on: we solve the feedback sum (hp node) and then integrate twice.

The "analog prototype response" for this thing is (a2*s^2+a1*s+a0)/(s^2+s/Q+1), so if we have any analog prototype (such as those listed in RBJ Cookbook) where the denominator is already in the form 1/(s^2+s/Q+1) then basically all you have to do is take the scalar multiplies from numerator as a2,a1,a0 and you're set.

If we have a peaking filter, then RBJ gives (s^2+A/Q*s+1)/(s^2+s/(A*Q)+1) so deminator is wrong, so what do we do?!? PANIC. Fortunately we can fix this by substituting Q'=AQ and we get (s^2+A^2/Q'*s+1)/(s^2+s/Q'+1) and now it's in the correct form again when we use r=1/Q'=1/(A*Q).

What about shelves though? We could panic again, but given RBJ lowshelf A*(s^2+sqrt(A)/Q*s+A)/(As^2+sqrt(A)/Q*s+1) we can also do a similar trick, but this with "s" where we substitute s' = s/sqrt(A) so that the denominator multiplies into the desired form and this time we then set g=tan(pi*f/fs)/sqrtA() to scale the cutoff (doing the scaling after tan() pre-warp keeps the pre-warp frequency as-is, which is what RBJ also does).

Symbolically the results are exactly the same whether you do it this way or go through the direct form coefficients, but if you're doing things numerically then the direct form coefficient solve is a bit less stable, so it's helpful to start directly from the analog prototype if possible.

Statistics: Posted by mystran — Fri Nov 08, 2024 5:47 pm



Viewing all articles
Browse latest Browse all 3350

Trending Articles