Some Background:
I currently working on generating my own EQ plots. I seem to get the same results as EQ APO if I choose a really large value for sample rate in my calculations. But I don't know how correct that really is.
So my question is what value for variable 'srate' (Sample rate) is EQ APO effectively using? It's not tied to the Windows setting is it?
Refer to BiQuad.cpp for the biquad coefficient equations.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
For calculating a plot a fixed sample rate must used but the value itself doesn't matter. This is what I've noticed when creating the graph window of the Peace equalizer interface. But when Equalizer APO is processing the audio (stream) it needs to take the sample rate for the specific device. This sample rate is usually 48 kHz of 96 kHz. In other words, the sample rate is tied to the Windows setting of that specific device. Any deviation and the Biquad filter calculations will fail.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
That's interesting. In my own calculations, sample rate does actually have an effect if your F0 frequncy is close to your SampleRate/2. Take a look at my attachement. The 3 curves are peaking filters at 18k, Q=1, dB=6.
I'm using the exact same equations for calculation the Biquad coefficients. But maybe I'm evaluating the transfer function differently?
You're right. When nearing the sample rate/2 the frequency curve does seem different (which is obviously a normal "behavour" according to the calculations). Sorry, I didn't spot that. As example I've attached 2 curves: 44100 and 96000 Hz. The peak filter on 2 kHz isn't affected but the one on 20 kHz is. The same as your curves, I guess, although it looks a bit different, less effect towards the 10 kHz. I'll give my calculation program code below.
One thing has to be noted. Since the sample rate is high (even 44100), the actual difference can't be easily heard. We're talking about frequencies above 10 kHz which our ears having more difficulty with than lower ones. But for accuracy the graph should be according to the set sample rate.
The following AutoIt program code is part of Peace. CalculateCoefficient is a function which needs an input of a filter type, a gain in dB, a frequency and a quality to calculate the coefficients for a BiQuad filter. For your information the filter types are the known ones and also Linkwitz-Riley and Butterworth filters which are built up from low/high pass filters. The second function called GainAtfrequency takes these coefficients to calculate the output gain at a given frequency. This function includes also the calculations for the Linkwitz-Riley and Butterworth filters. Both functions are similar to those of Equalizer APO except in earlier versions of Equalizer APO the Gain At Frequency function had a bug (a wrong sign). I think it's now corrected in Equalizer APO.
FuncCalculateCoefficient($FilterNo,$FilterType,$dBGain,$Frequency,$Quality); calculate coefficients of transfer function of a filterLocal $Gain,$Omega,$Cosine,$Alpha,$Beta,$a0,$a1,$a2,$b0,$b1,$b2,$Factors,$FirstOrderIf$FilterType=0Or$FilterType=4Or$FilterType=5Or$FilterType=8Or$FilterType=9Or$FilterType=14Or$FilterType=15Then; peak, low/high shelf;~ beneath calculation not needed, not sure why;~ ; calculate center frequency of LS/HS 6/12 dB filters);~ If $FilterType = 10 Then;~ $Frequency *= 10^(($dBGain/80)/($Quality/12));~ ElseIf $FilterType = 11 Then;~ $Frequency /= 10^(($dBGain/80)/($Quality/12));~ EndIf
$Gain=10^($dBGain/40)Else
$Gain=10^($dBGain/20)EndIf
$Omega=$2Pi*$Frequency/$SampleFrequency;$Cosine=cos($Omega);If$FilterType=4Or$FilterType=5Or$FilterType=8Or$FilterType=9Or$FilterType=14Or$FilterType=15Then; low/high shelf; set or calculate slope factorIf$FilterType=4Or$FilterType=5Then
$Quality=0.9; quality taken from Equalizer APO for low/high shelfElseIf$FilterType=8Or$FilterType=9Then
$Quality/=12; quality division taken from Equalizer APO for low/high shelf with center frequencyElseIf$FilterType=14Or$FilterType=15Then
$Quality=1/((1/($Quality*$Quality)-2)/($Gain+1/$Gain)+1); quality to slope, Equalizer APO 1.2.1 and higherEndIf$Alpha=sin($Omega)/2*sqrt(($Gain+1/$Gain)*(1/$Quality-1)+2)$Beta=2*sqrt($Gain)*$AlphaElse$Alpha=sin($Omega)/(2*$Quality)EndIfSwitch($FilterType)Case0; peak$b0=1+($Alpha*$Gain)$b1=-2*$Cosine$b2=1-($Alpha*$Gain)$a0=1+($Alpha/$Gain)$a1=-2*$Cosine$a2=1-($Alpha/$Gain)Case1; low pass$b0=(1-$Cosine)/2$b1=1-$Cosine$b2=(1-$Cosine)/2$a0=1+$Alpha;$a1=-2*$Cosine;$a2=1-$Alpha;Case2; high pass$b0=(1+$Cosine)/2$b1=-(1+$Cosine)$b2=(1+$Cosine)/2$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$AlphaCase3; band pass$b0=$Alpha$b1=0;$b2=-$Alpha$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$AlphaCase4,8,14; low shelf$b0= $Gain*(($Gain+1)-($Gain-1)*$Cosine+$Beta)$b1=2*$Gain*(($Gain-1)-($Gain+1)*$Cosine)$b2= $Gain*(($Gain+1)-($Gain-1)*$Cosine-$Beta)$a0=($Gain+1)+($Gain-1)*$Cosine+$Beta$a1=-2*(($Gain-1)+($Gain+1)*$Cosine)$a2=($Gain+1)+($Gain-1)*$Cosine-$BetaCase5,9,15; high shelf$b0= $Gain*(($Gain+1)+($Gain-1)*$Cosine+$Beta)$b1=-2*$Gain*(($Gain-1)+($Gain+1)*$Cosine)$b2= $Gain*(($Gain+1)+($Gain-1)*$Cosine-$Beta)$a0=($Gain+1)-($Gain-1)*$Cosine+$Beta$a1=2*(($Gain-1)-($Gain+1)*$Cosine)$a2=($Gain+1)-($Gain-1)*$Cosine-$BetaCase6; notch$b0=1$b1=-2*$Cosine$b2=1$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$AlphaCase7; all pass$b0=1-$Alpha$b1=-2*$Cosine$b2=1+$Alpha$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$AlphaCase10,12; low pass Butterworth and Linkwitz-RileyIf$FilterType=10Or$FilterType=11Then$Factors=Floor($Quality/2)$FirstOrder=0Else$Factors=Floor($Quality/2)$FirstOrder=Mod($Factors,2)$Factors=Floor($Factors/2)
$Quality/=2EndIfIf$FirstOrder=1Then$Alpha=sin($Omega)/(2*0.5)$b0=(1-$Cosine)/2$b1=1-$Cosine$b2=(1-$Cosine)/2$a0=1+$Alpha;$a1=-2*$Cosine;$a2=1-$Alpha;
$TFb0[$FilterNo][0] =$b0/$a0
$TFb1[$FilterNo][0] =$b1/$a0
$TFb2[$FilterNo][0] =$b2/$a0
$TFa1[$FilterNo][0] =$a1/$a0
$TFa2[$FilterNo][0] =$a2/$a0EndIfFor $k=$FactorsTo1Step-1; $Quality = number of orders n$Alpha=sin($Omega)/(2*CalculateQuality($k,$Quality))$b0=(1-$Cosine)/2$b1=1-$Cosine$b2=(1-$Cosine)/2$a0=1+$Alpha;$a1=-2*$Cosine;$a2=1-$Alpha;
$TFb0[$FilterNo][$k+$FirstOrder-1] =$b0/$a0
$TFb1[$FilterNo][$k+$FirstOrder-1] =$b1/$a0
$TFb2[$FilterNo][$k+$FirstOrder-1] =$b2/$a0
$TFa1[$FilterNo][$k+$FirstOrder-1] =$a1/$a0
$TFa2[$FilterNo][$k+$FirstOrder-1] =$a2/$a0NextCase11,13; high pass Butterworth and Linkwitz-RileyIf$FilterType=10Or$FilterType=11Then; Butterworth$Factors=Floor($Quality/2)$FirstOrder=0Else$Factors=Floor($Quality/2)$FirstOrder=Mod($Factors,2)$Factors=Floor($Factors/2)
$Quality/=2EndIfIf$FirstOrder=1Then$Alpha=sin($Omega)/(2*0.5)$b0=(1+$Cosine)/2$b1=-(1+$Cosine)$b2=(1+$Cosine)/2$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$Alpha
$TFb0[$FilterNo][0] =$b0/$a0
$TFb1[$FilterNo][0] =$b1/$a0
$TFb2[$FilterNo][0] =$b2/$a0
$TFa1[$FilterNo][0] =$a1/$a0
$TFa2[$FilterNo][0] =$a2/$a0EndIfFor $k=$FactorsTo1Step-1; $Quality = number of orders n$Alpha=sin($Omega)/(2*CalculateQuality($k,$Quality))$b0=(1+$Cosine)/2$b1=-(1+$Cosine)$b2=(1+$Cosine)/2$a0=1+$Alpha$a1=-2*$Cosine$a2=1-$Alpha
$TFb0[$FilterNo][$k+$FirstOrder-1] =$b0/$a0
$TFb1[$FilterNo][$k+$FirstOrder-1] =$b1/$a0
$TFb2[$FilterNo][$k+$FirstOrder-1] =$b2/$a0
$TFa1[$FilterNo][$k+$FirstOrder-1] =$a1/$a0
$TFa2[$FilterNo][$k+$FirstOrder-1] =$a2/$a0NextEndSwitchIfNot($FilterType>=10And$FilterType<=13)Then; no Butterworth and Linkwitz-Riley low/high pass filters; normalize by a0
$TFb0[$FilterNo][0] =$b0/$a0
$TFb1[$FilterNo][0] =$b1/$a0
$TFb2[$FilterNo][0] =$b2/$a0
$TFa1[$FilterNo][0] =$a1/$a0
$TFa2[$FilterNo][0] =$a2/$a0EndIfEndFuncFuncGainAtFrequency($Speaker,$FilterNo,$Frequency); calculate gain at a frequencyLocal $Phi=(sin($2Pi*$Frequency/(2*$SampleFrequency)))^2,$Numerator,$Denominator,$Gain,$CascadeAmount,$Factors,$FirstOrder,$QualityIf$Equalizer[$Speaker][4][$FilterNo] >=10And$Equalizer[$Speaker][4][$FilterNo] <=13Then; Butterworth and Linkwitz-Riley low/high pass filters
$Gain=0
$Quality=$Equalizer[$Speaker][3][$FilterNo]
If$Equalizer[$Speaker][4][$FilterNo] =10Or$Equalizer[$Speaker][4][$FilterNo] =11Then$CascadeAmount=1$Factors=Floor($Quality/2)$FirstOrder=0Else$CascadeAmount=2$Factors=Floor($Quality/2)$FirstOrder=Mod($Factors,2)$Factors=Floor($Factors/2)
$Quality/=2EndIfIf$FirstOrder=1Then
$Numerator=($TFb0[$FilterNo][0]+$TFb1[$FilterNo][0]+$TFb2[$FilterNo][0])^2-4*($TFb0[$FilterNo][0]*$TFb1[$FilterNo][0]+4*$TFb0[$FilterNo][0]*$TFb2[$FilterNo][0]+$TFb1[$FilterNo][0]*$TFb2[$FilterNo][0])*$Phi+16*$TFb0[$FilterNo][0]*$TFb2[$FilterNo][0]*$Phi*$Phi$Denominator=(1+$TFa1[$FilterNo][0]+$TFa2[$FilterNo][0])^2-4*($TFa1[$FilterNo][0]+4*$TFa2[$FilterNo][0]+$TFa1[$FilterNo][0]*$TFa2[$FilterNo][0])*$Phi+16*$TFa2[$FilterNo][0]*$Phi*$Phi
$Gain+=10*Log10($Numerator/$Denominator)EndIfFor $k=$Factors+$FirstOrder-1To$FirstOrderStep-1; $Quality = number of filter orders nFor$Cascade=1To$CascadeAmount
$Numerator=($TFb0[$FilterNo][$k]+$TFb1[$FilterNo][$k]+$TFb2[$FilterNo][$k])^2-4*($TFb0[$FilterNo][$k]*$TFb1[$FilterNo][$k]+4*$TFb0[$FilterNo][$k]*$TFb2[$FilterNo][$k]+$TFb1[$FilterNo][$k]*$TFb2[$FilterNo][$k])*$Phi+16*$TFb0[$FilterNo][$k]*$TFb2[$FilterNo][$k]*$Phi*$Phi$Denominator=(1+$TFa1[$FilterNo][$k]+$TFa2[$FilterNo][$k])^2-4*($TFa1[$FilterNo][$k]+4*$TFa2[$FilterNo][$k]+$TFa1[$FilterNo][$k]*$TFa2[$FilterNo][$k])*$Phi+16*$TFa2[$FilterNo][$k]*$Phi*$Phi
$Gain+=10*Log10($Numerator/$Denominator)NextNextReturn $GainElse
$Numerator=($TFb0[$FilterNo][0]+$TFb1[$FilterNo][0]+$TFb2[$FilterNo][0])^2-4*($TFb0[$FilterNo][0]*$TFb1[$FilterNo][0]+4*$TFb0[$FilterNo][0]*$TFb2[$FilterNo][0]+$TFb1[$FilterNo][0]*$TFb2[$FilterNo][0])*$Phi+16*$TFb0[$FilterNo][0]*$TFb2[$FilterNo][0]*$Phi*$Phi$Denominator=(1+$TFa1[$FilterNo][0]+$TFa2[$FilterNo][0])^2-4*($TFa1[$FilterNo][0]+4*$TFa2[$FilterNo][0]+$TFa1[$FilterNo][0]*$TFa2[$FilterNo][0])*$Phi+16*$TFa2[$FilterNo][0]*$Phi*$PhiReturn10*Log10($Numerator/$Denominator)EndIfEndFunc
I looked at the EQ APO plotter and it does respond to the Windows system sample rate in the same way. When I first glanced at it, I thought it wasn't.
So does this mean the way our programmed EQ filters sound can be affected (albeit slightly) by our sample rate setting?
I'm wondering if the difference between 44k and 192k will start to matter when you have multiple filters set above 8k interacting with each other. Yesterday I was doing just that when I realized my plots (at fs=44k) looked different at a glance from Peace and my RME ADI-2 (fancy DAC with built in EQ).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I wasn't aware of this so it's great to hear that Equalizer APO responds to the sample rate. But there's one major catch. When adding filters in the Configurator Editor or Peace, all these filters will be applied on all devices. But each device could have its own sample rate. Therefore the graph of analysis panel is probably based on the sample rate of the current selected device. I'm guessing here. Could also be a fixed one. This can be checked in the program code.
Yes, the sample rate can influence a filter (as Juha is also pointing out), the most at a lower sample rate say 44100. Fortunately sample rates of devices are set much higher, 96 kHz or 192 kHz. Audio played of a lower sample rate is converted to this higher rate. In other words in general applying filters is okay then. And using a sample rate of 96 kHz for a plot is also okay. If your RME ADI-2 uses a sample rate of 44100 you'll see a noticable difference of course, especially with multiple high frequency filters.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I myself have always used a setting of 192k for my audio. So it's no issue for me. But whenever you see EQ presets posted online (like the Auto EQ project) no one ever mentions the sample rate. So I'm sure there are some other users getting slightly worse EQ results because they left the their sample rate setting as the default.
The ADI-2 DAC will accept any frequncy you throw at it. Interestingly, the built-in plotter doesn't respond to any change in sample rate. I wonder if it's using a different filter method. I don't believe it's upsampling the audio prior to any DSP functions.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The ADI-2 DAC will accept any frequncy you throw at it. Interestingly, the built-in plotter doesn't respond to any change in sample rate. I wonder if it's using a different filter method. I don't believe it's upsampling the audio prior to any DSP functions.
It might also be that ADI-2 uses s-domain filters for its plots so,... as those are continious time filters there aren't that N limit present. To find it out, you could measure responses of the ADI-2 internal filters (loop-back).
Last edit: Juha 2020-05-11
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Your plot looks normal.
Certain type discrete time filters tends to 'skew' when fc closes N (Nyqvist) frequency (fs/2). RBJ-filters also may work differently with quality parameter Q than with BW. This is normal 'effect' but, also it can be improved a bit by using some tweaking methods. Unfortunately you need to go custom IIR filters then which are not CPU friendly in EqualizerAPO.
Thanks for sharing these links. But for my purposes, I need to use whatever methods EQ APO is using. Do you by chance know if there's other parametric EQ software out there using something other than the RBJ filters?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
EqualizerAPO is based on RBJ filters but there's an option for custom IIR filters so you be able to code your own filters (though, its limited scripting language). Here's an example of LPF I did some time ago.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Some Background:
I currently working on generating my own EQ plots. I seem to get the same results as EQ APO if I choose a really large value for sample rate in my calculations. But I don't know how correct that really is.
So my question is what value for variable 'srate' (Sample rate) is EQ APO effectively using? It's not tied to the Windows setting is it?
Refer to BiQuad.cpp for the biquad coefficient equations.
For calculating a plot a fixed sample rate must used but the value itself doesn't matter. This is what I've noticed when creating the graph window of the Peace equalizer interface. But when Equalizer APO is processing the audio (stream) it needs to take the sample rate for the specific device. This sample rate is usually 48 kHz of 96 kHz. In other words, the sample rate is tied to the Windows setting of that specific device. Any deviation and the Biquad filter calculations will fail.
That's interesting. In my own calculations, sample rate does actually have an effect if your F0 frequncy is close to your SampleRate/2. Take a look at my attachement. The 3 curves are peaking filters at 18k, Q=1, dB=6.
I'm using the exact same equations for calculation the Biquad coefficients. But maybe I'm evaluating the transfer function differently?
You're right. When nearing the sample rate/2 the frequency curve does seem different (which is obviously a normal "behavour" according to the calculations). Sorry, I didn't spot that. As example I've attached 2 curves: 44100 and 96000 Hz. The peak filter on 2 kHz isn't affected but the one on 20 kHz is. The same as your curves, I guess, although it looks a bit different, less effect towards the 10 kHz. I'll give my calculation program code below.
One thing has to be noted. Since the sample rate is high (even 44100), the actual difference can't be easily heard. We're talking about frequencies above 10 kHz which our ears having more difficulty with than lower ones. But for accuracy the graph should be according to the set sample rate.
The following AutoIt program code is part of Peace. CalculateCoefficient is a function which needs an input of a filter type, a gain in dB, a frequency and a quality to calculate the coefficients for a BiQuad filter. For your information the filter types are the known ones and also Linkwitz-Riley and Butterworth filters which are built up from low/high pass filters. The second function called GainAtfrequency takes these coefficients to calculate the output gain at a given frequency. This function includes also the calculations for the Linkwitz-Riley and Butterworth filters. Both functions are similar to those of Equalizer APO except in earlier versions of Equalizer APO the Gain At Frequency function had a bug (a wrong sign). I think it's now corrected in Equalizer APO.
I looked at the EQ APO plotter and it does respond to the Windows system sample rate in the same way. When I first glanced at it, I thought it wasn't.
So does this mean the way our programmed EQ filters sound can be affected (albeit slightly) by our sample rate setting?
I'm wondering if the difference between 44k and 192k will start to matter when you have multiple filters set above 8k interacting with each other. Yesterday I was doing just that when I realized my plots (at fs=44k) looked different at a glance from Peace and my RME ADI-2 (fancy DAC with built in EQ).
I wasn't aware of this so it's great to hear that Equalizer APO responds to the sample rate. But there's one major catch. When adding filters in the Configurator Editor or Peace, all these filters will be applied on all devices. But each device could have its own sample rate. Therefore the graph of analysis panel is probably based on the sample rate of the current selected device. I'm guessing here. Could also be a fixed one. This can be checked in the program code.
Yes, the sample rate can influence a filter (as Juha is also pointing out), the most at a lower sample rate say 44100. Fortunately sample rates of devices are set much higher, 96 kHz or 192 kHz. Audio played of a lower sample rate is converted to this higher rate. In other words in general applying filters is okay then. And using a sample rate of 96 kHz for a plot is also okay. If your RME ADI-2 uses a sample rate of 44100 you'll see a noticable difference of course, especially with multiple high frequency filters.
I myself have always used a setting of 192k for my audio. So it's no issue for me. But whenever you see EQ presets posted online (like the Auto EQ project) no one ever mentions the sample rate. So I'm sure there are some other users getting slightly worse EQ results because they left the their sample rate setting as the default.
The ADI-2 DAC will accept any frequncy you throw at it. Interestingly, the built-in plotter doesn't respond to any change in sample rate. I wonder if it's using a different filter method. I don't believe it's upsampling the audio prior to any DSP functions.
It might also be that ADI-2 uses s-domain filters for its plots so,... as those are continious time filters there aren't that N limit present. To find it out, you could measure responses of the ADI-2 internal filters (loop-back).
Last edit: Juha 2020-05-11
I think the developers would actually be happy to anwer questions about their DSP functionality on the RME forum. So I'll probably try that later.
Your plot looks normal.
Certain type discrete time filters tends to 'skew' when fc closes N (Nyqvist) frequency (fs/2). RBJ-filters also may work differently with quality parameter Q than with BW. This is normal 'effect' but, also it can be improved a bit by using some tweaking methods. Unfortunately you need to go custom IIR filters then which are not CPU friendly in EqualizerAPO.
There are few response matching methods you could try:
Massberg https://books.google.fi/books?id=QddcxHLavrMC&pg=PA201&lpg=PA204#v=onepage&q&f=false
Orfandis (check särkkä .../pub/ folder (https://users.aalto.fi/~ssarkka/pub/eq-design-demo.zip)
Vicanek (most filter types) https://vicanek.de/articles/BiquadFits.pdf
Särkkä https://users.aalto.fi/~ssarkka/pub/eq-article.pdf
MZTi (LPF only) https://www.kvraudio.com/forum/viewtopic.php?t=360690
Jackson https://ieeexplore.ieee.org/document/870677?tp=&arnumber=870677
Mecklenbräuker https://www.sciencedirect.com/science/article/abs/pii/S0165168400001134
Nelatury https://www.sciencedirect.com/science/article/abs/pii/S1051200406001424
etc...
EDIT: Here's a plot showing peak filter responses of commonly used methods (BLT, RBJq and RBJbw) against s-domain (analog) model (fs = 44100Hz).
Last edit: Juha 2020-05-11
Thanks for sharing these links. But for my purposes, I need to use whatever methods EQ APO is using. Do you by chance know if there's other parametric EQ software out there using something other than the RBJ filters?
EqualizerAPO is based on RBJ filters but there's an option for custom IIR filters so you be able to code your own filters (though, its limited scripting language). Here's an example of LPF I did some time ago.
Thanks Juha. That should be quite helpful if I decide I want a custom filter later.