# Pre-emphasis filter freq response changing with sample rate

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS
Audiority
KVRian
Topic Starter
1214 posts since 15 Nov, 2005 from Italy
Hi guys,

I'm struggling with a pre-emphasis filter I made, that's not keeping it's center frequency when sample rate changes.

Basically, I'm using a first order difference filter

Code: Select all

``out = input - alpha * lastInput``

The alpha coefficient is calculated this way:

Code: Select all

``exp(-2.0 * pi * Freq * samplePeriod)``
samplePeriod is 1/sampleRate. I see the coefficient changing when the sample rate is changed, but the frequency response is shifted. I guess there's something wrong on the alpha calculation. Right now I replaced that with a biquad high shelving filter, but I would like to understand my mistake here and how can I keep this type of filter without replacing it with a biquad.

Thanks,
Luca

juha_p
KVRian
792 posts since 21 Feb, 2006 from FI
alpha calculation looks OK. Source code of the full process might tell more.

You can also try use

Code: Select all

``exp(-2.0f*pi*fc/fs)``
to be sure fs change is noticed in alpha calculation.

Here's an example of the filtering process itself:

Code: Select all

``````float last_input = 0;

float filter (float input, float alpha)
{
float output = input - alpha * last_input;
last_input = input;
return output;
}
``````

rafa1981
KVRian
861 posts since 4 Jan, 2007
Not an expert on DSP, but shouldn't that have prewarping?

That 1-pole filter is the typical parameter-smoothing 1-pole (non zero) filter.

You could use the 1-pole, 1-zero on Vadim's book. It also explains prewarping.
https://www.native-instruments.com/file ... _2.1.0.pdf

Here is the onepole I have, as a bad code reference, as it has all bells and whistles (compile-time multimode, vectorized, etc). "t_spl" is fc/fs:
https://github.com/RafaGago/artv-audio/ ... le.hpp#L83

Markus Krause
KVRAF
1625 posts since 2 Jul, 2018
float alpha = exp(-2.0f*pi*fc/fs)

float filter (float input, float alpha)
{
float output = input - alpha * last_input;
last_input = input;
return output;
}
When you move very close towards the nyquist frequency this filter does show a different frequency and phase response in different samplerates. I'd say this is true for all (?) IIR filters.
Tone2 Audiosoftware https://www.tone2.com

juha_p
KVRian
792 posts since 21 Feb, 2006 from FI
Audiority wrote: Tue Feb 07, 2023 6:30 am Hi guys,

I'm struggling with a pre-emphasis filter I made, that's not keeping it's center frequency when sample rate changes.

Basically, I'm using a first order difference filter

Code: Select all

``out = input - alpha * lastInput``

The alpha coefficient is calculated this way:

Code: Select all

``exp(-2.0 * pi * Freq * samplePeriod)``
samplePeriod is 1/sampleRate. I see the coefficient changing when the sample rate is changed, but the frequency response is shifted. I guess there's something wrong on the alpha calculation. Right now I replaced that with a biquad high shelving filter, but I would like to understand my mistake here and how can I keep this type of filter without replacing it with a biquad.

Thanks,
Luca
Can you show more of your source code with all related parameter values and maybe plots showing the issue you have there (even if solved already)?

I tested common pre-emphasis filter for speech (alpha 0.95 @ 44.1kHz) (fc = ~360.013937501767984926838 Hz) in Octave and got these responses for 44.1kHz as a base fs (x1, x2, x4 and x8):
preemphnormalized.png
I had to normalize x2, x4 and x8 filters to have 0dB @ ~7.2kHz to get all filter responses follow the base filter response.
You do not have the required permissions to view the files attached to this post.

Audiority
KVRian
Topic Starter
1214 posts since 15 Nov, 2005 from Italy
Hey guys,
thanks for you replies. The full code is nothing much more of what I posted:

Code: Select all

``````class preEmphasisFilter
{
public:
preEmphasisFilter() : sRate(44100.0), samplePeriod(0.0f), alpha(0.0f), last(0.0f)
{}

~preEmphasisFilter() {}

void init(const double sampleRate)
{
sRate = sampleRate;
samplePeriod = 1.0 / sampleRate;
last = 0.0f;
}

void setFrequency(const float freq)
{
alpha = exp(-2.0 * M_PI * freq * samplePeriod);
}

inline float process(const float input)
{
const float output = input - alpha * last;
last = input;

return output;
}

private:
double sRate = 44100.0, samplePeriod = 1.0 / sRate;
float alpha = 0.0f, last = 0.0f;

};
``````
This was set around 2kHz, so nothing so close to nyquist to justify a huge change in frequency response. When sample rate is changed (or oversampling enabled), this filter gets initialized again and its frequency reset to the current value, so I'm pretty much sure the sample period value is up to date.

kryptonaut
KVRian
791 posts since 25 Apr, 2011
Your process() function is essentially using alpha to blend between the input and the derivative (difference between input and previous input):

Code: Select all

``output = input - alpha * last = (1-alpha)*input + alpha*(input-last)``
If you increase the sample rate by a factor r, then the derivatives (differences) will scale by 1/r (all else being equal) so in order to maintain a similar output I think you want:

Code: Select all

``````float r=sRate/44100.0
output = (1-alpha)*input + r*alpha*(input-last)``````
Of course you can optimise by precalculating 1-alpha and r*alpha, and you might be able to rearrange the arithmetic to use fewer operations.

Note that I haven't run this as code, but I did some spreadsheet calcs which seem to show that it works as expected.

Note: I think you will also want to remove the dependency of alpha on the current sample rate

juha_p
KVRian
792 posts since 21 Feb, 2006 from FI
This page guides making of (FM) de- and pre-emphasis filter. Keeps response quite well (plotted 44.1kHz, x2, x4 and x8):
FMdeemphUS.png
You do not have the required permissions to view the files attached to this post.

Mrmedic01
KVRer
1 posts since 30 Dec, 2021
double L = 3 * L2 - L1 - L;