Я пытаюсь создать цифровой фильтр, который создает близкие результаты в спецификацию а-весовой: referenceа-взвешивание в качестве цифрового фильтра
Я уже создал простой низко- и верхние частоты с 2 ем и 6 th заказать фильтры IIR. Я также создал каскадную последовательность второго порядка из трех биквадров. Эти фильтры, похоже, работают достаточно хорошо. Я генерирую коэффициенты с помощью функций октавы/матлаба butter
и tf2sos
. Фильтр реализован на C++ и применяется к моему аудиовходу. Обработанное аудио преобразуется в частотную область и отображается на моем экране.
Теперь мой вопрос, как я могу реализовать фильтр a-weighting. Я уже попробовал код MatLab я нашел в Интернете:
Fs = 44100;
f1 = 20.598997;
f2 = 107.65265;
f3 = 737.86223;
f4 = 12194.217;
A1000 = 1.9997;
pi = 3.14159265358979;
NUMs = [ (2*pi*f4)^2*(10^(A1000/20)) 0 0 0 0 ];
DENs = conv([1 +4*pi*f4 (2*pi*f4)^2],[1 +4*pi*f1 (2*pi*f1)^2]);
DENs = conv(conv(DENs,[1 2*pi*f3]),[1 2*pi*f2]);
[B,A] = bilinear(NUMs,DENs,Fs);
printf('%0.16f\n',A);
1.0000000000000000
5.9999984423677502
14.9999922118394622
19.9999844236803490
14.9999844236817736
5.9999922118415991
0.9999984423684625
printf('%0.16f\n',B);
0.0000000000000000
-0.0000000000000000
-0.0000000000000000
0.0000000000000000
-0.0000000000000000
-0.0000000000000000
0.0000000000000000
эти коэффициенты выглядят странно, а они не работают с моей 6-й порядка IIR. Поэтому я попытался создать каскадные биквады:
sos = tf2sos(B,A);
printf('%0.16f\n',sos);
0.0000000000000000
1.0000000000000000
1.0000000000000000
-0.0000000000000000
-2.0001419687327253
1.9999999999999987
0.0000000000000000
1.0001419788113322
0.9999999999999984
1.0000000000000000
1.0000000000000000
1.0000000000000000
2.0044328398652649
1.9955456521230652
2.0000199503794249
1.0044526299594496
0.9955653535664766
1.0000002046824734
, но эти коэффициенты также не работают. Может быть, потому, что коэффициенты ошибочны в первую очередь?
Может кто-нибудь указать мне, как правильно реализовать цифровой весовой фильтр?
EDIT: Благодаря ответ SleuthEye в поле ниже, я мог бы реализовать а-взвешивающий фильтр с правильными коэффициентами из октавы.
Я нашел множество различных реализаций фильтра C++ в Интернете и в приложениях-генераторах win32-фильтров, но они казались все непоследовательными.
Наконец, я нашел два кодовых фрагментов, которые в основном работают таким же образом:
https://github.com/berndporr/iir1/blob/master/iir/State.h (также канал YouTube: https://www.youtube.com/user/DSPcourse)
http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ (а и б поменяны местами здесь)
Так что я в основном скопировал код оттуда и закончил с этим: (его транспонированная прямая реализация II)
Определение:
class Biquad{
public:
Biquad(double a0, double a1, double a2, double b0, double b1, double b2) {
this->a0 = a0;
this->a1 = a1;
this->a2 = a2;
this->b0 = b0;
this->b1 = b1;
this->b2 = b2;
z1 = z2 = 0.0;
}
double filter(double in) {
double out = z1 + b0 * in;
z1 = z2 + b1 * in - a1 * out;
z2 = b2 * in - a2 * out;
return out;
}
private:
double a0, a1, a2, b0, b1, b2;
double z1, z2;
};
Initialization:
Biquad *a1Filter = new Biquad(1.0000000, -0.1405361, 0.0049376, 0.2557411, -0.5114387, 0.2556976);
Biquad *a2Filter = new Biquad(1.0000000, -1.8849012, 0.8864215, 1.0000000, -2.0001702, 1.0001702);
Biquad *a3Filter = new Biquad(1.0000000, -1.9941389, 0.9941475, 1.0000000, 2.0000000, 1.0000000);
Призвание:
double outputValue = a3Filter->filter(a2Filter->filter(a1Filter->filter(inputValue)));
Спасибо, что на самом деле сделал трюк! –
Обратите внимание, что билинейное преобразование приводит к тому, что красный сбрасывается быстрее, чем синий, вводя погрешность измерения. Простое исправление заключается в том, чтобы [сначала выполнить выборку данных] (https://www.vocal.com/echo-cancellation/a-and-c-weighting-via-bilinear-transform/). Другие подходы здесь: https://dsp.stackexchange.com/q/36077/29 – endolith