r4034 - trunk/bse
- From: timj svn gnome org
- To: svn-commits-list gnome org
- Subject: r4034 - trunk/bse
- Date: Sun, 29 Oct 2006 18:49:46 -0500 (EST)
Author: timj
Date: 2006-10-29 18:49:45 -0500 (Sun, 29 Oct 2006)
New Revision: 4034
Added:
trunk/bse/bsefilter.h
Removed:
trunk/bse/bseellipticfilter.c
trunk/bse/bseellipticfilter.h
Modified:
trunk/bse/bsefilter-ellf.c
Log:
Mon Oct 30 00:47:23 2006 Tim Janik <timj gtk org>
* bsefilter.h: new header for offering a unified IIR filter API.
* bsefilter-ellf.c: define _GNU_SOURCE instead of _ISOC99_SOURCE before
including any headers. this gets us the C99 API *and* GNU features
(i.e. the uint typedef).
split up the implementation so that the current stand-alone behavior
is preserved if ELLF_BEHAVIOR is defined and so that the necessary
contents from bseellipticfilter.h are inlined otherwise.
moved EllfDesignState here (from bseellipticfilter.h). renamed
EllfComplex.
_bse_filter_design_ellf(): implemented library function prototyped
in bsefilter.h to design butterworth, chebychev1 and elliptic filters.
* bseellipticfilter.h, bseellipticfilter.c: removed.
Deleted: trunk/bse/bseellipticfilter.c
===================================================================
--- trunk/bse/bseellipticfilter.c 2006-10-29 21:28:10 UTC (rev 4033)
+++ trunk/bse/bseellipticfilter.c 2006-10-29 23:49:45 UTC (rev 4034)
@@ -1,1873 +0,0 @@
-/* BSE - Bedevilled Sound Engine
- * Copyright (C) 2006 Tim Janik
- * Copyright (C) 1984, 1987, 1988, 1989, 1995, 2000 Stephen L. Moshier
- *
- * This software is provided "as is"; redistribution and modification
- * is permitted, provided that the following disclaimer is retained.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * In no event shall the authors or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even
- * if advised of the possibility of such damage.
- */
-#include "bseellipticfilter.h"
-#define _ISOC99_SOURCE /* for INFINITY and NAN */
-#include <math.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-static void __attribute__ ((__format__ (__printf__, 1, 2)))
-VERBOSE (const char *format,
- ...)
-{
- char buffer[4096];
- va_list args;
- va_start (args, format);
- vsnprintf (buffer, sizeof (buffer), format, args);
- va_end (args);
- printf ("# %s", buffer);
- fflush (stdout);
-}
-
-#define EVERBOSE VERBOSE
-//#define EVERBOSE(...) do{}while (0)
-
-#if 0 // FIXME: increase precision by using:
-
-//#include "bseieee754.h"
-#define PI (3.141592653589793238462643383279502884197) // pi
-#define BSE_PI_DIV_2 (1.570796326794896619231321691639751442099) // pi/2
-#define BSE_DOUBLE_EPSILON (1.1102230246251565404236316680908203125e-16) /* 2^-53, round-off error at 1.0 */
-#define BSE_DOUBLE_MAX_NORMAL (1.7976931348623157e+308) /* 7fefffff ffffffff, 2^1024 * (1 - BSE_DOUBLE_EPSILON) */
-
-
-
-
-#define DECIBELL_FACTOR (4.3429448190325182765112891891661) /* 10.0 / ln (10.0) */
-#define MACHEP (BSE_DOUBLE_EPSILON) /* the machine roundoff error */
-// #define PI /* PI is defined in bseieee754.h */
-#define PIO2 (BSE_PI_DIV_2) /* pi/2 */
-#define MAXNUM (BSE_DOUBLE_MAX_NORMAL) /* 2**1024*(1-MACHEP) */
-static void init_constants (void) {}
-
-#else
-
-static double DECIBELL_FACTOR = -1;
-static void
-init_constants (void)
-{
- DECIBELL_FACTOR = 10.0 / log (10.0);
-}
-static const double MAXNUM = 1.79769313486231570815E308; /* 2**1024*(1-MACHEP) */
-static const double PI = 3.14159265358979323846; /* pi */
-static const double PIO2 = 1.57079632679489661923; /* pi/2 */
-static const double MACHEP = 1.11022302462515654042E-16; /* 2**-53 */
-#endif
-
-/* This code calculates design coefficients for
- * digital filters of the Butterworth, Chebyshev, or
- * elliptic varieties.
- *
- * The program displays relevant pass band and stop band edge
- * frequencies and stop band attenuation. The z-plane coefficients
- * are printed in these forms:
- * Numerator and denominator z polynomial coefficients
- * Pole and zero locations
- * Polynomial coefficients of quadratic factors
- *
- * After giving all the coefficients, the program prints a
- * table of the frequency response of the filter. You can
- * get a picture by reading the table into gnuplot.
- *
- * Filter design:
- *
- * The output coefficients of primary interest are shown as follows:
- *
- * (z-plane pole location:)
- * pole 3.0050282041410E-001 9.3475816516366E-001
- * (quadratic factors:)
- * q. f.
- * z**2 9.6407477241696E-001
- * z**1 -6.0100564082819E-001
- * (center frequency, gain at f0, and gain at 0 Hz:)
- * f0 2.00496167E+003 gain 2.9238E+001 DC gain 7.3364E-001
- *
- * zero 1.7886295237392E-001 9.8387399816648E-001
- * q. f.
- * z**2 1.0000000000000E+000
- * z**1 -3.5772590474783E-001
- * f0 2.21379064E+003 gain 0.0000E+000 DC gain 1.6423E+000
- *
- * To make a biquad filter from this, the equation for the
- * output y(i) at the i-th sample as a function of the input
- * x(i) at the i-th sample is
- *
- * y(i) + -6.0100564082819E-001 y(i-1) + 9.6407477241696E-001 y(i-2)
- * = x(i) + -3.5772590474783E-001 x(i-1) + 1.0000000000000E+000 x(i-2).
- *
- * Thus the two coefficients for the pole would normally be
- * negated in a typical implementation of the filter.
- *
- * References:
- *
- * A. H. Gray, Jr., and J. D. Markel, "A Computer Program for
- * Designing Digital Elliptic Filters", IEEE Transactions on
- * Acoustics, Speech, and Signal Processing 6, 529-538
- * (December, 1976)
- *
- * B. Gold and C. M. Rader, Digital Processing of Signals,
- * McGraw-Hill, Inc. 1969, pp 61-90
- *
- * M. Abramowitz and I. A. Stegun, eds., Handbook of Mathematical
- * Functions, National Bureau of Standards AMS 55, 1964,
- * Chapters 16 and 17
- */
-
-/* --- prototypes --- */
-static const Complex COMPLEX_ONE = {1.0, 0.0};
-static double Cabs (const Complex *z);
-static void Cadd (const Complex *a, const Complex *b, Complex *c);
-static void Cdiv (const Complex *a, const Complex *b, Complex *c);
-static void Cmov (const Complex *a, Complex *b);
-static void Cmul (const Complex *a, const Complex *b, Complex *c);
-static void Csqrt (const Complex *z, Complex *w);
-static void Csub (const Complex *a, const Complex *b, Complex *c);
-static double polevl (double x, const double coef[], int N);
-static double ellik (double phi, double m); // incomplete elliptic integral of the first kind
-static double ellpk (double x); // complete elliptic integral of the first kind
-static int ellpj (double u, double m, double *sn, double *cn, double *dn, double *ph); // Jacobian Elliptic Functions
-static int math_set_error (char *name, int code);
-
-/* --- math errors --- */
-static int math_global_error = 0;
-#define MATH_ERROR_DOMAIN 1 /* argument domain error */
-#define MATH_ERROR_SING 2 /* argument singularity */
-#define MATH_ERROR_OVERFLOW 3 /* overflow range error */
-#define MATH_ERROR_UNDERFLOW 4 /* underflow range error */
-#define MATH_ERROR_TOTAL_LOSS 5 /* total loss of precision */
-#define MATH_ERROR_PARTIAL_LOSS 6 /* partial loss of precision */
-
-/* Common error handling routine
- *
- * SYNOPSIS:
- * char *fctnam;
- * int code;
- * int math_set_error();
- *
- * math_set_error(fctnam, code);
- *
- * DESCRIPTION:
- * This routine may be called to report one of the following
- * error conditions (in the include file mconf.h).
- * Mnemonic Value Significance
- * MATH_ERROR_DOMAIN 1 argument domain error
- * MATH_ERROR_SING 2 function singularity
- * MATH_ERROR_OVERFLOW 3 overflow range error
- * MATH_ERROR_UNDERFLOW 4 underflow range error
- * MATH_ERROR_TOTAL_LOSS 5 total loss of precision
- * MATH_ERROR_PARTIAL_LOSS 6 partial loss of precision
- *
- * The default version of the file prints the function name,
- * passed to it by the pointer fctnam, followed by the
- * error condition. The display is directed to the standard
- * output device. The routine then returns to the calling
- * program. Users may wish to modify the program to abort by
- * calling exit() under severe error conditions such as domain
- * errors.
- *
- * Since all error conditions pass control to this function,
- * the display may be easily changed, eliminated, or directed
- * to an error logging device.
- */
-static int
-math_set_error (char *name, int code)
-{
- /* Notice: the order of appearance of the following
- * messages is bound to the error codes defined
- * in mconf.h.
- */
- static const char *ermsg[7] = {
- "unknown", /* error code 0 */
- "domain", /* error code 1 */
- "singularity", /* et seq. */
- "overflow",
- "underflow",
- "total loss of precision",
- "partial loss of precision"
- };
-
- /* Display string passed by calling program,
- * which is supposed to be the name of the
- * function in which the error occurred:
- */
- printf ("\n%s ", name); // FIXME
-
- /* Set global error message word */
- math_global_error = code;
-
- /* Display error message defined
- * by the code argument.
- */
- if ((code <= 0) || (code >= 7))
- code = 0;
- printf ("%s error\n", ermsg[code]);
-
- /* Return to calling
- * program
- */
- return 0;
-}
-
-/* --- complex number arithmetic --- */
-/* c = b + a */
-static void
-Cadd (const Complex *a, const Complex *b, Complex *c)
-{
- c->r = b->r + a->r;
- c->i = b->i + a->i;
-}
-
-/* c = b - a */
-static void
-Csub (const Complex *a, const Complex *b, Complex *c)
-{
- c->r = b->r - a->r;
- c->i = b->i - a->i;
-}
-
-/* c = b * a */
-static void
-Cmul (const Complex *a, const Complex *b, Complex *c)
-{
- /* Multiplication:
- * c.r = b.r * a.r - b.i * a.i
- * c.i = b.r * a.i + b.i * a.r
- */
- double y;
- y = b->r * a->r - b->i * a->i;
- c->i = b->r * a->i + b->i * a->r;
- c->r = y;
- /* see Cdiv() for accuracy comments */
-}
-
-/* c = b / a */
-static void
-Cdiv (const Complex *a, const Complex *b, Complex *c)
-{
- /* Division:
- * d = a.r * a.r + a.i * a.i
- * c.r = (b.r * a.r + b.i * a.i)/d
- * c.i = (b.i * a.r - b.r * a.i)/d
- */
- double y = a->r * a->r + a->i * a->i;
- double p = b->r * a->r + b->i * a->i;
- double q = b->i * a->r - b->r * a->i;
-
- if (y < 1.0)
- {
- double w = MAXNUM * y;
- if ((fabs (p) > w) || (fabs (q) > w) || (y == 0.0))
- {
- c->r = MAXNUM;
- c->i = MAXNUM;
- math_set_error ("Cdiv", MATH_ERROR_OVERFLOW);
- return;
- }
- }
- c->r = p/y;
- c->i = q/y;
- /* ACCURACY:
- * In DEC arithmetic, the test (1/z) * z = 1 had peak relative
- * error 3.1e-17, rms 1.2e-17. The test (y/z) * (z/y) = 1 had
- * peak relative error 8.3e-17, rms 2.1e-17.
- * Tests in the rectangle {-10,+10}:
- * Relative error:
- * arithmetic function # trials peak rms
- * DEC Cadd 10000 1.4e-17 3.4e-18
- * IEEE Cadd 100000 1.1e-16 2.7e-17
- * DEC Csub 10000 1.4e-17 4.5e-18
- * IEEE Csub 100000 1.1e-16 3.4e-17
- * DEC Cmul 3000 2.3e-17 8.7e-18
- * IEEE Cmul 100000 2.1e-16 6.9e-17
- * DEC Cdiv 18000 4.9e-17 1.3e-17
- * IEEE Cdiv 100000 3.7e-16 1.1e-16
- */
-}
-
-/* b = a */
-static void
-Cmov (const Complex *a, Complex *b)
-{
- *b = *a;
-}
-
-/* Cabs() - Complex absolute value
- *
- * SYNOPSIS:
- * double Cabs();
- * Complex z;
- * double a;
- *
- * a = Cabs (&z);
- *
- * DESCRIPTION:
- * If z = x + iy
- * then
- * a = sqrt (x**2 + y**2).
- * Overflow and underflow are avoided by testing the magnitudes
- * of x and y before squaring. If either is outside half of
- * the floating point full scale range, both are rescaled.
- *
- * ACCURACY:
- * Relative error:
- * arithmetic domain # trials peak rms
- * DEC -30,+30 30000 3.2e-17 9.2e-18
- * IEEE -10,+10 100000 2.7e-16 6.9e-17
- */
-static double
-Cabs (const Complex *z)
-{
- /* exponent thresholds for IEEE doubles */
- const double PREC = 27;
- const double MAXEXP = 1024;
- const double MINEXP = -1077;
-
- double x, y, b, re, im;
- int ex, ey, e;
-
- /* Note, Cabs (INFINITY,NAN) = INFINITY. */
- if (z->r == INFINITY || z->i == INFINITY
- || z->r == -INFINITY || z->i == -INFINITY)
- return INFINITY;
-
- if (isnan (z->r))
- return z->r;
- if (isnan (z->i))
- return z->i;
-
- re = fabs (z->r);
- im = fabs (z->i);
-
- if (re == 0.0)
- return im;
- if (im == 0.0)
- return re;
-
- /* Get the exponents of the numbers */
- x = frexp (re, &ex);
- y = frexp (im, &ey);
-
- /* Check if one number is tiny compared to the other */
- e = ex - ey;
- if (e > PREC)
- return re;
- if (e < -PREC)
- return im;
-
- /* Find approximate exponent e of the geometric mean. */
- e = (ex + ey) >> 1;
-
- /* Rescale so mean is about 1 */
- x = ldexp (re, -e);
- y = ldexp (im, -e);
-
- /* Hypotenuse of the right triangle */
- b = sqrt (x * x + y * y);
-
- /* Compute the exponent of the answer. */
- y = frexp (b, &ey);
- ey = e + ey;
-
- /* Check it for overflow and underflow. */
- if (ey > MAXEXP)
- {
- math_set_error ("Cabs", MATH_ERROR_OVERFLOW);
- return INFINITY;
- }
- if (ey < MINEXP)
- return 0.0;
-
- /* Undo the scaling */
- b = ldexp (b, e);
- return b;
-}
-
-/* Csqrt() - Complex square root
- *
- * SYNOPSIS:
- * void Csqrt();
- * Complex z, w;
- * Csqrt (&z, &w);
- *
- * DESCRIPTION:
- * If z = x + iy, r = |z|, then
- * 1/2
- * Im w = [ (r - x)/2 ] ,
- * Re w = y / 2 Im w.
- *
- * Note that -w is also a square root of z. The root chosen
- * is always in the upper half plane.
- * Because of the potential for cancellation error in r - x,
- * the result is sharpened by doing a Heron iteration
- * (see sqrt.c) in complex arithmetic.
- *
- * ACCURACY:
- * Relative error:
- * arithmetic domain # trials peak rms
- * DEC -10,+10 25000 3.2e-17 9.6e-18
- * IEEE -10,+10 100000 3.2e-16 7.7e-17
- * 2
- * Also tested by Csqrt (z) = z, and tested by arguments
- * close to the real axis.
- */
-static void
-Csqrt (const Complex *z, Complex *w)
-{
- Complex q, s;
- double x, y, r, t;
-
- x = z->r;
- y = z->i;
-
- if (y == 0.0)
- {
- if (x < 0.0)
- {
- w->r = 0.0;
- w->i = sqrt (-x);
- return;
- }
- else
- {
- w->r = sqrt (x);
- w->i = 0.0;
- return;
- }
- }
-
- if (x == 0.0)
- {
- r = fabs (y);
- r = sqrt (0.5*r);
- if (y > 0)
- w->r = r;
- else
- w->r = -r;
- w->i = r;
- return;
- }
-
- /* Approximate sqrt (x^2+y^2) - x = y^2/2x - y^4/24x^3 + ... .
- * The relative error in the first term is approximately y^2/12x^2 .
- */
- if ((fabs (y) < 2.e-4 * fabs (x))
- && (x > 0))
- {
- t = 0.25*y*(y/x);
- }
- else
- {
- r = Cabs (z);
- t = 0.5*(r - x);
- }
-
- r = sqrt (t);
- q.i = r;
- q.r = y/(2.0*r);
- /* Heron iteration in complex arithmetic */
- Cdiv (&q, z, &s);
- Cadd (&q, &s, w);
- w->r *= 0.5;
- w->i *= 0.5;
-}
-
-/* --- elliptic functions --- */
-/* ellik.c - Incomplete elliptic integral of the first kind
- *
- * SYNOPSIS:
- * double phi, m, y, ellik();
- * y = ellik (phi, m);
- *
- * DESCRIPTION:
- * Approximates the integral
- * phi
- * -
- * | |
- * | dt
- * F(phi_\m) = | ------------------
- * | 2
- * | | sqrt(1 - m sin t)
- * -
- * 0
- * of amplitude phi and modulus m, using the arithmetic -
- * geometric mean algorithm.
- *
- * ACCURACY:
- * Tested at random points with m in [0, 1] and phi as indicated.
- * Relative error:
- * arithmetic domain # trials peak rms
- * IEEE -10,10 200000 7.4e-16 1.0e-16
- */
-static double
-ellik (double phi, double m)
-{
- double a, b, c, e, temp, t, K;
- int d, mod, sign, npio2;
-
- if (m == 0.0)
- return phi;
- a = 1.0 - m;
- if (a == 0.0)
- {
- if (fabs (phi) >= PIO2)
- {
- math_set_error ("ellik", MATH_ERROR_SING);
- return MAXNUM;
- }
- return log ( tan ((PIO2 + phi) / 2.0) );
- }
- npio2 = floor (phi/PIO2);
- if (npio2 & 1)
- npio2 += 1;
- if (npio2)
- {
- K = ellpk (a);
- phi = phi - npio2 * PIO2;
- }
- else
- K = 0.0;
- if (phi < 0.0)
- {
- phi = -phi;
- sign = -1;
- }
- else
- sign = 0;
- b = sqrt (a);
- t = tan (phi);
- if (fabs (t) > 10.0)
- {
- /* Transform the amplitude */
- e = 1.0/(b*t);
- /* ... but avoid multiple recursions. */
- if (fabs (e) < 10.0)
- {
- e = atan (e);
- if (npio2 == 0)
- K = ellpk (a);
- temp = K - ellik (e, m);
- goto done;
- }
- }
- a = 1.0;
- c = sqrt (m);
- d = 1;
- mod = 0;
-
- while (fabs (c/a) > MACHEP)
- {
- temp = b/a;
- phi = phi + atan (t*temp) + mod * PI;
- mod = (phi + PIO2)/PI;
- t = t * (1.0 + temp)/(1.0 - temp * t * t);
- c = (a - b)/2.0;
- temp = sqrt (a * b);
- a = (a + b)/2.0;
- b = temp;
- d += d;
- }
-
- temp = (atan (t) + mod * PI)/(d * a);
-
- done:
- if (sign < 0)
- temp = -temp;
- temp += npio2 * K;
- return temp;
-}
-
-/* ellpj - Jacobian Elliptic Functions
- *
- * SYNOPSIS:
- * double u, m, sn, cn, dn, phi;
- * int ellpj();
- * ellpj (u, m, _&sn, _&cn, _&dn, _&phi);
- *
- * DESCRIPTION:
- * Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m),
- * and dn(u|m) of parameter m between 0 and 1, and real
- * argument u.
- *
- * These functions are periodic, with quarter-period on the
- * real axis equal to the complete elliptic integral
- * ellpk(1.0-m).
- *
- * Relation to incomplete elliptic integral:
- * If u = ellik(phi,m), then sn(u|m) = sin(phi),
- * and cn(u|m) = cos(phi). Phi is called the amplitude of u.
- *
- * Computation is by means of the arithmetic-geometric mean
- * algorithm, except when m is within 1e-9 of 0 or 1. In the
- * latter case with m close to 1, the approximation applies
- * only for phi < pi/2.
- *
- * ACCURACY:
- * Tested at random points with u between 0 and 10, m between
- * 0 and 1.
- * Absolute error (* = relative error):
- * arithmetic function # trials peak rms
- * DEC sn 1800 4.5e-16 8.7e-17
- * IEEE phi 10000 9.2e-16* 1.4e-16*
- * IEEE sn 50000 4.1e-15 4.6e-16
- * IEEE cn 40000 3.6e-15 4.4e-16
- * IEEE dn 10000 1.3e-12 1.8e-14
- * Peak error observed in consistency check using addition
- * theorem for sn(u+v) was 4e-16 (absolute). Also tested by
- * the above relation to the incomplete elliptic integral.
- * Accuracy deteriorates when u is large.
- */
-static int
-ellpj (double u, double m,
- double *sn, double *cn, double *dn,
- double *ph)
-{
- double ai, b, phi, t, twon;
- double a[9], c[9];
- int i;
- /* Check for special cases */
- if (m < 0.0 || m > 1.0)
- {
- math_set_error ("ellpj", MATH_ERROR_DOMAIN);
- *sn = 0.0;
- *cn = 0.0;
- *ph = 0.0;
- *dn = 0.0;
- return -1;
- }
- if (m < 1.0e-9)
- {
- t = sin (u);
- b = cos (u);
- ai = 0.25 * m * (u - t*b);
- *sn = t - ai*b;
- *cn = b + ai*t;
- *ph = u - ai;
- *dn = 1.0 - 0.5*m*t*t;
- return 0;
- }
-
- if (m >= 0.9999999999)
- {
- ai = 0.25 * (1.0-m);
- b = cosh (u);
- t = tanh (u);
- phi = 1.0/b;
- twon = b * sinh (u);
- *sn = t + ai * (twon - u)/(b*b);
- *ph = 2.0*atan (exp (u)) - PIO2 + ai*(twon - u)/b;
- ai *= t * phi;
- *cn = phi - ai * (twon - u);
- *dn = phi + ai * (twon + u);
- return 0;
- }
- /* A. G. M. scale */
- a[0] = 1.0;
- b = sqrt (1.0 - m);
- c[0] = sqrt (m);
- twon = 1.0;
- i = 0;
-
- while (fabs (c[i]/a[i]) > MACHEP)
- {
- if (i > 7)
- {
- math_set_error ("ellpj", MATH_ERROR_OVERFLOW);
- goto done;
- }
- ai = a[i];
- ++i;
- c[i] = (ai - b)/2.0;
- t = sqrt (ai * b);
- a[i] = (ai + b)/2.0;
- b = t;
- twon *= 2.0;
- }
-
- done:
- /* backward recurrence */
- phi = twon * a[i] * u;
- do
- {
- t = c[i] * sin (phi) / a[i];
- b = phi;
- phi = (asin (t) + phi)/2.0;
- }
- while (--i);
-
- *sn = sin (phi);
- t = cos (phi);
- *cn = t;
- *dn = t/cos (phi-b);
- *ph = phi;
- return 0;
-}
-
-/* ellpk - Complete elliptic integral of the first kind
- *
- * SYNOPSIS:
- * double m1, y, ellpk();
- * y = ellpk (m1);
- *
- * DESCRIPTION:
- * Approximates the integral
- * pi/2
- * -
- * | |
- * | dt
- * K(m) = | ------------------
- * | 2
- * | | sqrt(1 - m sin t)
- * -
- * 0
- * where m = 1 - m1, using the approximation
- * P(x) - log x Q(x).
- *
- * The argument m1 is used rather than m so that the logarithmic
- * singularity at m = 1 will be shifted to the origin; this
- * preserves maximum accuracy.
- * K(0) = pi/2.
- *
- * ACCURACY:
- * Relative error:
- * arithmetic domain # trials peak rms
- * DEC 0,1 16000 3.5e-17 1.1e-17
- * IEEE 0,1 30000 2.5e-16 6.8e-17
- * ERROR MESSAGES:
- * message condition value returned
- * ellpk domain x<0, x>1 0.0
- */
-static double
-ellpk (double x)
-{
- static const double P_ellpk[] = {
- 1.37982864606273237150E-4,
- 2.28025724005875567385E-3,
- 7.97404013220415179367E-3,
- 9.85821379021226008714E-3,
- 6.87489687449949877925E-3,
- 6.18901033637687613229E-3,
- 8.79078273952743772254E-3,
- 1.49380448916805252718E-2,
- 3.08851465246711995998E-2,
- 9.65735902811690126535E-2,
- 1.38629436111989062502E0
- };
- static const double Q_ellpk[] = {
- 2.94078955048598507511E-5,
- 9.14184723865917226571E-4,
- 5.94058303753167793257E-3,
- 1.54850516649762399335E-2,
- 2.39089602715924892727E-2,
- 3.01204715227604046988E-2,
- 3.73774314173823228969E-2,
- 4.88280347570998239232E-2,
- 7.03124996963957469739E-2,
- 1.24999999999870820058E-1,
- 4.99999999999999999821E-1
- };
- static const double C1_ellpk = 1.3862943611198906188E0; /* log(4) */
-
- if ((x < 0.0) || (x > 1.0))
- {
- math_set_error ("ellpk", MATH_ERROR_DOMAIN);
- return 0.0;
- }
-
- if (x > MACHEP)
- {
- return polevl (x,P_ellpk,10) - log (x) * polevl (x,Q_ellpk,10);
- }
- else
- {
- if (x == 0.0)
- {
- math_set_error ("ellpk", MATH_ERROR_SING);
- return MAXNUM;
- }
- else
- {
- return C1_ellpk - 0.5 * log (x);
- }
- }
-}
-
-/* jacobi_theta_by_nome():
- * Find parameter corresponding to given nome by expansion
- * in theta functions:
- * AMS55 #16.38.5, 16.38.7
- *
- * 1/2
- * (2K) 4 9
- * (--) = 1 + 2q + 2q + 2q + ... = Theta (0,q)
- * (pi) 3
- *
- *
- * 1/2
- * (2K) 1/4 1/4 2 6 12 20
- * (--) m = 2q (1 + q + q + q + q + ...) = Theta (0,q)
- * (pi) 2
- *
- * The nome q(m) = exp(- pi K(1-m)/K(m)).
- *
- * 1/2
- * Given q, this program returns m .
- */
-static double
-jacobi_theta_by_nome (double q)
-{
- double t1, a = 1.0, b = 1.0, r = 1.0, p = q;
- do
- {
- r *= p;
- a += 2.0 * r;
- t1 = fabs (r / a);
-
- r *= p;
- b += r;
- p *= q;
- double t2 = fabs (r / b);
- if (t2 > t1)
- t1 = t2;
- }
- while (t1 > MACHEP);
- a = b / a;
- a = 4.0 * sqrt (q) * a * a; /* see above formulas, solved for m */
- return a;
-}
-
-/* --- misc utilities --- */
-/* polevl - Evaluate polynomial
- *
- * SYNOPSIS:
- * int N;
- * double x, y, coef[N+1], polevl[];
- * y = polevl(x, coef, N);
- *
- * DESCRIPTION:
- * Evaluates polynomial of degree N:
- * 2 N
- * y = C + C x + C x +...+ C x
- * 0 1 2 N
- *
- * Coefficients are stored in reverse order:
- * coef[0] = C , ..., coef[N] = C .
- * N 0
- * SPEED:
- * In the interest of speed, there are no checks for out
- * of bounds arithmetic. This routine is used by most of
- * the functions in the library. Depending on available
- * equipment features, the user may wish to rewrite the
- * program in microcode or assembly language.
- */
-static double
-polevl (double x, const double coef[], int N)
-{
- double ans;
- int i;
- const double *p;
-
- p = coef;
- ans = *p++;
- i = N;
-
- do
- ans = ans * x + *p++;
- while (--i);
-
- return ans;
-}
-
-/* --- filter design functions --- */
-static void
-print_z_fraction_before_zplnc (const BseIIRFilterRequest *ifr,
- DesignState *ds) /* must be called *before* zplnc() */
-{
- double zgain;
- if ((ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1) && ds->numerator_accu == 0)
- zgain = 1.0;
- else
- zgain = ds->denominator_accu / (ds->numerator_accu * ds->gain_scale);
- VERBOSE ("# constant mygain factor %23.13E\n", zgain); // BSE info
- VERBOSE ("# z plane Denominator Numerator\n"); // BSE info
- int j;
- for (j = 0; j <= ds->n_solved_poles; j++)
- VERBOSE ("%2d %17.9E %17.9E\n", j, ds->zd[j], ds->zn[j] * zgain); // BSE info
-}
-
-
-static int
-find_elliptic_locations_in_lambda_plane (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- double k = ds->wc / ds->wr;
- double m = k * k;
- ds->elliptic_Kk = ellpk (1.0 - m);
- ds->elliptic_Kpk = ellpk (m);
- EVERBOSE ("check: k=%.20g m=%.20g Kk=%.20g Kpk=%.20g\n", k, m, ds->elliptic_Kk, ds->elliptic_Kpk); // BSE info
- double q = exp (-PI * ifr->order * ds->elliptic_Kpk / ds->elliptic_Kk); /* the nome of k1 */
- double m1 = jacobi_theta_by_nome (q); /* see below */
- /* Note m1 = ds->ripple_epsilon / sqrt(A*A - 1.0) */
- double a = ds->ripple_epsilon / m1;
- a = a * a + 1;
- a = 10.0 * log (a) / log (10.0);
- printf ("dbdown %.9E\n", a);
- a = 180.0 * asin (k) / PI;
- double b = 1.0 / (1.0 + ds->ripple_epsilon * ds->ripple_epsilon);
- b = sqrt (1.0 - b);
- printf ("theta=%.9E, rho=%.9E\n", a, b);
- m1 *= m1;
- double m1p = 1.0 - m1;
- double Kk1 = ellpk (m1p);
- double Kpk1 = ellpk (m1);
- double r = Kpk1 * ds->elliptic_Kk / (Kk1 * ds->elliptic_Kpk);
- printf ("consistency check: n= %.14E\n", r);
- EVERBOSE ("consistency check: r=%.20g Kpk1=%.20g Kk1=%.20g m1=%.20g m1p=%.20g\n", r, Kpk1, Kk1, m1, m1p); // BSE info
- /* -1
- * sn j/ds->ripple_epsilon\m = j ellik(atan(1/ds->ripple_epsilon), m)
- */
- b = 1.0 / ds->ripple_epsilon;
- ds->elliptic_phi = atan (b);
- double u = ellik (ds->elliptic_phi, m1p);
- EVERBOSE ("phi=%.20g m=%.20g u=%.20g\n", ds->elliptic_phi, m1p, u);
- /* consistency check on inverse sn */
- double sn, cn, dn;
- ellpj (u, m1p, &sn, &cn, &dn, &ds->elliptic_phi);
- a = sn / cn;
- EVERBOSE ("consistency check: sn/cn = %.20g = %.20g = 1/ripple\n", a, b);
- ds->elliptic_k = k;
- ds->elliptic_u = u * ds->elliptic_Kk / (ifr->order * Kk1); /* or, u = u * Kpk / Kpk1 */
- ds->elliptic_m = m;
- return 0;
-}
-
-/* calculate s plane poles and zeros, normalized to wc = 1 */
-static int
-find_s_plane_poles_and_zeros (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- double *spz = ds->spz;
- int i, j;
- for (i = 0; i < BSE_IIR_CARRAY_SIZE; i++)
- spz[i] = 0.0;
- ds->n_poles = (ifr->order + 1) / 2;
- ds->n_zeros = 0;
- if (ifr->kind == BSE_IIR_FILTER_BUTTERWORTH)
- {
- double m;
- /* Butterworth poles equally spaced around the unit circle */
- if (ifr->order & 1)
- m = 0.0;
- else
- m = PI / (2.0 * ifr->order);
- for (i = 0; i < ds->n_poles; i++)
- { /* poles */
- int lr = i + i;
- spz[lr] = -cos (m);
- spz[lr + 1] = sin (m);
- m += PI / ifr->order;
- }
- /* high pass or band reject
- */
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- int ii = 0;
- /* map s => 1/s */
- for (j = 0; j < ds->n_poles; j++)
- {
- int ir = j + j;
- ii = ir + 1;
- double b = spz[ir]*spz[ir] + spz[ii]*spz[ii];
- spz[ir] = spz[ir] / b;
- spz[ii] = spz[ii] / b;
- }
- /* The zeros at infinity map to the origin.
- */
- ds->n_zeros = ds->n_poles;
- if (ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- ds->n_zeros += ifr->order / 2;
- }
- for (j = 0; j < ds->n_zeros; j++)
- {
- int ir = ii + 1;
- ii = ir + 1;
- spz[ir] = 0.0;
- spz[ii] = 0.0;
- }
- }
- }
- if (ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- {
- /* For Chebyshev, find radii of two Butterworth circles
- * See Gold & Rader, page 60
- */
- double rho = (ds->chebyshev_phi - 1.0) * (ds->chebyshev_phi + 1); /* rho = ds->ripple_epsilon^2 = {sqrt(1+ds->ripple_epsilon^2)}^2 - 1 */
- ds->ripple_epsilon = sqrt (rho);
- /* sqrt(1 + 1/ds->ripple_epsilon^2) + 1/ds->ripple_epsilon = {sqrt(1 + ds->ripple_epsilon^2) + 1} / ds->ripple_epsilon
- */
- ds->chebyshev_phi = (ds->chebyshev_phi + 1.0) / ds->ripple_epsilon;
- EVERBOSE ("Chebychev: phi-before=%.20g ripple=%.20g\n", ds->chebyshev_phi, ds->ripple_epsilon); // BSE info
- ds->chebyshev_phi = pow (ds->chebyshev_phi, 1.0 / ifr->order); /* raise to the 1/n power */
- EVERBOSE ("Chebychev: phi-raised=%.20g rn=%.20g\n", ds->chebyshev_phi, ifr->order * 1.0); // BSE info
- double b = 0.5 * (ds->chebyshev_phi + 1.0 / ds->chebyshev_phi); /* y coordinates are on this circle */
- double a = 0.5 * (ds->chebyshev_phi - 1.0 / ds->chebyshev_phi); /* x coordinates are on this circle */
- double m;
- if (ifr->order & 1)
- m = 0.0;
- else
- m = PI / (2.0 * ifr->order);
- for (i = 0; i < ds->n_poles; i++)
- { /* poles */
- int lr = i + i;
- spz[lr] = -a * cos (m);
- spz[lr + 1] = b * sin (m);
- m += PI / ifr->order;
- }
- /* high pass or band reject
- */
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- int ii = 0;
- /* map s => 1/s */
- for (j = 0; j < ds->n_poles; j++)
- {
- int ir = j + j;
- ii = ir + 1;
- b = spz[ir]*spz[ir] + spz[ii]*spz[ii];
- spz[ir] = spz[ir] / b;
- spz[ii] = spz[ii] / b;
- }
- /* The zeros at infinity map to the origin.
- */
- ds->n_zeros = ds->n_poles;
- if (ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- ds->n_zeros += ifr->order / 2;
- }
- for (j = 0; j < ds->n_zeros; j++)
- {
- int ir = ii + 1;
- ii = ir + 1;
- spz[ir] = 0.0;
- spz[ii] = 0.0;
- }
- }
- }
- if (ifr->kind == BSE_IIR_FILTER_ELLIPTIC)
- {
- double phi1 = 0.0, m = ds->elliptic_m;
- ds->n_zeros = ifr->order / 2;
- double sn1, cn1, dn1;
- ellpj (ds->elliptic_u, 1.0 - m, &sn1, &cn1, &dn1, &phi1);
- for (i = 0; i < ds->n_zeros; i++)
- { /* zeros */
- double a = ifr->order - 1 - i - i;
- double b = (ds->elliptic_Kk * a) / ifr->order;
- double sn, cn, dn;
- ellpj (b, m, &sn, &cn, &dn, &ds->elliptic_phi);
- int lr = 2 * ds->n_poles + 2 * i;
- spz[lr] = 0.0;
- a = ds->wc / (ds->elliptic_k * sn); /* elliptic_k = sqrt(m) */
- spz[lr + 1] = a;
- }
- for (i = 0; i < ds->n_poles; i++)
- { /* poles */
- double a = ifr->order - 1 - i - i;
- double b = a * ds->elliptic_Kk / ifr->order;
- double sn, cn, dn;
- ellpj (b, m, &sn, &cn, &dn, &ds->elliptic_phi);
- double r = ds->elliptic_k * sn * sn1;
- b = cn1 * cn1 + r * r;
- a = -ds->wc * cn * dn * sn1 * cn1 / b;
- int lr = i + i;
- spz[lr] = a;
- b = ds->wc * sn * dn1 / b;
- spz[lr + 1] = b;
- }
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- int ii = 0, nt = ds->n_poles + ds->n_zeros;
- for (j = 0; j < nt; j++)
- {
- int ir = j + j;
- ii = ir + 1;
- double b = spz[ir]*spz[ir] + spz[ii]*spz[ii];
- spz[ir] = spz[ir] / b;
- spz[ii] = spz[ii] / b;
- }
- while (ds->n_poles > ds->n_zeros)
- {
- int ir = ii + 1;
- ii = ir + 1;
- ds->n_zeros += 1;
- spz[ir] = 0.0;
- spz[ii] = 0.0;
- }
- }
- }
- printf ("s plane poles:\n");
- j = 0;
- for (i = 0; i < ds->n_poles + ds->n_zeros; i++)
- {
- double a = spz[j];
- ++j;
- double b = spz[j];
- ++j;
- printf ("%.9E %.9E\n", a, b);
- if (i == ds->n_poles - 1)
- printf ("s plane zeros:\n");
- }
- return 0;
-}
-
-/* convert s plane poles and zeros to the z plane. */
-static int
-convert_s_plane_to_z_plane (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- Complex r, cnum, cden, cwc, ca, cb, b4ac;
- double C;
-
- if (ifr->kind == BSE_IIR_FILTER_ELLIPTIC)
- C = ds->tan_angle_frequency;
- else
- C = ds->wc;
-
- int i;
- for (i = 0; i < BSE_IIR_CARRAY_SIZE; i++)
- {
- ds->zcpz[i].r = 0.0;
- ds->zcpz[i].i = 0.0;
- }
-
- int nc = ds->n_poles;
- ds->z_counter = -1;
- int icnt, ii = -1;
- for (icnt = 0; icnt < 2; icnt++)
- {
- Complex *z_pz = ds->zcpz;
- /* The maps from s plane to z plane */
- do
- {
- int ir = ii + 1;
- ii = ir + 1;
- r.r = ds->spz[ir];
- r.i = ds->spz[ii];
-
- switch (ifr->type)
- {
- case BSE_IIR_FILTER_LOW_PASS:
- case BSE_IIR_FILTER_HIGH_PASS:
- /* Substitute s - r = s/wc - r = (1/wc)(z-1)/(z+1) - r
- *
- * 1 1 - r wc ( 1 + r wc)
- * = --- -------- (z - --------)
- * z+1 wc ( 1 - r wc)
- *
- * giving the root in the z plane.
- */
- cnum.r = 1 + C * r.r;
- cnum.i = C * r.i;
- cden.r = 1 - C * r.r;
- cden.i = -C * r.i;
- ds->z_counter += 1;
- Cdiv (&cden, &cnum, &z_pz[ds->z_counter]);
- if (r.i != 0.0)
- {
- /* fill in complex conjugate root */
- ds->z_counter += 1;
- z_pz[ds->z_counter].r = z_pz[ds->z_counter - 1].r;
- z_pz[ds->z_counter].i = -z_pz[ds->z_counter - 1].i;
- }
- break;
- case BSE_IIR_FILTER_BAND_PASS:
- case BSE_IIR_FILTER_BAND_STOP:
- /* Substitute s - r => s/wc - r
- *
- * z^2 - 2 z cgam + 1
- * => ------------------ - r
- * (z^2 + 1) wc
- *
- * 1
- * = ------------ [ (1 - r wc) z^2 - 2 cgam z + 1 + r wc ]
- * (z^2 + 1) wc
- *
- * and solve for the roots in the z plane.
- */
- if (ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- cwc.r = ds->chebyshev_band_cbp;
- else
- cwc.r = ds->tan_angle_frequency;
- cwc.i = 0.0;
- Cmul (&r, &cwc, &cnum); /* r wc */
- Csub (&cnum, &COMPLEX_ONE, &ca); /* a = 1 - r wc */
- Cmul (&cnum, &cnum, &b4ac); /* 1 - (r wc)^2 */
- Csub (&b4ac, &COMPLEX_ONE, &b4ac);
- b4ac.r *= 4.0; /* 4ac */
- b4ac.i *= 4.0;
- cb.r = -2.0 * ds->cgam; /* b */
- cb.i = 0.0;
- Cmul (&cb, &cb, &cnum); /* b^2 */
- Csub (&b4ac, &cnum, &b4ac); /* b^2 - 4 ac */
- Csqrt (&b4ac, &b4ac);
- cb.r = -cb.r; /* -b */
- cb.i = -cb.i;
- ca.r *= 2.0; /* 2a */
- ca.i *= 2.0;
- Cadd (&b4ac, &cb, &cnum); /* -b + sqrt(b^2 - 4ac) */
- Cdiv (&ca, &cnum, &cnum); /* ... /2a */
- ds->z_counter += 1;
- Cmov (&cnum, &z_pz[ds->z_counter]);
- if (cnum.i != 0.0)
- {
- ds->z_counter += 1;
- z_pz[ds->z_counter].r = cnum.r;
- z_pz[ds->z_counter].i = -cnum.i;
- }
- if ((r.i != 0.0) || (cnum.i == 0))
- {
- Csub (&b4ac, &cb, &cnum); /* -b - sqrt(b^2 - 4ac) */
- Cdiv (&ca, &cnum, &cnum); /* ... /2a */
- ds->z_counter += 1;
- Cmov (&cnum, &z_pz[ds->z_counter]);
- if (cnum.i != 0.0)
- {
- ds->z_counter += 1;
- z_pz[ds->z_counter].r = cnum.r;
- z_pz[ds->z_counter].i = -cnum.i;
- }
- }
- break;
- } /* end switch */
- }
- while (--nc > 0);
-
- if (icnt == 0)
- {
- ds->n_solved_poles = ds->z_counter + 1;
- if (ds->n_zeros <= 0)
- {
- if (ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- return 0;
- else
- break;
- }
- }
- nc = ds->n_zeros;
- } /* end for() loop */
- return 0;
-}
-
-static int
-z_plane_zeros_poles_to_numerator_denomerator (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- Complex lin[2];
-
- lin[1].r = 1.0;
- lin[1].i = 0.0;
-
- if (ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- { /* Butterworth or Chebyshev */
- /* generate the remaining zeros */
- while (2 * ds->n_solved_poles - 1 > ds->z_counter)
- {
- if (ifr->type != BSE_IIR_FILTER_HIGH_PASS)
- {
- printf ("adding zero at Nyquist frequency\n");
- ds->z_counter += 1;
- ds->zcpz[ds->z_counter].r = -1.0; /* zero at Nyquist frequency */
- ds->zcpz[ds->z_counter].i = 0.0;
- }
- if (ifr->type == BSE_IIR_FILTER_BAND_PASS || ifr->type == BSE_IIR_FILTER_HIGH_PASS)
- {
- printf ("adding zero at 0 Hz\n");
- ds->z_counter += 1;
- ds->zcpz[ds->z_counter].r = 1.0; /* zero at 0 Hz */
- ds->zcpz[ds->z_counter].i = 0.0;
- }
- }
- }
- else
- { /* elliptic */
- while (2 * ds->n_solved_poles - 1 > ds->z_counter)
- {
- ds->z_counter += 1;
- ds->zcpz[ds->z_counter].r = -1.0; /* zero at Nyquist frequency */
- ds->zcpz[ds->z_counter].i = 0.0;
- if (ifr->type == BSE_IIR_FILTER_BAND_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- ds->z_counter += 1;
- ds->zcpz[ds->z_counter].r = 1.0; /* zero at 0 Hz */
- ds->zcpz[ds->z_counter].i = 0.0;
- }
- }
- }
- printf ("order = %d\n", ds->n_solved_poles);
-
- /* Expand the poles and zeros into numerator and
- * denominator polynomials
- */
- int j, icnt;
- for (icnt = 0; icnt < 2; icnt++)
- {
- double yy[BSE_IIR_CARRAY_SIZE] = { 0, };
- for (j = 0; j < BSE_IIR_CARRAY_SIZE; j++)
- ds->zn[j] = 0.0;
- ds->zn[0] = 1.0;
- for (j = 0; j < ds->n_solved_poles; j++)
- {
- int jj = j;
- if (icnt)
- jj += ds->n_solved_poles;
- double a = ds->zcpz[jj].r;
- double b = ds->zcpz[jj].i;
- int i;
- for (i = 0; i <= j; i++)
- {
- int jh = j - i;
- ds->zn[jh + 1] = ds->zn[jh + 1] - a * ds->zn[jh] + b * yy[jh];
- yy[jh + 1] = yy[jh + 1] - b * ds->zn[jh] - a * yy[jh];
- }
- }
- if (icnt == 0)
- {
- for (j = 0; j <= ds->n_solved_poles; j++)
- ds->zd[j] = ds->zn[j];
- }
- }
- /* Scale factors of the pole and zero polynomials */
- double a = 1.0;
- switch (ifr->type)
- {
- double gam;
- case BSE_IIR_FILTER_HIGH_PASS:
- a = -1.0;
- /* fall through */
- case BSE_IIR_FILTER_LOW_PASS:
- case BSE_IIR_FILTER_BAND_STOP:
- ds->numerator_accu = 1.0;
- ds->denominator_accu = 1.0;
- for (j = 1; j <= ds->n_solved_poles; j++)
- {
- ds->numerator_accu = a * ds->numerator_accu + ds->zn[j];
- ds->denominator_accu = a * ds->denominator_accu + ds->zd[j];
- }
- break;
- case BSE_IIR_FILTER_BAND_PASS:
- gam = PI / 2.0 - asin (ds->cgam); /* = acos(cgam) */
- int mh = ds->n_solved_poles / 2;
- ds->numerator_accu = ds->zn[mh];
- ds->denominator_accu = ds->zd[mh];
- double ai = 0.0;
- if (mh > ((ds->n_solved_poles / 4) * 2))
- {
- ai = 1.0;
- ds->numerator_accu = 0.0;
- ds->denominator_accu = 0.0;
- }
- for (j = 1; j <= mh; j++)
- {
- a = gam * j - ai * PI / 2.0;
- double cng = cos (a);
- int jh = mh + j;
- int jl = mh - j;
- ds->numerator_accu = ds->numerator_accu + cng * (ds->zn[jh] + (1.0 - 2.0 * ai) * ds->zn[jl]);
- ds->denominator_accu = ds->denominator_accu + cng * (ds->zd[jh] + (1.0 - 2.0 * ai) * ds->zd[jl]);
- }
- }
- return 0;
-}
-
-/* display quadratic factors */
-static int
-print_quadratic_factors (const BseIIRFilterRequest *ifr,
- const DesignState *ds,
- double x, double y,
- bool is_pole) /* 1 if poles, 0 if zeros */
-{
- double a, b, r, f, g, g0;
-
- if (y > 1.0e-16) /* check for imaginary pole/zero */
- {
- a = -2.0 * x;
- b = x * x + y * y;
- }
- else /* real valued pole/zero */
- {
- a = -x;
- b = 0.0;
- }
- printf ("q. f.\nz**2 %23.13E\nz**1 %23.13E\n", b, a);
- if (b != 0.0)
- {
- /* resonant frequency */
- r = sqrt (b);
- f = PI / 2.0 - asin (-a/(2.0 * r));
- f = f * ifr->sampling_frequency / (2.0 * PI);
- /* gain at resonance */
- g = 1.0 + r;
- g = g * g - (a * a / r);
- g = (1.0 - r) * sqrt (g);
- g0 = 1.0 + a + b; /* gain at d.c. */
- }
- else
- {
- /* It is really a first-order network.
- * Give the gain at ds->nyquist_frequency and D.C.
- */
- f = ds->nyquist_frequency;
- g = 1.0 - a;
- g0 = 1.0 + a;
- }
-
- if (is_pole)
- {
- if (g != 0.0)
- g = 1.0 / g;
- else
- g = MAXNUM;
- if (g0 != 0.0)
- g0 = 1.0 / g0;
- else
- g = MAXNUM;
- }
- printf ("f0 %16.8E gain %12.4E DC gain %12.4E\n\n", f, g, g0);
- return 0;
-}
-
-static int
-gainscale_and_print_deno_nume_zeros2_poles2 (const BseIIRFilterRequest *ifr, /* zplnc */
- DesignState *ds)
-{
- int j;
- ds->gain = ds->denominator_accu / (ds->numerator_accu * ds->gain_scale);
- if ((ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1) && ds->numerator_accu == 0)
- ds->gain = 1.0;
- printf ("constant gain factor %23.13E\n", ds->gain);
- for (j = 0; j <= ds->n_solved_poles; j++)
- ds->zn[j] = ds->gain * ds->zn[j];
-
- printf ("z plane Denominator Numerator\n");
- for (j = 0; j <= ds->n_solved_poles; j++)
- {
- printf ("%2d %17.9E %17.9E\n", j, ds->zd[j], ds->zn[j]);
- }
-
- /* I /think/ at this point the polynomial is factorized in 2nd order filters,
- * so that it can be implemented without stability problems -- stw
- */
- printf ("poles and zeros with corresponding quadratic factors\n");
- for (j = 0; j < ds->n_solved_poles; j++)
- {
- double a = ds->zcpz[j].r;
- double b = ds->zcpz[j].i;
- if (b >= 0.0)
- {
- printf ("pole %23.13E %23.13E\n", a, b);
- print_quadratic_factors (ifr, ds, a, b, true);
- }
- a = ds->zcpz[ds->n_solved_poles + j].r;
- b = ds->zcpz[ds->n_solved_poles + j].i;
- if (b >= 0.0)
- {
- printf ("zero %23.13E %23.13E\n", a, b);
- print_quadratic_factors (ifr, ds, a, b, false);
- }
- }
- return 0;
-}
-
-/* Calculate frequency response at f Hz mulitplied by amp */
-static double
-response (const BseIIRFilterRequest *ifr,
- DesignState *ds,
- double f, double amp)
-{
- Complex x, num, den, w;
- double u;
- int j;
-
- /* exp(j omega T) */
- u = 2.0 * PI * f /ifr->sampling_frequency;
- x.r = cos (u);
- x.i = sin (u);
-
- num.r = 1.0;
- num.i = 0.0;
- den.r = 1.0;
- den.i = 0.0;
- for (j = 0; j < ds->n_solved_poles; j++)
- {
- Csub (&ds->zcpz[j], &x, &w);
- Cmul (&w, &den, &den);
- Csub (&ds->zcpz[ds->n_solved_poles + j], &x, &w);
- Cmul (&w, &num, &num);
- }
- Cdiv (&den, &num, &w);
- w.r *= amp;
- w.i *= amp;
- u = Cabs (&w);
- return u;
-}
-
-/* Print table of filter frequency response */
-static void
-print_filter_table (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- double f, limit = 0.05 * ds->nyquist_frequency * 21;
-
- for (f=0; f < limit; f += limit / 21.)
- {
- double r = response (ifr, ds, f, ds->gain);
- if (r <= 0.0)
- r = -999.99;
- else
- r = 2.0 * DECIBELL_FACTOR * log (r);
- printf ("%10.1f %10.2f\n", f, r);
- // f = f + 0.05 * ds->nyquist_frequency;
- }
-}
-
-/* --- main IIR filter design function --- */
-static const char*
-iir_filter_design (const BseIIRFilterRequest *ifr,
- DesignState *ds)
-{
- double passband_edge1 = ifr->passband_edge;
- double passband_edge0 = ifr->passband_edge2;
-
- if (ifr->kind != BSE_IIR_FILTER_BUTTERWORTH &&
- ifr->kind != BSE_IIR_FILTER_CHEBYSHEV1 &&
- ifr->kind != BSE_IIR_FILTER_ELLIPTIC)
- return "unknown kind";
- if (ifr->type != BSE_IIR_FILTER_LOW_PASS &&
- ifr->type != BSE_IIR_FILTER_BAND_PASS &&
- ifr->type != BSE_IIR_FILTER_HIGH_PASS &&
- ifr->type != BSE_IIR_FILTER_BAND_STOP)
- return "unknown type";
- if (ifr->order <= 0)
- return "order too small";
-
- if (ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1 || ifr->kind == BSE_IIR_FILTER_ELLIPTIC)
- {
- if (ifr->passband_ripple_db <= 0.0)
- return "passband_ripple_db too small";
- if (ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- {
- /* For Chebyshev filter, ripples go from 1.0 to 1/sqrt(1+ds->ripple_epsilon^2) */
- ds->chebyshev_phi = exp (0.5 * ifr->passband_ripple_db / DECIBELL_FACTOR);
-
- if ((ifr->order & 1) == 0)
- ds->gain_scale = ds->chebyshev_phi;
- else
- ds->gain_scale = 1.0;
- }
- else
- { /* elliptic */
- ds->ripple_epsilon = exp (ifr->passband_ripple_db / DECIBELL_FACTOR);
- ds->gain_scale = 1.0;
- if ((ifr->order & 1) == 0)
- ds->gain_scale = sqrt (ds->ripple_epsilon);
- ds->ripple_epsilon = sqrt (ds->ripple_epsilon - 1.0);
- }
- }
-
- if (ifr->sampling_frequency <= 0.0)
- return "sampling_frequency too small";
-
- ds->nyquist_frequency = 0.5 * ifr->sampling_frequency;
-
- if (passband_edge1 <= 0.0)
- return "passband_edge1 too small";
- if (passband_edge1 >= ds->nyquist_frequency)
- return "passband_edge1 too high";
-
- if (ifr->type == BSE_IIR_FILTER_BAND_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- {
- if (passband_edge0 <= 0.0)
- return "passband_edge too small";
- if (passband_edge0 >= ds->nyquist_frequency)
- return "passband_edge too high";
- }
- else
- {
- passband_edge0 = 0.0;
- }
- if (passband_edge1 < passband_edge0)
- {
- double tmp = passband_edge1;
- passband_edge1 = passband_edge0;
- passband_edge0 = tmp;
- }
- double high_edge, band_width;
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS)
- {
- band_width = passband_edge1;
- high_edge = ds->nyquist_frequency;
- }
- else
- {
- band_width = passband_edge1 - passband_edge0;
- high_edge = passband_edge1;
- }
- /* Frequency correspondence for bilinear transformation
- *
- * Wanalog = tan(2 pi Fdigital T / 2)
- *
- * where T = 1/ifr->sampling_frequency
- */
- double ang = band_width * PI / ifr->sampling_frequency; /* angle frequency */
- double sang;
- double cang = cos (ang);
- ds->tan_angle_frequency = sin (ang) / cang; /* Wanalog */
- if (ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- {
- ds->wc = ds->tan_angle_frequency;
- /*printf("cos(1/2 (Whigh-Wlow) T) = %.5e, wc = %.5e\n", cang, ds->wc);*/
- }
-
- if (ifr->kind == BSE_IIR_FILTER_ELLIPTIC)
- { /* elliptic */
- double tmp_cgam = cos ((high_edge + passband_edge0) * PI / ifr->sampling_frequency) / cang;
- ds->cgam = tmp_cgam;
- if (ifr->stopband_edge > 0.0)
- ds->stopband_edge = ifr->stopband_edge;
- else if (ifr->stopband_db >= 0.0)
- return "need stopband_db or stopband_edge";
- else /* stopband_db < 0.0 */
- { /* calculate band edge from db down */
- double a = exp (-ifr->stopband_db / DECIBELL_FACTOR);
- double m1 = ds->ripple_epsilon / sqrt (a - 1.0);
- m1 *= m1;
- double m1p = 1.0 - m1;
- double Kk1 = ellpk (m1p);
- double Kpk1 = ellpk (m1);
- double q = exp (-PI * Kpk1 / (ifr->order * Kk1));
- double k = jacobi_theta_by_nome (q);
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- ds->wr = k;
- else
- ds->wr = 1.0 / k;
- if (ifr->type == BSE_IIR_FILTER_LOW_PASS || ifr->type == BSE_IIR_FILTER_HIGH_PASS)
- {
- ds->stopband_edge = atan (ds->tan_angle_frequency * ds->wr) * ifr->sampling_frequency / PI;
- }
- else
- {
- // FIXME: using tmp_cgam here increases precision
- double a = ds->tan_angle_frequency * ds->wr;
- a *= a;
- double b = a * (1.0 - ds->cgam * ds->cgam) + a * a;
- b = (ds->cgam + sqrt (b)) / (1.0 + a);
- ds->stopband_edge = (PI / 2.0 - asin (b)) * ifr->sampling_frequency / (2.0 * PI);
- }
- }
- switch (ifr->type)
- {
- case BSE_IIR_FILTER_LOW_PASS:
- if (ds->stopband_edge <= passband_edge1)
- return "need stopband_edge > passband_edge";
- break;
- case BSE_IIR_FILTER_BAND_PASS:
- if (ds->stopband_edge >= passband_edge0 && ds->stopband_edge <= passband_edge1)
- return "need stopband_edge < passband_edge or stopband_edge > passband_edge2";
- break;
- case BSE_IIR_FILTER_HIGH_PASS:
- if (ds->stopband_edge >= passband_edge1)
- return "need stopband_edge < passband_edge";
- break;
- case BSE_IIR_FILTER_BAND_STOP:
- if (ds->stopband_edge <= passband_edge0)
- return "need stopband_edge > passband_edge2";
- if (ds->stopband_edge >= passband_edge1)
- return "need stopband_edge < passband_edge";
- break;
- }
- ang = ds->stopband_edge * PI / ifr->sampling_frequency;
- cang = cos (ang);
- sang = sin (ang);
-
- if (ifr->type == BSE_IIR_FILTER_LOW_PASS || ifr->type == BSE_IIR_FILTER_HIGH_PASS)
- {
- ds->wr = sang / (cang * ds->tan_angle_frequency);
- }
- else
- {
- double q = cang * cang - sang * sang;
- sang = 2.0 * cang * sang;
- cang = q;
- ds->wr = (ds->cgam - cang) / (sang * ds->tan_angle_frequency);
- }
-
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- ds->wr = 1.0 / ds->wr;
- if (ds->wr < 0.0)
- ds->wr = -ds->wr;
-
- const double tmp_y0 = 1.0;
- double tmp_y1 = ds->wr;
- /* ds->chebyshev_band_cbp = ds->wr; */
- if (ifr->type == BSE_IIR_FILTER_HIGH_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP)
- tmp_y1 = 1.0 / tmp_y1;
- if (ifr->type == BSE_IIR_FILTER_LOW_PASS || ifr->type == BSE_IIR_FILTER_HIGH_PASS)
- {
- int i;
- for (i = 1; i <= 2; i++)
- {
- double tmp_y = i == 1 ? tmp_y0 : tmp_y1;
- ds->zd[i] = atan (ds->tan_angle_frequency * tmp_y) * ifr->sampling_frequency / PI ;
- }
- printf ("pass band %.9E\n", ds->zd[1]);
- printf ("stop band %.9E\n", ds->zd[2]);
- }
- else
- {
- int i;
- for (i = 1; i <= 2; i++)
- {
- double tmp_y = i == 1 ? tmp_y0 : tmp_y1;
- double a = ds->tan_angle_frequency * tmp_y;
- double b = atan (a);
- double q = sqrt (1.0 + a * a - ds->cgam * ds->cgam);
- q = atan2 (q, ds->cgam);
- ds->zd[i] = (q + b) * ds->nyquist_frequency / PI;
- ds->zn[i] = (q - b) * ds->nyquist_frequency / PI;
- }
- printf ("pass band %.9E %.9E\n", ds->zn[1], ds->zd[1]);
- printf ("stop band %.9E %.9E\n", ds->zn[2], ds->zd[2]);
- }
- ds->wc = 1.0;
- find_elliptic_locations_in_lambda_plane (ifr, ds); /* find locations in lambda plane */
- if ((2 * ifr->order + 2) > BSE_IIR_CARRAY_SIZE)
- goto toosml;
- } /* elliptic */
-
- /* Transformation from low-pass to band-pass critical frequencies
- *
- * Center frequency
- * cos(1/2 (Whigh+Wlow) T)
- * cos(Wcenter T) = ----------------------
- * cos(1/2 (Whigh-Wlow) T)
- *
- *
- * Band edges
- * cos(Wcenter T) - cos(Wdigital T)
- * Wanalog = -----------------------------------
- * sin(Wdigital T)
- */
-
- if (ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1)
- { /* Chebyshev */
- double a = PI * (high_edge + passband_edge0) / ifr->sampling_frequency ;
- ds->cgam = cos (a) / cang;
- a = 2.0 * PI * passband_edge1 / ifr->sampling_frequency;
- ds->chebyshev_band_cbp = (ds->cgam - cos (a)) / sin (a);
- }
- if (ifr->kind == BSE_IIR_FILTER_BUTTERWORTH)
- { /* Butterworth */
- double a = PI * (high_edge + passband_edge0) / ifr->sampling_frequency ;
- ds->cgam = cos (a) / cang;
- a = 2.0 * PI * passband_edge1 / ifr->sampling_frequency;
- /* ds->chebyshev_band_cbp = (ds->cgam - cos (a)) / sin (a); */
- ds->gain_scale = 1.0;
- }
-
- EVERBOSE ("State: gain_scale=%.20g ripple_epsilon=%.20g nyquist_frequency=%.20g " // BSE info
- "tan_angle_frequency=%.20g stopband_edge=%.20g wc=%.20g wr=%.20g cgam=%.20g\n",
- ds->gain_scale, ds->ripple_epsilon, ds->nyquist_frequency,
- ds->tan_angle_frequency, ds->stopband_edge, ds->wc, ds->wr, ds->cgam);
-
- find_s_plane_poles_and_zeros (ifr, ds); /* find s plane poles and zeros */
-
- if ((ifr->type == BSE_IIR_FILTER_BAND_PASS || ifr->type == BSE_IIR_FILTER_BAND_STOP) && 4 * ifr->order + 2 > BSE_IIR_CARRAY_SIZE)
- goto toosml;
-
- convert_s_plane_to_z_plane (ifr, ds); /* convert s plane to z plane */
- // volatile_sink ("x");
- z_plane_zeros_poles_to_numerator_denomerator (ifr, ds);
- EVERBOSE ("an=%.20g pn=%.20g scale=%.20g\n", ds->denominator_accu, ds->numerator_accu, ds->gain_scale); // BSE info
- print_z_fraction_before_zplnc (ifr, ds);
- gainscale_and_print_deno_nume_zeros2_poles2 (ifr, ds);
- print_filter_table (ifr, ds); /* tabulate transfer function */
- return NULL;
-
- toosml:
- return "storage arrays too small";
-}
-
-static double
-my_getnum (const char *text)
-{
- printf ("%s ? ", text);
- char s[4096];
- if (!fgets (s, sizeof (s), stdin))
- exit (0);
- double val = 0;
- sscanf (s, "%lf", &val);
- return val;
-}
-
-
-int
-main (int argc,
- char *argv[])
-{
- init_constants();
- BseIIRFilterRequest ifr = { 0 };
- DesignState ds = default_design_state;
- switch ((int) my_getnum ("kind"))
- {
- case 1: ifr.kind = BSE_IIR_FILTER_BUTTERWORTH; break;
- case 2: ifr.kind = BSE_IIR_FILTER_CHEBYSHEV1; break;
- case 3: ifr.kind = BSE_IIR_FILTER_ELLIPTIC; break;
- default: return 1;
- }
- ifr.type = my_getnum ("type");
- ifr.order = my_getnum ("order");
- if (ifr.kind != BSE_IIR_FILTER_BUTTERWORTH) /* not Butterworth */
- ifr.passband_ripple_db = my_getnum ("passband_ripple_db");
- ifr.sampling_frequency = my_getnum ("sampling_frequency");
- ifr.passband_edge = my_getnum ("passband_edge");
- if (ifr.type == BSE_IIR_FILTER_BAND_PASS ||
- ifr.type == BSE_IIR_FILTER_BAND_STOP)
- ifr.passband_edge2 = my_getnum ("passband_edge2");
- if (ifr.kind == BSE_IIR_FILTER_ELLIPTIC)
- ifr.stopband_db = ifr.stopband_edge = my_getnum ("stopband_edge or stopband_db");
- printf ("\n");
- const char *errmsg = iir_filter_design (&ifr, &ds);
- fflush (stdout);
- fflush (stderr);
- // VERBOSE ("DEBUG: %.20g %.20g %.20g %.20g %.20g\n", a, cos(a), cang, ds->cgam, 0.);
- if (errmsg)
- {
- fprintf (stderr, "Invalid specification: %s\n", errmsg);
- fflush (stderr);
- return 1;
- }
-
- return 0;
-}
-
-/* compile with: gcc -Wall -O2 -g bseellipticfilter.c -lm -o bseellipticfilter
- * (use -ffloat-store for ellf.c compatibility)
- */
Deleted: trunk/bse/bseellipticfilter.h
===================================================================
--- trunk/bse/bseellipticfilter.h 2006-10-29 21:28:10 UTC (rev 4033)
+++ trunk/bse/bseellipticfilter.h 2006-10-29 23:49:45 UTC (rev 4034)
@@ -1,146 +0,0 @@
-/* BSE - Bedevilled Sound Engine
- * Copyright (C) 2006 Tim Janik
- *
- * This software is provided "as is"; redistribution and modification
- * is permitted, provided that the following disclaimer is retained.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * In no event shall the authors or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even
- * if advised of the possibility of such damage.
- */
-#ifndef BSE_IIR_FILTER_H__
-#define BSE_IIR_FILTER_H__
-
-// FIXME: #include <bse/bsemath.h>
-#include <stdbool.h> // FIXME
-typedef unsigned int uint; // FIXME
-
-// FIXME: BIRNET_EXTERN_C_BEGIN();
-
-/* --- Complex numeral --- */
-typedef struct {
- double r; // real part
- double i; // imaginary part
-} Complex;
-
-
-typedef enum {
- BSE_IIR_FILTER_BUTTERWORTH = 1,
- BSE_IIR_FILTER_BESSEL = 2,
- BSE_IIR_FILTER_CHEBYSHEV1 = 3,
- BSE_IIR_FILTER_CHEBYSHEV2 = 4,
- BSE_IIR_FILTER_ELLIPTIC = 5,
-} BseIIRFilterKind;
-
-typedef enum {
- BSE_IIR_FILTER_LOW_PASS = 1,
- BSE_IIR_FILTER_BAND_PASS = 2,
- BSE_IIR_FILTER_HIGH_PASS = 3,
- BSE_IIR_FILTER_BAND_STOP = 4,
-} BseIIRFilterType;
-
-typedef struct {
- BseIIRFilterKind kind;
- BseIIRFilterType type;
- uint order; /* >= 1 */
- double sampling_frequency; /* Hz, > 0.0 && == 2 * nyquist_frequency */
- double passband_edge; /* Hz, > 0.0 && < nyquist_frequency */
- double passband_ripple_db; /* dB, > 0.0, not Butterworth */
- double passband_edge2; /* Hz, > 0.0 && < nyquist_frequency, for BAND filters */
- double stopband_edge; /* Hz, > 0.0, replaces stopband_db, elliptic only */
- double stopband_db; /* dB, < 0.0, elliptic only */
-} BseIIRFilterRequest;
-
-#define BSE_IIR_MAX_ORDER (64)
-#define BSE_IIR_CARRAY_SIZE (4 * BSE_IIR_MAX_ORDER + 2) /* size of arrays used to store coefficients */
-
-typedef struct {
- uint order;
- double sampling_frequency;
- /* s-plane output */
- double spz[BSE_IIR_CARRAY_SIZE]; /* s-plane poles and zeros */
- /* z-plane poles and zeros */
- double gain;
- Complex zp[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane poles [order] */
- Complex zz[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane zeros [order] */
- /* normalized z-plane transfer function */
- double zn[BSE_IIR_CARRAY_SIZE]; /* numerator coefficients [order+1] */
- double zd[BSE_IIR_CARRAY_SIZE]; /* denominator coefficients [order+1] */
-} BseIIRFilterDesign;
-
-typedef struct {
- int n_poles;
- int n_zeros;
- int z_counter; /* incremented as z^N coefficients are found, indexes poles and zeros */
- int n_solved_poles;
- /* common state */
- double gain_scale;
- double ripple_epsilon;
- double nyquist_frequency;
- double tan_angle_frequency;
- double wc; /* tan_angle_frequency or normalized to 1.0 for elliptic */
- double cgam; /* angle frequency temporary */
- double stopband_edge; /* derived from ifr->stopband_edge or ifr->stopband_db */
- double wr;
- double numerator_accu;
- double denominator_accu;
- /* chebyshev state */
- double chebyshev_phi;
- double chebyshev_band_cbp;
- /* elliptic state */
- double elliptic_phi;
- double elliptic_k;
- double elliptic_u;
- double elliptic_m;
- double elliptic_Kk; /* complete elliptic integral of the first kind of 1-elliptic_m */
- double elliptic_Kpk; /* complete elliptic integral of the first kind of elliptic_m */
- /* common output */
- double gain;
- double spz[BSE_IIR_CARRAY_SIZE]; /* s-plane poles and zeros */
- Complex zcpz[BSE_IIR_CARRAY_SIZE]; /* z-plane poles and zeros */
- /* normalized z-plane transfer function */
- double zn[BSE_IIR_CARRAY_SIZE]; /* numerator coefficients [order+1] */
- double zd[BSE_IIR_CARRAY_SIZE]; /* denominator coefficients [order+1] */
-} DesignState;
-
-static const DesignState default_design_state = {
- .n_poles = 0,
- .n_zeros = 0,
- .z_counter = 0,
- .n_solved_poles = 0,
- .gain_scale = 0.0,
- .ripple_epsilon = 0.0,
- .nyquist_frequency = 0.0,
- .tan_angle_frequency = 0.0,
- .wc = 0.0,
- .cgam = 0.0,
- .stopband_edge = 2400,
- .wr = 0.0,
- .numerator_accu = 0.0,
- .denominator_accu = 0.0,
- .chebyshev_phi = 0.0,
- .chebyshev_band_cbp = 0.0,
- .elliptic_phi = 0.0,
- .elliptic_k = 0.0,
- .elliptic_u = 0.0,
- .elliptic_m = 0.0,
- .elliptic_Kk = 0.0,
- .elliptic_Kpk = 0.0,
- .gain = 0.0,
- .spz = { 0, },
- .zn = { 0, },
- .zd = { 0, },
- .zcpz = { { 0, }, },
-};
-
-// FIXME: BIRNET_EXTERN_C_END();
-
-#endif /* BSE_IIR_FILTER_H__ */ /* vim:set ts=8 sw=2 sts=2: */
Modified: trunk/bse/bsefilter-ellf.c
===================================================================
--- trunk/bse/bsefilter-ellf.c 2006-10-29 21:28:10 UTC (rev 4033)
+++ trunk/bse/bsefilter-ellf.c 2006-10-29 23:49:45 UTC (rev 4034)
@@ -17,13 +17,107 @@
* otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*/
-#include "bseellipticfilter.h"
#define _ISOC99_SOURCE /* for INFINITY and NAN */
+#define _GNU_SOURCE /* provides: _ISOC99_SOURCE */
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+
+#ifndef ELLF_BEHAVIOR
+#include "bsefilter.h"
+
+#else
+
+#include <stdbool.h> // FIXME
+#include <complex.h>
+// typedef unsigned int uint;
+typedef _Complex double Complex;
+
+typedef enum {
+ BSE_IIR_FILTER_BUTTERWORTH = 1,
+ BSE_IIR_FILTER_BESSEL = 2,
+ BSE_IIR_FILTER_CHEBYSHEV1 = 3,
+ BSE_IIR_FILTER_CHEBYSHEV2 = 4,
+ BSE_IIR_FILTER_ELLIPTIC = 5,
+} BseIIRFilterKind;
+
+typedef enum {
+ BSE_IIR_FILTER_LOW_PASS = 1,
+ BSE_IIR_FILTER_BAND_PASS = 2,
+ BSE_IIR_FILTER_HIGH_PASS = 3,
+ BSE_IIR_FILTER_BAND_STOP = 4,
+} BseIIRFilterType;
+
+typedef struct {
+ BseIIRFilterKind kind;
+ BseIIRFilterType type;
+ uint order; /* >= 1 */
+ double sampling_frequency; /* Hz, > 0.0 && == 2 * nyquist_frequency */
+ double passband_edge; /* Hz, > 0.0 && < nyquist_frequency */
+ double passband_ripple_db; /* dB, > 0.0, not Butterworth */
+ double passband_edge2; /* Hz, > 0.0 && < nyquist_frequency, for BAND filters */
+ double stopband_edge; /* Hz, > 0.0, replaces stopband_db, elliptic only */
+ double stopband_db; /* dB, < 0.0, elliptic only */
+} BseIIRFilterRequest;
+
+#define BSE_IIR_MAX_ORDER (64)
+#define BSE_IIR_CARRAY_SIZE (4 * BSE_IIR_MAX_ORDER + 2) /* size of arrays used to store coefficients */
+
+typedef struct {
+ uint order;
+ double sampling_frequency;
+ /* z-plane poles and zeros */
+ double gain;
+ Complex zp[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane poles [order] */
+ Complex zz[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane zeros [order] */
+ /* normalized z-plane transfer function */
+ double zn[BSE_IIR_CARRAY_SIZE]; /* numerator coefficients [order+1] */
+ double zd[BSE_IIR_CARRAY_SIZE]; /* denominator coefficients [order+1] */
+} BseIIRFilterDesign;
+#endif
+
+typedef struct {
+ double r; // real part
+ double i; // imaginary part
+} EllfComplex;
+
+typedef struct {
+ int n_poles;
+ int n_zeros;
+ int z_counter; /* incremented as z^N coefficients are found, indexes poles and zeros */
+ int n_solved_poles;
+ /* common state */
+ double gain_scale;
+ double ripple_epsilon;
+ double nyquist_frequency;
+ double tan_angle_frequency;
+ double wc; /* tan_angle_frequency or normalized to 1.0 for elliptic */
+ double cgam; /* angle frequency temporary */
+ double stopband_edge; /* derived from ifr->stopband_edge or ifr->stopband_db */
+ double wr;
+ double numerator_accu;
+ double denominator_accu;
+ /* chebyshev state */
+ double chebyshev_phi;
+ double chebyshev_band_cbp;
+ /* elliptic state */
+ double elliptic_phi;
+ double elliptic_k;
+ double elliptic_u;
+ double elliptic_m;
+ double elliptic_Kk; /* complete elliptic integral of the first kind of 1-elliptic_m */
+ double elliptic_Kpk; /* complete elliptic integral of the first kind of elliptic_m */
+ /* common output */
+ double gain;
+ double spz[BSE_IIR_CARRAY_SIZE]; /* s-plane poles and zeros */
+ EllfComplex zcpz[BSE_IIR_CARRAY_SIZE]; /* z-plane poles and zeros */
+ /* normalized z-plane transfer function */
+ double zn[BSE_IIR_CARRAY_SIZE]; /* numerator coefficients [order+1] */
+ double zd[BSE_IIR_CARRAY_SIZE]; /* denominator coefficients [order+1] */
+} EllfDesignState;
+
static void __attribute__ ((__format__ (__printf__, 1, 2)))
VERBOSE (const char *format,
...)
@@ -40,8 +134,12 @@
#define EVERBOSE VERBOSE
//#define EVERBOSE(...) do{}while (0)
-#if 0 // FIXME: increase precision by using:
+static const char* ellf_filter_design (const BseIIRFilterRequest *ifr,
+ EllfDesignState *ds);
+
+#ifndef ELLF_BEHAVIOR
+
//#include "bseieee754.h"
#define PI (3.141592653589793238462643383279502884197) // pi
#define BSE_PI_DIV_2 (1.570796326794896619231321691639751442099) // pi/2
@@ -56,8 +154,41 @@
// #define PI /* PI is defined in bseieee754.h */
#define PIO2 (BSE_PI_DIV_2) /* pi/2 */
#define MAXNUM (BSE_DOUBLE_MAX_NORMAL) /* 2**1024*(1-MACHEP) */
-static void init_constants (void) {}
+bool
+_bse_filter_design_ellf (const BseIIRFilterRequest *ifr,
+ BseIIRFilterDesign *fid)
+{
+ EllfDesignState ds = { 0, };
+ const char *errmsg = ellf_filter_design (ifr, &ds);
+ fflush (stdout);
+ fflush (stderr);
+ // VERBOSE ("DEBUG: %.20g %.20g %.20g %.20g %.20g\n", a, cos(a), cang, ds->cgam, 0.);
+ if (errmsg)
+ return false;
+ fid->order = ds.n_solved_poles;
+ fid->sampling_frequency = ifr->sampling_frequency;
+ fid->gain = ds.gain;
+ fid->n_zeros = 0;
+ fid->n_poles = 0;
+ uint i;
+ for (i = 0; i < ds.n_solved_poles; i++)
+ {
+ double a = ds.zcpz[i].r, b = ds.zcpz[i].i;
+ if (b >= 0.0)
+ fid->zp[fid->n_poles++] = a + I * b;
+ a = ds.zcpz[ds.n_solved_poles + i].r, b = ds.zcpz[ds.n_solved_poles + i].i;
+ if (b >= 0.0)
+ fid->zz[fid->n_zeros++] = a + I * b;
+ }
+ for (i = 0; i <= fid->order; i++)
+ {
+ fid->zn[i] = ds.zn[i];
+ fid->zd[i] = ds.zd[i];
+ }
+ return true;
+}
+
#else
static double DECIBELL_FACTOR = -1;
@@ -70,6 +201,64 @@
static const double PI = 3.14159265358979323846; /* pi */
static const double PIO2 = 1.57079632679489661923; /* pi/2 */
static const double MACHEP = 1.11022302462515654042E-16; /* 2**-53 */
+
+
+static double
+my_getnum (const char *text)
+{
+ printf ("%s ? ", text);
+ char s[4096];
+ if (!fgets (s, sizeof (s), stdin))
+ exit (0);
+ double val = 0;
+ sscanf (s, "%lf", &val);
+ return val;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ init_constants();
+ BseIIRFilterRequest ifr = { 0 };
+ EllfDesignState ds = { .stopband_edge = 2400, };
+ switch ((int) my_getnum ("kind"))
+ {
+ case 1: ifr.kind = BSE_IIR_FILTER_BUTTERWORTH; break;
+ case 2: ifr.kind = BSE_IIR_FILTER_CHEBYSHEV1; break;
+ case 3: ifr.kind = BSE_IIR_FILTER_ELLIPTIC; break;
+ default: return 1;
+ }
+ ifr.type = my_getnum ("type");
+ ifr.order = my_getnum ("order");
+ if (ifr.kind != BSE_IIR_FILTER_BUTTERWORTH) /* not Butterworth */
+ ifr.passband_ripple_db = my_getnum ("passband_ripple_db");
+ ifr.sampling_frequency = my_getnum ("sampling_frequency");
+ ifr.passband_edge = my_getnum ("passband_edge");
+ if (ifr.type == BSE_IIR_FILTER_BAND_PASS ||
+ ifr.type == BSE_IIR_FILTER_BAND_STOP)
+ ifr.passband_edge2 = my_getnum ("passband_edge2");
+ if (ifr.kind == BSE_IIR_FILTER_ELLIPTIC)
+ ifr.stopband_db = ifr.stopband_edge = my_getnum ("stopband_edge or stopband_db");
+ printf ("\n");
+ const char *errmsg = ellf_filter_design (&ifr, &ds);
+ fflush (stdout);
+ fflush (stderr);
+ // VERBOSE ("DEBUG: %.20g %.20g %.20g %.20g %.20g\n", a, cos(a), cang, ds->cgam, 0.);
+ if (errmsg)
+ {
+ fprintf (stderr, "Invalid specification: %s\n", errmsg);
+ fflush (stderr);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* compile with: gcc -Wall -O2 -g -ffloat-store -DELLF_BEHAVIOR bsefilter-ellf.c -lm -o bsefilter-ellf
+ * (using -ffloat-store for ellf.c compatibility)
+ */
+
#endif
/* This code calculates design coefficients for
@@ -132,14 +321,14 @@
*/
/* --- prototypes --- */
-static const Complex COMPLEX_ONE = {1.0, 0.0};
-static double Cabs (const Complex *z);
-static void Cadd (const Complex *a, const Complex *b, Complex *c);
-static void Cdiv (const Complex *a, const Complex *b, Complex *c);
-static void Cmov (const Complex *a, Complex *b);
-static void Cmul (const Complex *a, const Complex *b, Complex *c);
-static void Csqrt (const Complex *z, Complex *w);
-static void Csub (const Complex *a, const Complex *b, Complex *c);
+static const EllfComplex COMPLEX_ONE = {1.0, 0.0};
+static double Cabs (const EllfComplex *z);
+static void Cadd (const EllfComplex *a, const EllfComplex *b, EllfComplex *c);
+static void Cdiv (const EllfComplex *a, const EllfComplex *b, EllfComplex *c);
+static void Cmov (const EllfComplex *a, EllfComplex *b);
+static void Cmul (const EllfComplex *a, const EllfComplex *b, EllfComplex *c);
+static void Csqrt (const EllfComplex *z, EllfComplex *w);
+static void Csub (const EllfComplex *a, const EllfComplex *b, EllfComplex *c);
static double polevl (double x, const double coef[], int N);
static double ellik (double phi, double m); // incomplete elliptic integral of the first kind
static double ellpk (double x); // complete elliptic integral of the first kind
@@ -229,7 +418,7 @@
/* --- complex number arithmetic --- */
/* c = b + a */
static void
-Cadd (const Complex *a, const Complex *b, Complex *c)
+Cadd (const EllfComplex *a, const EllfComplex *b, EllfComplex *c)
{
c->r = b->r + a->r;
c->i = b->i + a->i;
@@ -237,7 +426,7 @@
/* c = b - a */
static void
-Csub (const Complex *a, const Complex *b, Complex *c)
+Csub (const EllfComplex *a, const EllfComplex *b, EllfComplex *c)
{
c->r = b->r - a->r;
c->i = b->i - a->i;
@@ -245,7 +434,7 @@
/* c = b * a */
static void
-Cmul (const Complex *a, const Complex *b, Complex *c)
+Cmul (const EllfComplex *a, const EllfComplex *b, EllfComplex *c)
{
/* Multiplication:
* c.r = b.r * a.r - b.i * a.i
@@ -260,7 +449,7 @@
/* c = b / a */
static void
-Cdiv (const Complex *a, const Complex *b, Complex *c)
+Cdiv (const EllfComplex *a, const EllfComplex *b, EllfComplex *c)
{
/* Division:
* d = a.r * a.r + a.i * a.i
@@ -304,7 +493,7 @@
/* b = a */
static void
-Cmov (const Complex *a, Complex *b)
+Cmov (const EllfComplex *a, EllfComplex *b)
{
*b = *a;
}
@@ -313,7 +502,7 @@
*
* SYNOPSIS:
* double Cabs();
- * Complex z;
+ * EllfComplex z;
* double a;
*
* a = Cabs (&z);
@@ -333,7 +522,7 @@
* IEEE -10,+10 100000 2.7e-16 6.9e-17
*/
static double
-Cabs (const Complex *z)
+Cabs (const EllfComplex *z)
{
/* exponent thresholds for IEEE doubles */
const double PREC = 27;
@@ -404,7 +593,7 @@
*
* SYNOPSIS:
* void Csqrt();
- * Complex z, w;
+ * EllfComplex z, w;
* Csqrt (&z, &w);
*
* DESCRIPTION:
@@ -429,9 +618,9 @@
* close to the real axis.
*/
static void
-Csqrt (const Complex *z, Complex *w)
+Csqrt (const EllfComplex *z, EllfComplex *w)
{
- Complex q, s;
+ EllfComplex q, s;
double x, y, r, t;
x = z->r;
@@ -898,7 +1087,7 @@
/* --- filter design functions --- */
static void
print_z_fraction_before_zplnc (const BseIIRFilterRequest *ifr,
- DesignState *ds) /* must be called *before* zplnc() */
+ EllfDesignState *ds) /* must be called *before* zplnc() */
{
double zgain;
if ((ifr->kind == BSE_IIR_FILTER_BUTTERWORTH || ifr->kind == BSE_IIR_FILTER_CHEBYSHEV1) && ds->numerator_accu == 0)
@@ -915,7 +1104,7 @@
static int
find_elliptic_locations_in_lambda_plane (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ EllfDesignState *ds)
{
double k = ds->wc / ds->wr;
double m = k * k;
@@ -961,7 +1150,7 @@
/* calculate s plane poles and zeros, normalized to wc = 1 */
static int
find_s_plane_poles_and_zeros (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ EllfDesignState *ds)
{
double *spz = ds->spz;
int i, j;
@@ -1141,9 +1330,9 @@
/* convert s plane poles and zeros to the z plane. */
static int
convert_s_plane_to_z_plane (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ EllfDesignState *ds)
{
- Complex r, cnum, cden, cwc, ca, cb, b4ac;
+ EllfComplex r, cnum, cden, cwc, ca, cb, b4ac;
double C;
if (ifr->kind == BSE_IIR_FILTER_ELLIPTIC)
@@ -1163,7 +1352,7 @@
int icnt, ii = -1;
for (icnt = 0; icnt < 2; icnt++)
{
- Complex *z_pz = ds->zcpz;
+ EllfComplex *z_pz = ds->zcpz;
/* The maps from s plane to z plane */
do
{
@@ -1278,9 +1467,9 @@
static int
z_plane_zeros_poles_to_numerator_denomerator (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ EllfDesignState *ds)
{
- Complex lin[2];
+ EllfComplex lin[2];
lin[1].r = 1.0;
lin[1].i = 0.0;
@@ -1400,7 +1589,7 @@
/* display quadratic factors */
static int
print_quadratic_factors (const BseIIRFilterRequest *ifr,
- const DesignState *ds,
+ const EllfDesignState *ds,
double x, double y,
bool is_pole) /* 1 if poles, 0 if zeros */
{
@@ -1456,7 +1645,7 @@
static int
gainscale_and_print_deno_nume_zeros2_poles2 (const BseIIRFilterRequest *ifr, /* zplnc */
- DesignState *ds)
+ EllfDesignState *ds)
{
int j;
ds->gain = ds->denominator_accu / (ds->numerator_accu * ds->gain_scale);
@@ -1499,10 +1688,10 @@
/* Calculate frequency response at f Hz mulitplied by amp */
static double
response (const BseIIRFilterRequest *ifr,
- DesignState *ds,
+ EllfDesignState *ds,
double f, double amp)
{
- Complex x, num, den, w;
+ EllfComplex x, num, den, w;
double u;
int j;
@@ -1532,7 +1721,7 @@
/* Print table of filter frequency response */
static void
print_filter_table (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ EllfDesignState *ds)
{
double f, limit = 0.05 * ds->nyquist_frequency * 21;
@@ -1550,8 +1739,8 @@
/* --- main IIR filter design function --- */
static const char*
-iir_filter_design (const BseIIRFilterRequest *ifr,
- DesignState *ds)
+ellf_filter_design (const BseIIRFilterRequest *ifr,
+ EllfDesignState *ds)
{
double passband_edge1 = ifr->passband_edge;
double passband_edge0 = ifr->passband_edge2;
@@ -1814,60 +2003,3 @@
toosml:
return "storage arrays too small";
}
-
-static double
-my_getnum (const char *text)
-{
- printf ("%s ? ", text);
- char s[4096];
- if (!fgets (s, sizeof (s), stdin))
- exit (0);
- double val = 0;
- sscanf (s, "%lf", &val);
- return val;
-}
-
-
-int
-main (int argc,
- char *argv[])
-{
- init_constants();
- BseIIRFilterRequest ifr = { 0 };
- DesignState ds = default_design_state;
- switch ((int) my_getnum ("kind"))
- {
- case 1: ifr.kind = BSE_IIR_FILTER_BUTTERWORTH; break;
- case 2: ifr.kind = BSE_IIR_FILTER_CHEBYSHEV1; break;
- case 3: ifr.kind = BSE_IIR_FILTER_ELLIPTIC; break;
- default: return 1;
- }
- ifr.type = my_getnum ("type");
- ifr.order = my_getnum ("order");
- if (ifr.kind != BSE_IIR_FILTER_BUTTERWORTH) /* not Butterworth */
- ifr.passband_ripple_db = my_getnum ("passband_ripple_db");
- ifr.sampling_frequency = my_getnum ("sampling_frequency");
- ifr.passband_edge = my_getnum ("passband_edge");
- if (ifr.type == BSE_IIR_FILTER_BAND_PASS ||
- ifr.type == BSE_IIR_FILTER_BAND_STOP)
- ifr.passband_edge2 = my_getnum ("passband_edge2");
- if (ifr.kind == BSE_IIR_FILTER_ELLIPTIC)
- ifr.stopband_db = ifr.stopband_edge = my_getnum ("stopband_edge or stopband_db");
- printf ("\n");
- const char *errmsg = iir_filter_design (&ifr, &ds);
- fflush (stdout);
- fflush (stderr);
- // VERBOSE ("DEBUG: %.20g %.20g %.20g %.20g %.20g\n", a, cos(a), cang, ds->cgam, 0.);
- if (errmsg)
- {
- fprintf (stderr, "Invalid specification: %s\n", errmsg);
- fflush (stderr);
- return 1;
- }
-
- return 0;
-}
-
-/* compile with: gcc -Wall -O2 -g bseellipticfilter.c -lm -o bseellipticfilter
- * (use -ffloat-store for ellf.c compatibility)
- */
Added: trunk/bse/bsefilter.h
===================================================================
--- trunk/bse/bsefilter.h 2006-10-29 21:28:10 UTC (rev 4033)
+++ trunk/bse/bsefilter.h 2006-10-29 23:49:45 UTC (rev 4034)
@@ -0,0 +1,109 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 2006 Tim Janik
+ *
+ * This software is provided "as is"; redistribution and modification
+ * is permitted, provided that the following disclaimer is retained.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ */
+#ifndef BSE_FILTER_H__
+#define BSE_FILTER_H__
+
+#include <bse/bsemath.h>
+
+BIRNET_EXTERN_C_BEGIN();
+
+typedef enum /*< skip >*/
+{
+ BSE_IIR_FILTER_BUTTERWORTH = 1,
+ BSE_IIR_FILTER_BESSEL = 2,
+ BSE_IIR_FILTER_CHEBYSHEV1 = 3,
+ BSE_IIR_FILTER_CHEBYSHEV2 = 4,
+ BSE_IIR_FILTER_ELLIPTIC = 5,
+} BseIIRFilterKind;
+
+typedef enum /*< skip >*/
+{
+ BSE_IIR_FILTER_LOW_PASS = 1,
+ BSE_IIR_FILTER_BAND_PASS = 2,
+ BSE_IIR_FILTER_HIGH_PASS = 3,
+ BSE_IIR_FILTER_BAND_STOP = 4,
+} BseIIRFilterType;
+
+typedef struct {
+ BseIIRFilterKind kind;
+ BseIIRFilterType type;
+ uint order; /* >= 1 */
+ double sampling_frequency; /* Hz, > 0.0 && == 2 * nyquist_frequency */
+ double passband_ripple_db; /* dB, > 0.0, Chebyshev1 or elliptic */
+ double passband_edge; /* Hz, > 0.0 && < nyquist_frequency */
+ double passband_edge2; /* Hz, > 0.0 && < nyquist_frequency, for BAND filters */
+ double stopband_edge; /* Hz, > 0.0, replaces stopband_db, elliptic only */
+ double stopband_db; /* dB, < 0.0, elliptic only */
+} BseIIRFilterRequest;
+
+#define BSE_IIR_MAX_ORDER (64)
+#define BSE_IIR_CARRAY_SIZE (4 * BSE_IIR_MAX_ORDER + 2) /* size of arrays used to store coefficients */
+
+typedef struct {
+ double sampling_frequency; /* same as BseIIRFilterRequest.sampling_frequency */
+ uint order;
+ /* z-plane poles and zeros */
+ double gain;
+ uint n_zeros;
+ Complex zz[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane zeros [order] */
+ uint n_poles;
+ Complex zp[BSE_IIR_CARRAY_SIZE / 2]; /* z-plane poles [order] */
+ /* normalized z-plane transfer function */
+ double zn[BSE_IIR_CARRAY_SIZE]; /* numerator coefficients [order+1] */
+ double zd[BSE_IIR_CARRAY_SIZE]; /* denominator coefficients [order+1] */
+} BseIIRFilterDesign;
+
+typedef struct {
+ double xz2; // x[i-2] coefficient
+ double xz1; // x[i-1] coefficient
+ double yz2; // y[i-2] coefficient
+ double yz1; // y[i-1] coefficient
+} BseIIRStage;
+
+typedef struct {
+ uint order;
+ BseIIRStage *stages;
+ double *states; /* [0..2*order] */
+} BseIIRFilter;
+
+
+bool bse_iir_filter_design (const BseIIRFilterRequest *filter_request,
+ BseIIRFilterDesign *filter_design);
+BseIIRFilter* bse_iir_filter_new (const BseIIRFilterDesign *filter_design);
+void bse_iir_filter_change (BseIIRFilter *filter,
+ const BseIIRFilterDesign *filter_design);
+void bse_iir_filter_eval (BseIIRFilter *filter,
+ uint n_values,
+ const float *x,
+ float *y);
+void bse_iir_filter_free (BseIIRFilter *filter);
+const gchar* bse_iir_filter_kind_string (BseIIRFilterKind fkind);
+const gchar* bse_iir_filter_type_string (BseIIRFilterType ftype);
+gchar* bse_iir_filter_request_string (const BseIIRFilterRequest *filter_request);
+gchar* bse_iir_filter_design_string (const BseIIRFilterDesign *filter_design);
+gchar* bse_iir_filter_string (const BseIIRFilter *filter);
+
+
+/* --- internal prototypes --- */
+bool _bse_filter_design_ellf (const BseIIRFilterRequest *ifr,
+ BseIIRFilterDesign *fid);
+
+BIRNET_EXTERN_C_END();
+
+#endif /* BSE_FILTER_H__ */ /* vim:set ts=8 sw=2 sts=2: */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]