Need sweepable high-Q bandpass filter (State Variable?)

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

I need a high-Q filter where the center frequency can be adjusted in realtime from ~55Hz to ~10KHz at 44.1KHz sampling rate. The bandwidth needs to be roughly 1.1 x the center frequency and slope needs to be at least ~36dB/octave. Note that I don't really care about phase shift, group delay, passband ripple, etc.

I played around with state variable filters but the slope isn't near what I need. I suppose I can cascade as many as I need to get the required slope but was wondering whether there are better filters given these requirements.

Any suggestions, preferably with available source code?

Post

check out TheVinn's C++ filters
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

antto wrote:check out TheVinn's C++ filters
Yes I actually did look at these and they are quite interesting. However I found it a bit difficult to locate and use the correct parts of the filters as building blocks in other projects since everything is so integrated (just setting up the filter is dispersed over multiple classes so it is not always obvious). For my specific application I certainly don't need it in the template form spread over multiple classes that it is currently in. And I'm not saying that to diss the project at all, I think it is great and gives valuable insight into how the different filters behave with different configurations.

Also, I was wondering whether there was any other filter type specifically suited to narrow bandwidth applications where Fc needs to be sweepable. Basically, what is the current "state of the art" in state variable filters these days? I've been a bit out of the loop for a while when it comes to filters and I'm not sure what the kids use these days...

Post

the filters i mentioned, there's a demo app where you can run the filters, and tweak their parameters in real time, process white noise or wave file to hear how it sounds, even change the filter order, it plots the frequency response and all that useful stuff

yeah it's a bit confusing till you set up the code
but the app helps you find out which filter might be the best one to do the job
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!

irc.libera.chat >>> #kvr

Post

Yes I actually played quite a bit with the app previously and it gave me a starting point for a filter to use. I already had code for an IIR 6th order Chebyshev BP so I used that based on results I saw in the filer app you mention.

However those parameters are "heavy" to calculate for sweep purposes and I'm looking for something that might fit my requirements better. Most synths have sweepable filters so I'm just wondering what they typically use for high-Q bandpass filters.

Post

Synth filters are usually not very steep; typically 2-pole or 4-pole structures so you'd get 12dB/oct slopes on each side for a 4-pole band-pass. In synths it's also not very useful to try to maintain optimality criteria like Chebyshev equiripple-properties so it's generally acceptable to just stack a bunch of lower-order filters in a cascade if you want steeper slopes.

