Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with the SVF Filter at high cutoff frequencies #145

Open
makingsoundmachines opened this issue Feb 14, 2021 · 7 comments
Open

Problems with the SVF Filter at high cutoff frequencies #145

makingsoundmachines opened this issue Feb 14, 2021 · 7 comments
Labels
bug Something isn't working

Comments

@makingsoundmachines
Copy link

I keep having problems with the SVF filter crashing at cutoff frequencies higher than 2500 hz, especially when using more than one instance. When setting the cutoff with a knob and sweeping the frequency, over a frequency in about that range, the filter just crashes and sound from daisy doesn't recover. Whereas using more than one instance of other filters is fine (e.g. the moogladder).

I can't exactly pinpoint why - would it make sense to try and implement the filter with mat approximations and without the doublesampling, to get better performance out of it? It's a shame because as far as I can see it's the only highpass filter in DaisySP right now.

@stephenhensley stephenhensley added the bug Something isn't working label Feb 15, 2021
@stephenhensley
Copy link
Collaborator

@makingsoundmachines There is a single-pole highpass filter available. (ATone)

I have not seen the behavior you're mentioning, but I also don't think I've used very many of these at once. Are you connecting them in series or are they in parallel or processing different things?

The previous issues that (I thought) were resolved were related to low resonance/high drive along with higher cut off frequencies. If these instabilities were not resolved then I would guess that the internal filter values are getting set to NaN and that is infecting the rest of your audio path.

I can look into fixing this, but I agree that creating a more generic SVF that's as lightweight as possible (i.e. no double sampling, etc.) would be very handy. We recently added a few MI ports that use the current Svf module that would definitely be a bit more efficient without the double sampling.

@makingsoundmachines
Copy link
Author

I'm using them in a serial hp -> lp setting, using two different instances of the filter so I can set an upper and lower cutoff with resonance (a bit like an MS20 filter).

ATone will help me out in one instance though, that is great already! Thank you!

@erikformella
Copy link

I've been experiencing the same issue, running 4 instances in parallel on my Versio.

It seems to happen when the resonance is low and the default drive is unchanged, so maybe related to the previous issue @stephenhensley described?

I haven't written a digital filter since college, but I am happy to get out my debugger and help where I can 😆.

@makingsoundmachines
Copy link
Author

makingsoundmachines commented Feb 25, 2021

I've been researching a little but for now all I have are clues. I'll still leave them here.

I asked a friend whos been working in audio DSP for a long time and he described the issue with Chamberlin SVF and derivates (which this is) like this: "it'll blow up at high freqs if you don't use a high enough q - it's more stable when it resonates than when it's damped", accoding to damping factor < 2 / F1 - F1 / 2.

This is exactly describing my experience. My workaround for now has been implementing another filter model (state variable biquad) where I needed it, which works fine on noise but the Andrew Simper SVF here sounds better on synthesized tones.

I found the original musicDSP source here https://www.musicdsp.org/en/latest/Filters/92-state-variable-filter-double-sampled-stable.html

and a thread about it here that has an erratum https://music-dsp.music.columbia.narkive.com/SzijmwZo/andrew-simper-s-state-variable-filter

`My fault, I put the MIN in the wrong place when re-typing the code to submit
it to the archive.

freq = 2.0sin(PIMIN(0.25, fc/(fs*2)));

or equivalently (for those that didn't understand the 0.25):

freq = 2.0sin(PI0.5*MIN(0.5, fc/fs));

Thanks for picking up the error, and everyone else who has used it and
didn't notice, well at least someone was paying attention ;)

For stability you just have to increase your resonance. This is taken
account of in the calculation:

damp = MIN(2.0*(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq*0.5));

which descreases damping (increase resonance) with increased frequency.

Others prefer to limit your frequency depending on damping, but I prefer to
have a wide frequency range.

--andy`

Haven't found the time to properly dive into it but maybe that will help solve the bug.

@stephenhensley
Copy link
Collaborator

@makingsoundmachines nice! Good find! That should totally help sort it out! I should be able to work in a patch sometime over the next few days!

Thanks for the sleuth work!

@TheSlowGrowth
Copy link
Contributor

TheSlowGrowth commented Feb 25, 2021

It could be worth checking out the topology preserving transform (TPT) version of the SVF: https://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.1.0.pdf
Pages 110 and following.
From my experience the TPT version it doesn't have any instability at high frequencies. I'm implementing this as part of a commercial EQ right now, and haven't seen anything weird so far for frequencies up to 0.9*Fs/2.

@stephenhensley
Copy link
Collaborator

Thanks for sharing that @TheSlowGrowth it looks like a hearty resource for sure. Once I dig into it a bit I may rework this filter (or add another one if it makes sense/sounds any different) with the TPT structure.

Hmm, went to go patch up the freq setting, and I think the fixes are applied to the current version on the archive, and in DaisySP. Though, I could just be missing something silly.

For a sanity check here are some side-by-sides:

For Freq:

// In DaisySP:
freq_ = 2.0f * sinf(PI_F * MIN(0.25f, fc_ / (sr_ * 2.0f)));
// copy/pasted from above (with * added for multiplies)
freq = 2.0 * sin(PI * MIN(0.25, fc/(fs*2)));

For Damp:

// In DaisySP
damp_  = MIN(2.0f * (1.0f - powf(res_, 0.25f)), MIN(2.0f, 2.0f / freq_ - freq_ * 0.5f));
// copy/pasted from above (with * added for multiplies)
damp = MIN(2.0*(1.0 - pow(res, 0.25)), MIN(2.0, 2.0/freq - freq*0.5));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants