StateVariable centre frequency depends on Q
tomcombriat opened this issue · comments
Hi,
Playing a bit with all the filters I found out a few limitations.
The StateVariable
in mozzi is good fun, it actually is able to display quite high resonance (way bigger than LowPassFilter
at high frequencies) and, for low resonance (Q=255) is quite spot on on the desired cutoff frequency as long as one does not push to far toward Nyquist (not a problem in my opinion).
However, when pushing the resonance, the effective centre_frequency
of the filter decreases. Here is an example with a set centre_frequency
of 1000 Hz:
Q | Effective centre frequency |
---|---|
255 | 1000 |
128 | 846 |
64 | 702 |
32 | 591 |
16 | 498 |
8 | 416 |
4 | 355 |
2 | 292 |
1 | 248 |
By fiddling around a bit, I found that one can renormalise the centre_frequency
to achieve the correct output:
centre_frequency = 4* centre_frequency / (Q^(1/4))
However correcting this is not completely trivial: it implies recalculating the centre_frequency
every time the resonance is changed (just like the LowPassFilter
is doing). Also the normalisation factor is not trivial to compute. So I am asking for opinions:
- Would it be worth to fight a bit to correct this?
- In that case, maybe a lookup table, calculated at compile time could be used?
- Should the original behavior kept (switch using a template argument between
LEGACY
andACCURATE
for instance?
On the other end, I also found that the LowPassFilter
can also be used as a statevariable using:
//return buf1; // LP
//return in-buf0; // HP
return buf0 - buf1; // BP
//return in - buf0 + buf1; // notch
And this filter is not impeded by the shift with Q (and is slightly faster).
As it is not as resonant as StateVariable
, and not scaled, I think it is worth keeping both, and adding the other outputs to LowPassFilter
to make it "another" StateVariable.
What would be the best strategy then?
- Adding a template argument for the filter type? What would be a good name then (
StateVariable2
does not sound right). - Making separated
HighPassFilter
etc, all actually falling back on the code ofLowPassFilter
(hidden template argument).
Let me know your opinions!
Cheers,
Tom
Regarding the StateVariable filter, I guess it will be a good idea to keep old code working as before. Arguably, the center frequency shift is a bug, but there may well be existing code where the frequency shift is not an issue, while additional computation might be. Suggested procedure: Create a new StateVariableFilter
which will have two well-documented functions: setResonance()
and setResonanceQuick()
(or something). StateVariable
could become deprecated with a note on the available choice.
As for a more generic LowPassFilter, FrequencyFilter
or ResonantFilter
might be suitable names for a template?
This can be closed, right?
Well, this is not resolved, but I guess it won't be as this would change the behavior of all existing sketches using the stateVariable. Additionnally, the ResonantFilter class offers filters with stable Q. So I would say yes.