Formula for IIR filter to increase logarithmicaly

I have a low pass and high pass filter in my program and i have a problem where it is hard to accurately filter lower and mid frequencies. As 10KHz is halfway it means most of the filter is just occurring on the treble. I have noticed in many eq’s (shown below) 10khz is near the end with greater ranges at the lower frequencies. How do I recreate this in my IIR filters as i am currently just using the raw value from the slider.

to get a nice “linear” sounding feel to my filter frequency control I used this :

auto freqHz = std::pow(2.71828182846, (frequencyKnob * 5.0) + 4.0);

where frequencyKnob value ranges between 0 and 1.

It’s using the “natural logarithm” e (2.718…etc), you might want to tweak the * 5.0 and + 4.0 to your liking (the multiplier controls the range, the addition controls the offset from 0 Hz, iirc I played about feeding it whitenoise and looking at the results in an analyser to just see how it was responding, as I couldn’t be bothered to fully understand the mathematics behind it in order to know how it would respond! I really ought not to be so lazy!)

edit: pretty obvious I’ve no idea about the mathematics, or at least misunderstood what e is :smiley:

1 Like
// start - start frequency (typically 20Hz)
// end - end frequency (typically 20000Hz)
// perc - proportion from start to end (range 0 - 1)
float logspace(float start, float end, float prop)
{
    return start * std::powf(end / start, prop);
}

This spaces powers of ten evenly so there’s an equal step between 20-200, 200-2000, etc. With this function, 10’000Hz is placed ~90% along the logarithmic scale.

DBG(logspace(20.f, 20000.f, 0.f));   // 20
DBG(logpsace(20.f, 20000.f, 0.33f)); // ~200
DBG(logspace(20.f, 20000.f, 0.67f)); // ~2000
DBG(logspace(20.f, 20000.f, 1.f));   // 20000

DBG(logpsace(20.f, 20000.f, 0.9f));  // 10000
3 Likes

sorry for the late reply, the algorithm worked fine with some changes, this is the code i have to display and read exact values,
some reason
lpKnob->valueFromTextFunction = (const String &text)
{
auto freq = text.removeCharacters(“Hz”).getDoubleValue();
return std::pow(2.71828182846, (1 / ((freq - 4) / 5.903487553f)));
};
lpKnob->textFromValueFunction = (double value)
{
double freq = (value);
return (juce::String(std::pow(2.71828182846, (freq * 5.903487553f) + 4)) + “Hz”);
};

log(2.7182818…)=1, so just use exp(value). It’s going to be faster.

pow(t, p) = exp(p * log(t))

im really not sure how to implement that, whenever i chose a value it either sets it to 20000hz (1) or crashes the program. i want a way to reverse the function (below) for when i type a value it is one between 0 and 1

converting from 0-1 to 0hz-20000hz
return (juce::String(std::pow(2.71828182846, (freq * 5.903487553f) + 4)) + “Hz”);

return (juce::String(std::exp(freq * 5.903487553f + 4)) + “Hz”);

dont think thats entirely correct, prehaps its something wrong on my side but 5 returns 272.99

It is, or you need to show what you mean by not correct:

exp(5)
148.4131591025766

pow(2.72, 5)
148.88279736320004

i got a perfect formula worked out (one that goes from exactly 20 to 20000 with 500 in the middle.
the second function is its inverse and the slider must have a range of 0 to 1. this is so other people can use it if they need.

lpKnob->textFromValueFunction = [](double value)
{
	double freq = (value);
	return (juce::String(20 * (std::pow(10, (3 * freq)))) + "Hz");
};
lpKnob->valueFromTextFunction = [](const String &text)
{
	auto freq = text.removeCharacters("Hz").getDoubleValue();
	return ((log10(freq / 20)) / 3);
};