#include #include "const.h" #include "IIRFilter.h" void IIRFilter::call_peaking_eq_with_lowfreq(double fc, double gain, double q, int fs , double* coef_b, double* coef_a) { double A, H, k; double a, d; double f2, f1; double ftemp = 0.0; double bw; ftemp = sqrt(1 + 1 / (4 * q * q)); f1 = fc * (ftemp - 0.5 / q); f2 = fc * (ftemp + 0.5 / q); if (f2 > 22000) f2 = 22000; bw = f2 - f1; if (bw < 0.1) bw = 0.1; A = pow(10, (gain * 0.05)); k = tan(pi * bw / fs); if (A < 1.0) a = (k - A) / (k + A); else a = (k - 1) / (k + 1); H = (A - 1) / 2; d = -cos(2 * pi * fc / fs); coef_b[0] = 1 + (1 + a) * H; coef_b[1] = d * (1 - a); coef_b[2] = (-a - (coef_b[0] - 1)); //( - a - (1 + a) * H / 2); coef_a[0] = 1; coef_a[1] = coef_b[1]; coef_a[2] = -a; } void IIRFilter::call_peaking_eq(double fc, double gain, double q, int fs, double* coef_b, double* coef_a) { double bw; double deltaw; double g0, g, gb; double beta; double w0; double f2, f1; double ftemp; if (gain<0.1 && gain>-0.1) { coef_b[0] = coef_a[0] = 1; coef_b[1] = coef_b[2] = coef_a[1] = coef_a[2] = 0; return; } if (fc < 100) return call_peaking_eq_with_lowfreq(fc, gain, q, fs, coef_b, coef_a); //bw = fc / q; //if (bw >= fs / 2) bw = fs / 2 - 100; ftemp = sqrt(1 + 1 / (4 * q * q)); f1 = fc * (ftemp - 0.5 / q); f2 = fc * (ftemp + 0.5 / q); if (f2 >= fs / 2.0f) f2 = fs / 2.0f - 100.0f; bw = f2 - f1; w0 = 2 * pi * fc / fs; deltaw = 2 * pi * bw / fs; g0 = 1.0; g = pow(10, (gain / 20)) * g0; if (fabs(gain) <= 6) { gb = pow(10, gain / 40); } else if (gain > 0) { gb = pow(10, (gain - 3) / 20); //·åÖµÒÔÏÂ-3dB´¦´ø¿í } else { gb = pow(10, (gain + 3) / 20); //·åÖµÒÔÉÏ3dB´¦´ø¿í } beta = sqrt((gb * gb - g0 * g0) / (g * g - gb * gb)) * tan(deltaw / 2); coef_a[0] = 1; coef_a[1] = -2 * (cos(w0) / (1 + beta)); coef_a[2] = (1 - beta) / (1 + beta); coef_b[0] = (g0 + g * beta) / (1 + beta); coef_b[1] = -2 * (g0 * cos(w0) / (1 + beta)); coef_b[2] = (g0 - g * beta) / (1 + beta); } int IIRFilter::eq(IIRBANDType type, int f0, double g, double q, int fs, double(*sos)[6]) { double A = sqrt(pow(10, g * 0.05)); double w0 = 2 * pi * f0 / fs; double alpha = sin(w0) / (2 * q); double* b = sos[0]; double* a = sos[0] + 3; switch (type) { case lowpass: A = pow(10, g * 0.05); b[0] = A * (1 - cos(w0)) / 2; b[1] = A * (1 - cos(w0)); b[2] = A * (1 - cos(w0)) / 2; a[0] = 1 + alpha; a[1] = -2 * cos(w0); a[2] = 1 - alpha; break; case highpass: A = pow(10, g * 0.05); b[0] = A * (1 + cos(w0)) / 2; b[1] = -A * (1 + cos(w0)); b[2] = A * (1 + cos(w0)) / 2; a[0] = 1 + alpha; a[1] = -2 * cos(w0); a[2] = 1 - alpha; break; case bpf_pq: break; case bpf_zero: break; case notch: { double w0 = 2 * pi * f0 / fs; double alpha = sin(w0) / (2 * q); double A = pow(10.0, g / 40.0); // gain/40 ¶ø²»ÊÇ gain/20 // ·Ö×ÓϵÊý b[0] = 1.0 + alpha * A; b[1] = -2.0 * cos(w0); b[2] = 1.0 - alpha * A; // ·ÖĸϵÊý a[0] = 1.0 + alpha / A; a[1] = -2.0 * cos(w0); a[2] = 1.0 - alpha / A; } break; case apf: A = pow(10, g * 0.05); b[0] = A * (1 - alpha); b[1] = A * -2 * cos(w0); b[2] = A * (1 + alpha); a[0] = 1 + alpha; a[1] = -2 * cos(w0); a[2] = 1 - alpha; break; case peaking_eq: call_peaking_eq(f0, g, q, fs, b, a); break; case lowshelf: { double cosw, sqrta; A = pow(10, g * 0.025); cosw = cos(w0); sqrta = 2 * sqrt(A) * alpha; b[0] = A * ((A + 1) - (A - 1) * cosw + sqrta); b[1] = 2 * A * ((A - 1) - (A + 1) * cosw); b[2] = A * ((A + 1) - (A - 1) * cosw - sqrta); a[0] = (A + 1) + (A - 1) * cosw + sqrta; a[1] = -2 * ((A - 1) + (A + 1) * cosw); a[2] = (A + 1) + (A - 1) * cosw - sqrta; } break; case highshelf: { double cosw, sqrta; A = pow(10, g * 0.025); cosw = cos(w0); sqrta = 2 * sqrt(A) * alpha; b[0] = A * ((A + 1) + (A - 1) * cosw + sqrta); b[1] = -2 * A * ((A - 1) + (A + 1) * cosw); b[2] = A * ((A + 1) + (A - 1) * cosw - sqrta); a[0] = (A + 1) - (A - 1) * cosw + sqrta; a[1] = 2 * ((A - 1) - (A + 1) * cosw); a[2] = (A + 1) - (A - 1) * cosw - sqrta; } break; default: return ret_param_error; break; } return ret_success; } int IIRFilter::butters(IIRBANDType type, int n, int fc, int fs, double g, double(*sos)[6]) { double wc = tan(2 * pi * fc / fs / 2); double w; double re_p[8], im_p[8]; int i, nsection; double a1; double re_m, re_k, im_m, im_k; nsection = (n + 1) / 2; for (i = 0; i < n; i++) { w = (pi * (n + 2 * i + 1) / (2 * n)); re_p[i] = wc * cos(w); im_p[i] = wc * sin(w); } if (type == IIRBANDType::lowpass) { for (i = 0; i < nsection; i++) { if (i == n - i - 1) { a1 = 1 - re_p[i]; sos[i][0] = wc / a1; sos[i][1] = wc / a1; sos[i][2] = 0; sos[i][3] = 1; sos[i][4] = (-re_p[i] - 1) / a1; sos[i][5] = 0; } else { re_m = re_p[i] * re_p[n - i - 1] - im_p[i] * im_p[n - i - 1]; im_m = re_p[i] * im_p[n - i - 1] + im_p[i] * re_p[n - i - 1]; re_k = re_p[i] + re_p[n - i - 1]; im_k = im_p[i] + im_p[n - i - 1]; a1 = 1 - re_k + re_m; sos[i][0] = wc * wc / a1; sos[i][1] = 2 * wc * wc / a1; sos[i][2] = wc * wc / a1; sos[i][3] = 1; sos[i][4] = (2 * re_m - 2) / a1; sos[i][5] = (re_m + re_k + 1) / a1; } } } else if (type == IIRBANDType::highpass) { for (i = 0; i < nsection; i++) { if (i == n - i - 1) { a1 = wc * wc - re_p[i]; sos[i][0] = wc / a1; sos[i][1] = -wc / a1; sos[i][2] = 0; sos[i][3] = 1; sos[i][4] = (wc * wc + re_p[i]) / a1; sos[i][5] = 0; } else { re_m = re_p[i] * re_p[n - i - 1] - im_p[i] * im_p[n - i - 1]; im_m = re_p[i] * im_p[n - i - 1] + im_p[i] * re_p[n - i - 1]; re_k = re_p[i] + re_p[n - i - 1]; im_k = im_p[i] + im_p[n - i - 1]; a1 = wc * wc * wc * wc - re_k * wc * wc + re_m; sos[i][0] = wc * wc / a1; sos[i][1] = -2 * wc * wc / a1; sos[i][2] = wc * wc / a1; sos[i][3] = 1; sos[i][4] = (2 * wc * wc * wc * wc - 2 * re_m) / a1; sos[i][5] = (wc * wc * wc * wc + re_k * wc * wc + re_m) / a1; } } } g = pow(10.0, g / 20.0); sos[0][0] *= g; sos[0][1] *= g; sos[0][2] *= g; return nsection; } int IIRFilter::linkwitzs(IIRBANDType type, int n, int fc, int fs, double g, double(*sos)[6]) { double q[5]; double wc = tan(2 * pi * fc / fs / 2); int i; int nsection = n / 2; double a1; switch (n) { case 2: q[0] = 1 / 0.5; break; case 4: q[0] = 1 / 0.71; q[1] = 1 / 0.71; break; case 6: q[0] = 1 / 0.5; q[1] = 1.0; q[2] = 1.0; break; case 8: q[0] = 1 / 0.54; q[1] = 1 / 1.34; q[2] = 1 / 0.54; q[3] = 1 / 1.34; break; case 10: q[0] = 1 / 0.5; q[1] = 1 / 0.62; q[2] = 1 / 1.62; q[3] = 1 / 0.62; q[4] = 1 / 1.62; break; } if (type == IIRBANDType::lowpass) { for (i = 0; i < nsection; i++) { a1 = 1 + q[i] * wc + wc * wc; sos[i][0] = wc * wc / a1; sos[i][1] = 2 * wc * wc / a1; sos[i][2] = wc * wc / a1; sos[i][3] = 1; sos[i][4] = (2 * wc * wc - 2) / a1; sos[i][5] = (wc * wc - q[i] * wc + 1) / a1; } } else if (type == IIRBANDType::highpass) { for (i = 0; i < nsection; i++) { a1 = 1 + q[i] * wc + wc * wc; sos[i][0] = 1 / a1; sos[i][1] = -2 / a1; sos[i][2] = 1 / a1; sos[i][3] = 1; sos[i][4] = (2 * wc * wc - 2) / a1; sos[i][5] = (wc * wc - q[i] * wc + 1) / a1; } } g = pow(10.0, g / 20.0); sos[0][0] *= g; sos[0][1] *= g; sos[0][2] *= g; return nsection; } int IIRFilter::bessels(IIRBANDType type, int n, int fc, int fs, double g, double(*sos)[6]) { int nsection = (n + 1) / 2; double wc = tan(2 * pi * fc / fs / 2); double re_p[8],im_p[8]; int i; double a1; double constant[] = { 1.0, 1.272, 1.413, 1.533, 1.613, 1.735, 1.804, 1.956 }; int k = 0; if (n == 1) { re_p[0] = -1; im_p[0] = 0; } else if (n == 2) { re_p[0] = -.8660254037844386467637229; im_p[0] = .4999999999999999999999996; re_p[1] = -.8660254037844386467637229; im_p[1] = -.4999999999999999999999996; } else if (n == 3) { re_p[0] = -.9416000265332067855971980; im_p[0] = 0; re_p[1] = -.7456403858480766441810907; im_p[1] = -.7113666249728352680992154; re_p[2] = -.7456403858480766441810907; im_p[2] = .7113666249728352680992154; } else if (n == 4) { re_p[0] = -.6572111716718829545787781; im_p[0] = -.8301614350048733772399715; re_p[1] = -.6572111716718829545787788; im_p[1] = .8301614350048733772399715; re_p[2] = -.9047587967882449459642637; im_p[2] = -.2709187330038746636700923; re_p[3] = -.9047587967882449459642624; im_p[3] = .2709187330038746636700926; } else if (n == 5) { re_p[0] = -.9264420773877602247196260; im_p[0] = 0; re_p[1] = -.8515536193688395541722677; im_p[1] = -.4427174639443327209850002; re_p[2] = -.8515536193688395541722677; im_p[2] = .4427174639443327209850002; re_p[3] = -.5905759446119191779319432; im_p[3] = -.9072067564574549539291747; re_p[4] = -.5905759446119191779319432; im_p[4] = .9072067564574549539291747; } else if (n == 6) { re_p[0] = -.9093906830472271808050953; im_p[0] = -.1856964396793046769246397; re_p[1] = -.9093906830472271808050953; im_p[1] = .1856964396793046769246397; re_p[2] = -.7996541858328288520243325; im_p[2] = -.5621717346937317988594118; re_p[3] = -.7996541858328288520243325; im_p[3] = .5621717346937317988594118; re_p[4] = -.5385526816693109683073792; im_p[4] = -.9616876881954277199245657; re_p[5] = -.5385526816693109683073792; im_p[5] = .9616876881954277199245657; } else if (n == 7) { re_p[0] = -.9194871556490290014311619; ; im_p[0] = 0; re_p[1] = -.8800029341523374639772340; im_p[1] = -.3216652762307739398381830; re_p[2] = -.8800029341523374639772340; im_p[2] = .3216652762307739398381830; re_p[3] = -.7527355434093214462291616; im_p[3] = -.6504696305522550699212995; re_p[4] = -.7527355434093214462291616; im_p[4] = .6504696305522550699212995; re_p[5] = -.4966917256672316755024763; im_p[5] = -1.002508508454420401230220; re_p[6] = -.4966917256672316755024763; im_p[6] = 1.002508508454420401230220; } else if (n == 8) { re_p[0] = -.9096831546652910216327629; im_p[0] = -.1412437976671422927888150; re_p[1] = -.9096831546652910216327629; im_p[1] = .1412437976671422927888150; re_p[2] = -.8473250802359334320103023; im_p[2] = -.4259017538272934994996429; re_p[3] = -.8473250802359334320103023; im_p[3] = .4259017538272934994996429; re_p[4] = -.7111381808485399250796172; im_p[4] = -.7186517314108401705762571; re_p[5] = -.7111381808485399250796172; im_p[5] = .7186517314108401705762571; re_p[6] = -.4621740412532122027072175; im_p[6] = -1.034388681126901058116589; re_p[7] = -.4621740412532122027072175; im_p[7] = 1.034388681126901058116589; } if (type == IIRBANDType::lowpass) { wc = wc / constant[n - 1]; if ((n & 1) == 1) { a1 = wc - re_p[0]; sos[k][0] = 1 / a1; sos[k][1] = -1 / a1; sos[k][2] = 0; sos[k][3] = 1; sos[k][4] = (re_p[0] + wc) / a1; sos[k][5] = 0; k = 1; } for (i = k; i < n; i += 2) { double re_s, re_m, im_s, im_m; re_m = re_p[i] * re_p[i + 1] - im_p[i] * im_p[i + 1]; im_m = re_p[i] * im_p[i + 1] + im_p[i] * re_p[i + 1]; re_s = re_p[i] + re_p[i + 1]; im_s = im_p[i] + im_p[i + 1]; a1 = wc * wc - re_s * wc + re_m; sos[k][0] = 1 / a1; sos[k][1] = -2 / a1; sos[k][2] = 1 / a1; sos[k][3] = 1; sos[k][4] = (2 * wc * wc - 2 * re_m) / a1; sos[k][5] = (wc * wc + re_s * wc + re_m) / a1; k = k + 1; } } else if (type == IIRBANDType::highpass) { wc = wc * constant[n - 1]; if ((n & 1) == 1) { a1 = 1 - re_p[0] * wc; sos[k][0] = wc / a1; sos[k][1] = wc / a1; sos[k][2] = 0; sos[k][3] = 1; sos[k][4] = (-re_p[0] * wc - 1) / a1; sos[k][5] = 0; k = 1; } for (i = k; i < n; i += 2) { double re_s, re_m, im_s, im_m; re_m = re_p[i] * re_p[i + 1] - im_p[i] * im_p[i + 1]; im_m = re_p[i] * im_p[i + 1] + im_p[i] * re_p[i + 1]; re_s = re_p[i] + re_p[i + 1]; im_s = im_p[i] + im_p[i + 1]; a1 = 1 - re_s * wc + re_m * wc * wc; sos[k][0] = wc * wc / a1; sos[k][1] = 2 * wc * wc / a1; sos[k][2] = wc * wc / a1; sos[k][3] = 1; sos[k][4] = (2 * re_m * wc * wc - 2) / a1; sos[k][5] = (re_m * wc * wc + re_s * wc + 1) / a1; k = k + 1; } } g = pow(10.0, g / 20.0); sos[0][0] *= g; sos[0][1] *= g; sos[0][2] *= g; return nsection; }