void autotest_iirdes_cplxpair_n6() { float tol = 1e-8f; // float complex r[6] = { 0.980066577841242 + 0.198669330795061 * _Complex_I, 5.000000000000000 + 0.000000000000000 * _Complex_I, -0.416146836547142 + 0.909297426825682 * _Complex_I, 0.980066577841242 - 0.198669330795061 * _Complex_I, 0.300000000000000 + 0.000000000000000 * _Complex_I, -0.416146836547142 - 0.909297426825682 * _Complex_I }; float complex p[6]; float complex ptest[6] = { -0.416146836547142 - 0.909297426825682 * _Complex_I, -0.416146836547142 + 0.909297426825682 * _Complex_I, 0.980066577841242 - 0.198669330795061 * _Complex_I, 0.980066577841242 + 0.198669330795061 * _Complex_I, 0.300000000000000 + 0.000000000000000 * _Complex_I, 5.000000000000000 + 0.000000000000000 * _Complex_I }; // compute complex pairs liquid_cplxpair(r,6,1e-6f,p); unsigned int i; if (liquid_autotest_verbose) { printf("complex set:\n"); for (i=0; i<6; i++) printf(" r[%3u] : %12.8f + j*%12.8f\n", i, crealf(r[i]), cimagf(r[i])); printf("complex pairs:\n"); for (i=0; i<6; i++) printf(" p[%3u] : %12.8f + j*%12.8f\n", i, crealf(p[i]), cimagf(p[i])); } // run test for (i=0; i<6; i++) { CONTEND_DELTA( crealf(p[i]), crealf(ptest[i]), tol ); CONTEND_DELTA( cimagf(p[i]), cimagf(ptest[i]), tol ); } }
// converts discrete-time zero/pole/gain (zpk) recursive (iir) // filter representation to second-order sections (sos) form // // _zd : discrete zeros array (size _n) // _pd : discrete poles array (size _n) // _n : number of poles, zeros // _kd : gain // // _B : output numerator matrix (size (L+r) x 3) // _A : output denominator matrix (size (L+r) x 3) // // L is the number of sections in the cascade: // r = _n % 2 // L = (_n - r) / 2; void iirdes_dzpk2sosf(float complex * _zd, float complex * _pd, unsigned int _n, float complex _kd, float * _B, float * _A) { int i; float tol=1e-6f; // tolerance for conjuate pair computation // find/group complex conjugate pairs (poles) float complex zp[_n]; liquid_cplxpair(_zd,_n,tol,zp); // find/group complex conjugate pairs (zeros) float complex pp[_n]; liquid_cplxpair(_pd,_n,tol,pp); // TODO : group pole pairs with zero pairs // _n = 2*L + r unsigned int r = _n % 2; // odd/even order unsigned int L = (_n - r)/2; // filter semi-length #if LIQUID_IIRDES_DEBUG_PRINT printf(" n=%u, r=%u, L=%u\n", _n, r, L); printf("poles :\n"); for (i=0; i<_n; i++) printf(" p[%3u] = %12.8f + j*%12.8f\n", i, crealf(_pd[i]), cimagf(_pd[i])); printf("zeros :\n"); for (i=0; i<_n; i++) printf(" z[%3u] = %12.8f + j*%12.8f\n", i, crealf(_zd[i]), cimagf(_zd[i])); printf("poles (conjugate pairs):\n"); for (i=0; i<_n; i++) printf(" p[%3u] = %12.8f + j*%12.8f\n", i, crealf(pp[i]), cimagf(pp[i])); printf("zeros (conjugate pairs):\n"); for (i=0; i<_n; i++) printf(" z[%3u] = %12.8f + j*%12.8f\n", i, crealf(zp[i]), cimagf(zp[i])); #endif float complex z0, z1; float complex p0, p1; for (i=0; i<L; i++) { p0 = -pp[2*i+0]; p1 = -pp[2*i+1]; z0 = -zp[2*i+0]; z1 = -zp[2*i+1]; // expand complex pole pairs _A[3*i+0] = 1.0; _A[3*i+1] = crealf(p0+p1); _A[3*i+2] = crealf(p0*p1); // expand complex zero pairs _B[3*i+0] = 1.0; _B[3*i+1] = crealf(z0+z1); _B[3*i+2] = crealf(z0*z1); } // add remaining zero/pole pair if order is odd if (r) { p0 = -pp[_n-1]; z0 = -zp[_n-1]; _A[3*i+0] = 1.0; _A[3*i+1] = -pp[_n-1]; _A[3*i+2] = 0.0; _B[3*i+0] = 1.0; _B[3*i+1] = -zp[_n-1]; _B[3*i+2] = 0.0; } // distribute gain equally amongst all feed-forward // coefficients float k = powf( crealf(_kd), 1.0f/(float)(L+r) ); // adjust gain of first element for (i=0; i<L+r; i++) { _B[3*i+0] *= k; _B[3*i+1] *= k; _B[3*i+2] *= k; } }
void autotest_iirdes_cplxpair_n20() { float tol = 1e-8f; // float complex r[20] = { -0.340396183901119 + 1.109902927794652 * _Complex_I, 1.148964416793990 + 0.000000000000000 * _Complex_I, 0.190037889511651 + 0.597517076404221 * _Complex_I, -0.340396183901119 - 1.109902927794652 * _Complex_I, 0.890883293686046 + 0.000000000000000 * _Complex_I, -0.248338528396292 - 0.199390430636670 * _Complex_I, 0.190037889511651 - 0.597517076404221 * _Complex_I, 0.003180396218998 + 0.000000000000000 * _Complex_I, 0.261949046540733 - 0.739400953405199 * _Complex_I, 0.261949046540733 + 0.739400953405199 * _Complex_I, 0.309342570837113 + 0.000000000000000 * _Complex_I, 0.035516103001236 + 0.000000000000000 * _Complex_I, -0.184159864176452 - 0.240335024546875 * _Complex_I, -0.485244526317243 + 0.452251520655749 * _Complex_I, -0.485244526317243 - 0.452251520655749 * _Complex_I, -0.581633365450190 + 0.000000000000000 * _Complex_I, -0.248338528396292 + 0.199390430636670 * _Complex_I, -0.184159864176452 + 0.240335024546875 * _Complex_I, 1.013685316242435 + 0.000000000000000 * _Complex_I, -0.089598596934739 + 0.000000000000000 * _Complex_I }; float complex p[20]; float complex ptest[20] = { -0.485244526317243 - 0.452251520655749 * _Complex_I, -0.485244526317243 + 0.452251520655749 * _Complex_I, -0.340396183901119 - 1.109902927794652 * _Complex_I, -0.340396183901119 + 1.109902927794652 * _Complex_I, -0.248338528396292 - 0.199390430636670 * _Complex_I, -0.248338528396292 + 0.199390430636670 * _Complex_I, -0.184159864176452 - 0.240335024546875 * _Complex_I, -0.184159864176452 + 0.240335024546875 * _Complex_I, 0.190037889511651 - 0.597517076404221 * _Complex_I, 0.190037889511651 + 0.597517076404221 * _Complex_I, 0.261949046540733 - 0.739400953405199 * _Complex_I, 0.261949046540733 + 0.739400953405199 * _Complex_I, -0.581633365450190 + 0.000000000000000 * _Complex_I, -0.089598596934739 + 0.000000000000000 * _Complex_I, 0.003180396218998 + 0.000000000000000 * _Complex_I, 0.035516103001236 + 0.000000000000000 * _Complex_I, 0.309342570837113 + 0.000000000000000 * _Complex_I, 0.890883293686046 + 0.000000000000000 * _Complex_I, 1.013685316242435 + 0.000000000000000 * _Complex_I, 1.148964416793990 + 0.000000000000000 * _Complex_I }; // compute complex pairs liquid_cplxpair(r,20,1e-6f,p); unsigned int i; if (liquid_autotest_verbose) { printf("complex set:\n"); for (i=0; i<20; i++) printf(" r[%3u] : %12.8f + j*%12.8f\n", i, crealf(r[i]), cimagf(r[i])); printf("complex pairs:\n"); for (i=0; i<20; i++) printf(" p[%3u] : %12.8f + j*%12.8f\n", i, crealf(p[i]), cimagf(p[i])); } // run test for (i=0; i<20; i++) { CONTEND_DELTA( crealf(p[i]), crealf(ptest[i]), tol ); CONTEND_DELTA( cimagf(p[i]), cimagf(ptest[i]), tol ); } }