Need sweepable high-Q bandpass filter (State Variable?)
-
- KVRist
- Topic Starter
- 222 posts since 7 Apr, 2003 from San Francisco, CA
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?
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?
- KVRAF
- 2554 posts since 4 Sep, 2006 from 127.0.0.1
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
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
-
- KVRist
- Topic Starter
- 222 posts since 7 Apr, 2003 from San Francisco, CA
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.antto wrote:check out TheVinn's C++ filters
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...
- KVRAF
- 2554 posts since 4 Sep, 2006 from 127.0.0.1
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
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
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
-
- KVRist
- Topic Starter
- 222 posts since 7 Apr, 2003 from San Francisco, CA
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.
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.
- KVRAF
- 7890 posts since 12 Feb, 2006 from Helsinki, Finland
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.
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.
-
- KVRAF
- 2458 posts since 3 Oct, 2002 from SF CA USA NA Earth
-
- KVRist
- Topic Starter
- 222 posts since 7 Apr, 2003 from San Francisco, CA
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.
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.
-
- Banned
- 12368 posts since 30 Apr, 2002 from i might peeramid
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.
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.
-
- KVRist
- Topic Starter
- 222 posts since 7 Apr, 2003 from San Francisco, CA
@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.
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.
-
- KVRAF
- 1607 posts since 12 Apr, 2002
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!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...
- KVRAF
- 7890 posts since 12 Feb, 2006 from Helsinki, Finland
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).Z1202 wrote: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!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...
- KVRAF
- 7890 posts since 12 Feb, 2006 from Helsinki, Finland
So maybe I should propose this instead (for 2-pole SVF biquad):
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?
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
-
- KVRAF
- 1607 posts since 12 Apr, 2002
So you're storing the doubled state in the z^-1 modules? Or what's your TDF2 integrator topology?mystran wrote:So maybe I should propose this instead (for 2-pole SVF biquad):
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?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
-
- KVRAF
- 1607 posts since 12 Apr, 2002
Wait, the bp and lp outputs are not averaged with the previous sample's values. Looks like a bug to meZ1202 wrote:So you're storing the doubled state in the z^-1 modules? Or what's your TDF2 integrator topology?mystran wrote:So maybe I should propose this instead (for 2-pole SVF biquad):
...