Anyway, if you start with an analog design (with normalized cutoff) then you can pretty much blindly map it to a digital filter with BLT (well, you might want to use separate BLTs for lowpass/highpass parts to maintain bandwidth, especially since you say you don't care about ripple). Since BLT lets you map an arbitrary analog frequency (eg the normalized cutoff) to whatever digital frequency, the whole tuning reduces to a tan() call if you don't need to do anything else.

Normally to get direct-form coeffs of a filter so transformed you'd then do some basic algebra (and possibly some trigonometric substitutions, which give you those sines and cosines you often see in formulas), but one approach that might be nice here would be to use the topology-preserving stuff to map an actual analog topology as-is. This would rely on you being able to come up with an analog topology with "nice" sweeping performance (but something like a cascade of SVF biquads should do), and while the topology-preserving filters are a bit more work to process, the tuning is trivial enough that that work for audio-rate is probably very close to equal (assuming you only need to be able to modify tuning.. you can obvious tune separately for low/high-pass so you can still have band-width control; changing the Chebyshev ripples would require analog coeff recalculation).

Unfortunately, I'm not sure if there's any good easy-to-follow resources on the TPT stuff. This thread is probably the most helpful, though you'll probably need a solid understanding of filters to get anything out of it. Or if you're mapping SVF biquad cascade specifically, you could just cheat and steal Andy's design which should be easy enough adapt into your purposes if you understand analog filters...

So the idea here would be: do the "heavy" calculation once, for normalized tuning in analog. Then separate it into biquads (implemented as something like SVF that actually sweeps nicely), then map each to a digital equivalent (like the above) and finally calculate the tan()-warping (and a bunch of temporaries that directly depend on it) to adjust cutoff. Only the last part needs to be done at sweep-rate.

That said, I'm afraid there's no easy "drop-in" solution here so you'll probably have to get your hand dirty a bit.

Post

A high-Q IIR has an effective slope near the resonant peak that is much steeper than the nominal 12dB or 24db/octave. Do you really need 36dB/octave?
Image
Don't do it my way.

Post

OK guys thanks for all the help. I ended up doing this a completely different way. What I did not mention was that this is for analysis purposes only where I need to track the pitch of the incoming signal very accurately. This filter is just a part of the overall algorithm and is there to clean up the signal for the final high-resolution pitch detector.

What I ended up doing was create a bank of filters, each with a narrow band and slightly overlapping the previous filter's band. So using my course pitch detector, I then pick the closest filter from the bank and pass the signal through it after which it is sent to the main pitch detector. I'm getting very good results now with a bank of my original IIR Chebyshev 6th order BP filters, so I guess all is well then.

BTW I tested cascading 3 variable state filters but the settling time was substantially higher than the 6th order Chebyshev, so I gave up on that. At 20Hz center frequency and 16KHz sampling rate it took about 125ms for the signal to settle down. The 6th order Chebyshev was less than half of that.

Post

the rbj cookbook biquads are worth building for the experience. the bp has two modes, the 2nd having unity gain at cutoff and narrower bandwidth with increased resonance. imo it's quite handy for this sort of application. scuse me if it doesn't meet your criteria.

try building all the ones you can find, it can be useful to have firsthand experience.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

@xoxos

OK thanks I will take a look at the rbj cookbook biquads and see if I can get better results. I agree experimenting with multiple filters is a good way to both learn and possibly find a better solution to my problem. The accuracy of my pitch detector is affected by how clean I can get the fundamental frequency so the better this part works, the more accurate it will be overall.

Post

mystran wrote:Or if you're mapping SVF biquad cascade specifically, you could just cheat and steal Andy's design which should be easy enough adapt into your purposes if you understand analog filters...
IIRC, Andy's optimized design has a kind of mistake. When optimizing 4 state variables into 3 of them, he is implicitly assuming time-invariance (I'm not sure we both are referring to the same version of Andy's design, but seems pretty much like it). I have no idea how much effect does this have on the time-varying performance of the filter, but beware! :)

Post

Z1202 wrote:
mystran wrote:Or if you're mapping SVF biquad cascade specifically, you could just cheat and steal Andy's design which should be easy enough adapt into your purposes if you understand analog filters...
IIRC, Andy's optimized design has a kind of mistake. When optimizing 4 state variables into 3 of them, he is implicitly assuming time-invariance (I'm not sure we both are referring to the same version of Andy's design, but seems pretty much like it). I have no idea how much effect does this have on the time-varying performance of the filter, but beware! :)
Well, to be honest I haven't even tried that filter personally, just figured it would be reasonable for the purpose (and couldn't think of another one to link to).

Post

So maybe I should propose this instead (for 2-pole SVF biquad):

Code: Select all

 // update coeffs when parameters change
 f = tan(M_PI*cutoff / samplerate)
 r = f + 1 / Q
 g = 1 / (f * r + 1)

 // rest is per sample
 // calculate outputs
 hp = (in - r*z1 - z2) * g
 bp = z1 + f*hp
 lp = z2 + f*bp

 // and update state
 z1 += 2*f*hp
 z2 += 2*f*bp

The derivation is to plug TDF2 integrators in the prototype, and solve for hp (and factor the expressions a bit). Should be safe for time-variance, right?

Post

mystran wrote:So maybe I should propose this instead (for 2-pole SVF biquad):

Code: Select all

 // update coeffs when parameters change
 f = tan(M_PI*cutoff / samplerate)
 r = f + 1 / Q
 g = 1 / (f * r + 1)

 // rest is per sample
 // calculate outputs
 hp = (in - r*z1 - z2) * g
 bp = z1 + f*hp
 lp = z2 + f*bp

 // and update state
 z1 += 2*f*hp
 z2 += 2*f*bp

The derivation is to plug TDF2 integrators in the prototype, and solve for hp (and factor the expressions a bit). Should be safe for time-variance, right?
So you're storing the doubled state in the z^-1 modules? Or what's your TDF2 integrator topology?

Post

Z1202 wrote:
mystran wrote:So maybe I should propose this instead (for 2-pole SVF biquad):
...
So you're storing the doubled state in the z^-1 modules? Or what's your TDF2 integrator topology?
Wait, the bp and lp outputs are not averaged with the previous sample's values. Looks like a bug to me

Post Reply

Return to “DSP and Plugin Development”