home *** CD-ROM | disk | FTP | other *** search
- /* ellf.c
- *
- * Read ellf.doc before attempting to compile this program.
- */
-
-
- /* size of arrays: */
- #define ARRSIZ 50
-
- double atan2();
-
- /* 1 = yes, 0 = no: */
- #define DECPDP 0
- #define UNK 1
- #define CEPHES 0
-
- #if DECPDP
- #define asin arcsin
- #define atan arctan
- #define artan2(a,b) (atan2(a,b))
- #endif
-
-
- #if CEPHES
- #define gtlin gets
- #define artan2(a,b) (atan2(a,b))
- #endif
-
- #if UNK
- #define gtlin gets
- #define artan2(a,b) (atan2(b,a))
- double PI = 3.14159265358979323846;
- double PIO2 = 1.57079632679489661923;
- /* MACHEP is the relative resolution of your computer's
- * floating point arithmetic. It will be 1.1E-16 for IEEE
- * double precision, 1.39E-17 for DEC VAX or PDP-11. */
- double MACHEP = 1.1e-16;
- double MAXNUM = 1.5e38;
- #endif
-
- extern double PI;
- extern double PIO2;
- extern double MACHEP;
-
- static double aa[ARRSIZ] = {0.0};
- static double pp[ARRSIZ] = {0.0};
- static double y[ARRSIZ] = {0.0};
- static double zs[ARRSIZ] = {0.0};
- static double z[2][ARRSIZ] = {0.0};
- static double wr = 0.0;
- static double wc = 0.0;
- static double rn = 8.0;
- static double c = 0.0;
- static double cgam = 0.0;
- static double scale = 0.0;
- static double fs = 1.0e4;
- static double dbr = 0.5;
- static double dbd = -40.0;
- static double f1 = 1.5;
- static double f2 = 2.0e3;
- static double f3 = 2.4e3;
- static double dbfac = 0.0;
- static double a = 0.0;
- static double b = 0.0;
- static double p = 0.0;
- static double q = 0.0;
- static double r = 0.0;
- static double ri = 0.0;
-
- static double t1 = 0.0;
- static double t2 = 0.0;
- static double u = 0.0;
- static double k = 0.0;
- static double kp = 0.0;
- static double m = 0.0;
- static double Kk = 0.0;
- static double Kk1 = 0.0;
- static double Kpk = 0.0;
- static double Kpk1 = 0.0;
- static double eps = 0.0;
- static double rho = 0.0;
- static double phi = 0.0;
- static double sn = 0.0;
- static double cn = 0.0;
- static double dn = 0.0;
- static double sn1 = 0.0;
- static double cn1 = 0.0;
- static double dn1 = 0.0;
- static double phi1 = 0.0;
- static double m1 = 0.0;
- static double m1p = 0.0;
- static double cang = 0.0;
- static double sang = 0.0;
- static double bw = 0.0;
- static double ang = 0.0;
- static double fnyq = 0.0;
- static double rr = 0.0;
- static double ar = 0.0;
- static double ai = 0.0;
- static double br = 0.0;
- static double bi = 0.0;
- static double qr = 0.0;
- static double qm = 0.0;
- static double qa = 0.0;
- static double sqr = 0.0;
- static double sqi = 0.0;
- static double qi = 0.0;
- static double pn = 0.0;
- static double an = 0.0;
- static double gam = 0.0;
- static double cng = 0.0;
- static int lr = 0;
- static int nt = 0;
- static int i = 0;
- static int j = 0;
- static int jt = 0;
- static int nc = 0;
- static int ii = 0;
- static int ir = 0;
- static int ni = 0;
- static int nr = 0;
-
- static int zord = 0;
- static int icnt = 0;
- static int mh = 0;
- static int jj = 0;
- static int jh = 0;
- static int jl = 0;
- static int n = 8;
- static int np = 0;
- static int nz = 0;
- static int type = 1;
- static char salut[] =
-
- {"Filter type:\n1 low pass\n2 band pass\n3 high pass\n4 band stop\n"};
-
- double abs(), exp(), log(), cos(), sin(), sqrt();
- double ellpk(), ellik(), asin(), atan();
- double cay();
-
-
- main()
- {
- char str[80];
-
- dbfac = 10.0/log(10.0);
-
- top:
-
- printf( "%s ? ", salut ); /* ask for filter type */
- gtlin( str ); /* gtlin() is like gets() */
- sscanf( str, "%d", &type );
- printf( "%d\n", type );
- if( (type <= 0) || (type > 4) )
- exit(0);
-
- getnum( "Order of filter", &rn ); /* see below for getnum() */
- n = rn;
- if( n <= 0 )
- {
- specerr:
- printf( "? Specification error\n" );
- goto top;
- }
- rn = n; /* ensure it is an integer */
- getnum( "Passband ripple, db", &dbr );
- if( dbr <= 0.0 )
- goto specerr;
- eps = exp( dbr/dbfac );
- scale = 1.0;
- if( (n & 1) == 0 )
- scale = sqrt( eps );
- eps = sqrt( eps - 1.0 );
-
- getnum( "Sampling frequency", &fs );
- if( fs <= 0.0 )
- goto specerr;
-
- fnyq = fs/2.0;
-
- getnum( "Passband edge", &f2 );
- if( (f2 <= 0.0) || (f2 >= fnyq) )
- goto specerr;
-
- if( (type & 1) == 0 )
- {
- getnum( "Other passband edge", &f1 );
- if( (f1 <= 0.0) || (f1 >= fnyq) )
- goto specerr;
- }
- else
- f1 = 0.0;
-
- if( f2 < f1 )
- {
- a = f2;
- f2 = f1;
- f1 = a;
- }
- if( type == 3 ) /* high pass */
- {
- bw = f2;
- a = fnyq;
- }
- else
- {
- bw = f2 - f1;
- a = f2;
- }
- ang = bw * PI / fs;
- cang = cos( ang );
- c = sin(ang) / cang;
- cgam = cos( (a+f1) * PI / fs ) / cang;
-
- getnum( "Stop band edge or -(db down)", &dbd );
- if( dbd > 0.0 )
- f3 = dbd;
- else
- { /* calculate band edge from db down */
- a = exp( -dbd/dbfac );
- m1 = eps/sqrt( a - 1.0 );
- m1 *= m1;
- m1p = 1.0 - m1;
- Kk1 = ellpk( m1p );
- Kpk1 = ellpk( m1 );
- q = exp( -PI * Kpk1 / (rn * Kk1) );
- k = cay(q);
- if( type >= 3 )
- wr = k;
- else
- wr = 1.0/k;
- if( type & 1 )
- {
- f3 = atan( c * wr ) * fs / PI;
- }
- else
- {
- a = c * wr;
- a *= a;
- b = a * (1.0 - cgam * cgam) + a * a;
- b = (cgam + sqrt(b))/(1.0 + a);
- f3 = (PI/2.0 - asin(b)) * fs / (2.0*PI);
- }
- }
-
- switch( type )
- {
- case 1:
- if( f3 <= f2 )
- goto specerr;
- break;
- case 2:
- if( (f3 > f2) || (f3 < f1) )
- break;
- goto specerr;
- case 3:
- if( f3 >= f2 )
- goto specerr;
- break;
- case 4:
- if( (f3 <= f1) || (f3 >= f2) )
- goto specerr;
- break;
- }
-
- ang = f3 * PI / fs;
- cang = cos(ang);
- sang = sin(ang);
-
- if( type & 1 )
- {
- wr = sang/(cang*c);
- }
- else
- {
- q = cang * cang - sang * sang;
- sang = 2.0 * cang * sang;
- cang = q;
- wr = (cgam - cang)/(sang * c);
- }
-
- if( type >= 3 )
- wr = 1.0/wr;
- if( wr < 0.0 )
- wr = -wr;
- y[0] = 1.0;
- y[1] = wr;
- if( type >= 3 )
- y[1] = 1.0/y[1];
-
- if( type & 1 )
- {
- for( i=1; i<=2; i++ )
- {
- aa[i] = atan( c * y[i-1] ) * fs / PI ;
- }
- printf( "pass band %.9E\n", aa[1] );
- printf( "stop band %.9E\n", aa[2] );
- }
- else
- {
- for( i=1; i<=2; i++ )
- {
- a = c * y[i-1];
- b = atan(a);
- q = sqrt( 1.0 + a * a - cgam * cgam );
- q = artan2( cgam, q );
- aa[i] = (q + b) * fnyq / PI;
- pp[i] = (q - b) * fnyq / PI;
- }
- printf( "pass band %.9E %.9E\n", pp[1], aa[1] );
- printf( "stop band %.9E %.9E\n", pp[2], aa[2] );
- }
-
- lampln(); /* find locations in lambda plane */
- if( (2*n+2) > ARRSIZ )
- goto toosml;
-
- spln(); /* find s plane poles and zeros */
-
- if( ((type & 1) == 0) && ((4*n+2) > ARRSIZ) )
- goto toosml;
-
- zplna(); /* convert s plane to z plane */
- zplnb();
- zplnc();
- goto top;
-
- toosml:
- printf( "Cannot continue, storage arrays too small\n" );
- goto top;
- }
-
-
- lampln()
- {
-
- wc = 1.0;
- k = wc/wr;
-
- m = k * k;
- Kk = ellpk( 1.0 - m );
- Kpk = ellpk( m );
-
- q = exp( -PI * rn * Kpk / Kk ); /* the nome of k1 */
- m1 = cay(q); /* see below */
-
- /* Note m1 = eps / sqrt( A*A - 1.0 ) */
- a = eps/m1;
- a = a * a + 1;
- a = 10.0 * log(a) / log(10.0);
- printf( "dbdown %.9E\n", a );
-
- a = 180.0 * asin( k ) / PI;
- b = 1.0/(1.0 + eps*eps);
- b = sqrt( 1.0 - b );
- printf( "theta %.9E, rho %.9E\n", a, b );
- m1 *= m1;
- m1p = 1.0 - m1;
- Kk1 = ellpk( m1p );
- Kpk1 = ellpk( m1 );
-
- r = Kpk1 * Kk / (Kk1 * Kpk);
- printf( "consistency check: n= %.14E\n", r );
-
- /* -1
- * sn j/eps\m = j ellik( atan(1/eps), m )
- */
- b = 1.0/eps;
- phi = atan( b );
- u = ellik( phi, m1p );
- printf( "phi %.7e m %.7e u %.7e\n", phi, m1p, u );
-
- /* consistency check on inverse sn */
-
- ellpj( u, m1p, &sn, &cn, &dn, &phi );
- a = sn/cn;
- printf( "consistency check: sn/cn = %.9E = %.9E = 1/eps\n", a, b );
-
-
- u = u * Kk / (rn * Kk1); /* or, u = u * Kpk / Kpk1 */
- }
-
-
- /* calculate s plane poles and zeros, normalized to wc = 1 */
- spln()
- {
- np = (n+1)/2;
- nz = n/2;
- ellpj( u, 1.0-m, &sn1, &cn1, &dn1, &phi1 );
- for( i=0; i<ARRSIZ; i++ )
- zs[i] = 0.0;
- for( i=0; i<nz; i++ )
- { /* zeros */
- a = n - 1 - i - i;
- b = (Kk * a) / rn;
- ellpj( b, m, &sn, &cn, &dn, &phi );
- lr = 2*np + 2*i;
- zs[ lr ] = 0.0;
- a = wc/(k*sn); /* k = sqrt(m) */
- zs[ lr + 1 ] = a;
- }
- for( i=0; i<np; i++ )
- { /* poles */
- a = n - 1 - i - i;
- b = a * Kk / rn;
- ellpj( b, m, &sn, &cn, &dn, &phi );
- r = k * sn * sn1;
- b = cn1*cn1 + r*r;
- a = -wc*cn*dn*sn1*cn1/b;
- lr = i + i;
- zs[lr] = a;
- b = wc*sn*dn1/b;
- zs[lr+1] = b;
- }
- if( type >= 3 )
- {
- nt = np + nz;
- for( j=0; j<nt; j++ )
- {
- ir = j + j;
- ii = ir + 1;
- b = zs[ir]*zs[ir] + zs[ii]*zs[ii];
- zs[ir] = zs[ir] / b;
- zs[ii] = zs[ii] / b;
- }
- while( np > nz )
- {
- ir = ii + 1;
- ii = ir + 1;
- nz += 1;
- zs[ir] = 0.0;
- zs[ii] = 0.0;
- }
- }
-
- printf( "s plane poles:\n" );
- j = 0;
- for( i=0; i<np+nz; i++ )
- {
- a = zs[j];
- ++j;
- b = zs[j];
- ++j;
- printf( "%.9E %.9E\n", a, b );
- if( i == np-1 )
- printf( "s plane zeros:\n" );
- }
- }
-
- getnum( line, val )
- char *line;
- double *val;
- {
- char s[40];
-
- printf( "%s = %.9E ? ", line, *val );
- gtlin( s );
- if( s[0] != '\0' )
- {
- sscanf( s, "%lf", val );
- printf( "%.9E\n", *val );
- }
- }
-
- /* cay()
- *
- * 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 .
- */
-
- double cay(q)
- double q;
- {
- double a, b, p, r;
- double t1, t2;
- double abs(), sqrt();
-
- a = 1.0;
- b = 1.0;
- r = 1.0;
- p = q;
-
- do
- {
- r *= p;
- a += 2.0 * r;
- t1 = abs( r/a );
-
- r *= p;
- b += r;
- p *= q;
- t2 = abs( 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);
- }
-
- /* zpln.c
- * Program to convert s plane poles and zeros to the z plane.
- */
-
-
- zplna()
- {
-
- for( i=0; i<ARRSIZ; i++ )
- {
- z[0][i] = 0.0;
- z[1][i] = 0.0;
- }
-
-
- nc = np;
- jt = -1;
- ii = -1;
-
- for( icnt=0; icnt<2; icnt++ )
- {
- /* The maps from s plane to z plane */
- do
- {
- ir = ii + 1;
- ii = ir + 1;
- rr = zs[ir];
- ri = zs[ii];
- b = 1.0 - rr * c;
- b *= b;
- b += ri * ri * c * c;
-
- switch( type )
- {
- case 1:
- case 3:
-
- jt += 1;
- z[0][jt] = (1.0 - (rr * rr + ri * ri)*c*c)/b;
- z[1][jt] = -2.0 * ri * c / b;
- if( ri == 0.0 )
- break;
-
- jt += 1;
- z[0][jt] = z[0][jt-1 ];
- z[1][jt] = -z[1][jt-1 ];
- break;
-
- case 2:
- case 4:
-
- rr = c * rr;
- ri = c * ri;
- b = 1.0 - rr;
- b *= b;
- b += ri * ri;
- ar = (1.0 - rr) * cgam / b;
- ai = cgam * ri / b;
- br = (1.0 - rr * rr - ri * ri) / b;
- bi = 2.0 * ri / b;
- qr = ar * ar - ai * ai - br;
- qi = 2.0 * ar * ai - bi;
- qm = sqrt( qr * qr + qi * qi );
- qm = sqrt( qm );
- qa = artan2( qr, qi ) / 2.0;
- sqr = qm * cos( qa );
- sqi = qm * sin( qa );
- jt += 1;
- z[0][jt] = ar + sqr;
- z[1][jt] = ai + sqi;
- jt += 1;
- z[0][jt] = ar - sqr;
- z[1][jt] = ai - sqi;
-
- if( ri > 0.0 )
- {
- jt += 2;
- for( i=0; i<=1; i++ )
- {
- jj = jt - 1 + i;
- z[0][jj] = z[0][jj-2];
- z[1][jj] = -z[1][jj-2];
- }
- }
- } /* end switch */
-
- }
- while( --nc > 0 );
-
- if( icnt == 0 )
- {
- zord = jt+1;
- if( nz <= 0 )
- break;
- }
- nc = nz;
- } /* end for() loop */
-
- }
-
- zplnb()
- {
-
- while( 2*zord - 1 > jt )
- {
- jt += 1;
- z[0][jt] = -1.0;
- z[1][jt] = 0.0;
- if( (type == 2) || (type == 4) )
- {
- jt += 1;
- z[0][jt] = 1.0;
- z[1][jt] = 0.0;
- }
- }
- printf( "order = %d\n", zord );
-
- /* Expand the poles and zeros into numerator and
- * denominator polynomials
- */
- for( icnt=0; icnt<2; icnt++ )
- {
- for( j=0; j<ARRSIZ; j++ )
- {
- pp[j] = 0.0;
- y[j] = 0.0;
- }
-
- pp[0] = 1.0;
-
- for( j=0; j<zord; j++ )
- {
- jj = j;
- if( icnt )
- jj += zord;
- a = z[0][jj];
- b = z[1][jj];
- for( i=0; i<=j; i++ )
- {
- jh = j - i;
- pp[jh+1] = pp[jh+1] - a * pp[jh] + b * y[jh];
- y[jh+1] = y[jh+1] - b * pp[jh] - a * y[jh];
- }
- }
-
- if( icnt == 0 )
- {
- for( j=0; j<=zord; j++ )
- aa[j] = pp[j];
- }
- }
-
- /* Scale factors of the pole and zero polynomials */
-
- a = 1.0;
-
- switch( type )
- {
-
- case 3:
-
- a = -1.0;
-
- case 1:
- case 4:
-
- pn = 1.0;
- an = 1.0;
- for( j=1; j<=zord; j++ )
- {
- pn = a * pn + pp[j];
- an = a * an + aa[j];
- }
- break;
-
- case 2:
-
- gam = PI/2.0 - asin( cgam );
- mh = zord/2;
- pn = pp[mh];
- an = aa[mh];
- ai = 0.0;
-
- if( mh > ((zord/4)*2) )
- {
- ai = 1.0;
- pn = 0.0;
- an = 0.0;
- }
-
- for( j=1; j<=mh; j++ )
- {
- a = gam * j - ai * PI / 2.0;
- cng = cos(a);
- jh = mh + j;
- jl = mh - j;
- pn = pn + cng * (pp[jh] + (1.0 - 2.0 * ai) * pp[jl]);
- an = an + cng * (aa[jh] + (1.0 - 2.0 * ai) * aa[jl]);
- }
- }
- }
-
- zplnc()
- {
-
- q = an/(pn*scale);
- printf( "constant gain factor %23.13E\n", q );
- for( j=0; j<=zord; j++ )
- pp[j] = q * pp[j];
-
- printf( "z plane Denominator Numerator\n" );
- for( j=0; j<=zord; j++ )
- {
- printf( "%2d %17.9E %17.9E\n", j, aa[j], pp[j] );
- }
- printf( "poles and zeros with corresponding quadratic factors\n" );
- for( j=0; j<zord; j++ )
- {
- a = z[0][j];
- b = z[1][j];
- if( b >= 0.0 )
- {
- printf( "pole %23.13E %23.13E\n", a, b );
- quadf( a, b, 1 );
- }
- jj = j + zord;
- a = z[0][jj];
- b = z[1][jj];
- if( b >= 0.0 )
- {
- printf( "zero %23.13E %23.13E\n", a, b );
- quadf( a, b, 0 );
- }
- }
- }
-
- /* display quadratic factors */
-
- quadf( x, y, pzflg )
- double x, y;
- int pzflg; /* 1 if poles, 0 if zeros */
- {
- double a, b, r, f, g, g0;
- double asin(), sqrt();
-
- if( y > 1.0e-16 )
- {
- a = -2.0 * x;
- b = x*x + y*y;
- }
- else
- {
- 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 * fs / (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 fnyq and D.C.
- */
-
- f = fnyq;
- g = 1.0 - a;
- g0 = 1.0 + a;
- }
-
- if( pzflg )
- {
- g = 1.0/g;
- g0 = 1.0/g0;
- }
- printf( "f0 %16.8E gain %12.4E DC gain %12.4E\n\n", f, g, g0 );
- }
-
- /* double precision absolute value */
-
- double abs(x)
- double x;
- {
- if( x < 0.0 )
- return( -x );
- else
- return( x );
- }
- #if !CEPHES
- /* polevl.c
- * p1evl.c
- *
- * Evaluate polynomial
- *
- *
- *
- * SYNOPSIS:
- *
- * int N;
- * double x, y, coef[N+1], polevl[];
- *
- * y = polevl( C, x, 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
- *
- * The function p1evl() assumes that coef[N] = 1.0 and is
- * omitted from the array. Its calling arguments are
- * otherwise the same as polevl().
- *
- *
- * 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.
- *
- */
- /* polevl.c */
-
-
- double polevl( x, coef, N )
- double x;
- double coef[];
- int N;
- {
- double ans;
- short i;
- register double *p;
-
- p = coef;
- ans = 0.0;
- i = N+1;
-
- do
- ans = ans * x + *p++;
- while( --i );
-
- return( ans );
- }
-
- /* p1evl() */
- /* N
- * Evaluate polynomial when coefficient of x is 1.0.
- * Otherwise same as polevl.
- */
-
- double p1evl( x, coef, N )
- double x;
- double coef[];
- int N;
- {
- double ans;
- register double *p;
- short i;
-
- p = coef;
- ans = x + *p++;
- i = N-1;
-
- do
- ans = ans * x + *p++;
- while( --i );
-
- return( ans );
- }
- #endif /*!CEPHES*/
-