iir_filt.c

来自「speech signal process tools」· C语言 代码 · 共 1,232 行 · 第 1/3 页

C
1,232
字号
    Fprintf(stderr, "\n\n%s: Desired Response type = %s\n", 	    argv[0],filt_resp_type);    Fprintf(stderr, "Poles and Zeros for ANALOG Filter\n\n");    Fprintf(stderr,"pole_size %d, zero_size %d\n", nroots_den, nroots_num);    for(i=0; i<2*filter_order; i++)      Fprintf(stderr,  "Index = %d, real_p = %f, imag_p = %f,\n\treal_z = %f, imag_z = %f\n", i, poles[i].real, poles[i].imag, zeros[i].real, zeros[i].imag);  }/* * Warp the frequencies back to the digital domain  * This is done by using the digital bilinear transform */  /*first zeros*/  blt(filter_response, sf, zeros, nroots_num);    /*now poles*/  blt(filter_response, sf, poles, nroots_den);    if(debug_level == 5 || debug_level >9){    Fprintf(stderr, "\n\nPoles and ZEROS for DIGITAL FILTER\n\n");    Fprintf(stderr,"pole_size %d, zero_size %d\n", nroots_den, nroots_num);    Fprintf(stderr, "\tFirst Poles:\n");    for(i=0; i< 2*filter_order; i++)      Fprintf(stderr,"Index = %d:\treal_pole = %lf, imag_pole = %lf\n",	      i, poles[i].real, poles[i].imag);    Fprintf(stderr, "\nNow Zeros:\n");    for(i=0; i< 2*filter_order; i++)      Fprintf(stderr,"Index = %d:\treal_zero = %lf, imag_zero = %lf\n",	      i, zeros[i].real, zeros[i].imag);  }/*  *Allocate space for numerator and denominator coefficients */    num_coeff = (double *)calloc((unsigned)2*filter_order+1, sizeof(double));    spsassert(num_coeff != NULL, "Couldn't allocate space for numerator");    den_coeff = (double *)calloc((unsigned)2*filter_order+1, sizeof(double));    spsassert(den_coeff != NULL, "Couldn't allocate space for denominator");/*  * Convert from pole and zeros to filter cooefficients  */    (void)pz_to_numden(nroots_den, poles, &num_den_co, den_coeff);    (void)pz_to_numden(nroots_num, zeros, &num_num_co, num_coeff);/* * Create output header  */    oh = new_header (FT_FEA);    fdp = (filtdesparams *) calloc( 1, sizeof(filtdesparams));    spsassert(fdp!=NULL, "can't allocate memory for header params");    oh->common.tag = NO;    fdp->define_pz = YES;     fdp->func_spec = (short)IIR;    fdp->type = filter_response;    fdp->method = filter_poly;    (void)strcpy (oh->common.prog, "iir_filt");    (void)strcpy (oh->common.vers, Version);    (void)strcpy (oh->common.progdate, Date);    (void)add_comment(oh, get_cmd_line(argc, argv));/*store command line*/    init_feafilt_hd( oh, (long)(2*filter_order+1), (long)(2*filter_order+1),		    fdp);/* * Add generic header items: samp_freq, notch_freq, and band_width */  (void)add_genhd_f("samp_freq", &sf, 1, oh);  order = filter_order;  if(filter_response == FILT_BS || filter_response == FILT_BP)    order = 2*order;  (void)add_genhd_s("filt_order", &order, 1, oh);  (void)add_genhd_f("pass_band_loss", &pass_loss, 1, oh);  (void)add_genhd_f("stop_band_loss", &stop_loss, 1, oh);  (void)add_genhd_f("band_edges", band_edges, (int)4, oh);   write_header (oh, fpout);    /*  * Allocate space for filter data record  */    frec = allo_feafilt_rec (oh);/*  * Write the data to the output file.  */    *frec->num_size = num_num_co;    for (i=0; i<num_num_co; i++)      frec->re_num_coeff[i] = num_coeff[i];    *frec->denom_size = num_den_co;    for (i=0; i<num_den_co; i++)      frec->re_denom_coeff[i] = den_coeff[i];    *frec->zero_dim = nroots_num;    for (i=0; i<nroots_num; i++)      frec->zeros[i] = zeros[i];    *frec->pole_dim = nroots_den;    for (i=0; i<nroots_den; i++)      frec->poles[i] = poles[i];/*  * set gain factor  */  (void)set_gain(filter_response, frec, gain, &gain_factor,		 band_edges, sf, filter_poly);  if(debug_level == 6 || debug_level >9){    Fprintf(stderr, "\n\n%s: Gain factor = %e\n\n", argv[0], gain_factor);    Fprintf(stderr, "\t\tNumerator and Denominator Coefficients\n\n");    Fprintf(stderr, "Numerator Coefficients\n");    for(i=0; i<num_num_co; i++)      Fprintf(stderr, "\tnum_coeff[%d] = %e\n", i, frec->re_num_coeff[i]);    Fprintf(stderr, "\nDenominator Coefficients\n");    for(i=0; i<num_den_co; i++)      Fprintf(stderr, "\tfrec->denom_coeff[%d] = %e\n", 	      i, frec->re_denom_coeff[i]);  } /* * Warn if filter order is too high, write output, and exit */  if(order >= 40 )    Fprintf(stderr, "%s: Filter design order probably too large to reliably design a\nfilter; please check filter design by plotting response.\n",argv[0]);  put_feafilt_rec (frec, oh, fpout);    (void) fclose (fpout);  exit(0);  /*NOTREACHED*/}float  prewarp(rad_freq, samp_freq)/*assumes that frequencies are expressed in radians/sec*//*implements Eqn. 7.112 in DFD by Parks and Burrus*/float rad_freq;float samp_freq;{  return((float)(2.*samp_freq*tan((double)(rad_freq/(2*samp_freq)))));}void  low_pass_proto(b_edges, filter_response, filter_poly)/* find critical low pass frequencies corresponding to filter specification*/float *b_edges;		    /*band edges for elliptical filter*/int filter_response;	    /* filter response type*/int filter_poly;	    /* filter design polynomial*/{  float ctr;  float tmp;    switch(filter_response){	case FILT_LP:    /*low pass cutoff already defined*/    break;  case FILT_HP:    /* replace S by 1/S */    tmp = b_edges[1];    b_edges[1] = 1./b_edges[0];   /* lowpass proto pass */    b_edges[0] = 1./tmp;   /* lowpass proto stop */    break;  case FILT_BP:    /* use Eqn 7.97 to get center freq (ctr)        and Eqn. 7.98 to get cutoff freq */        ctr = (float)sqrt((double)(b_edges[1]*b_edges[2]));    b_edges[1] = (SQRD(b_edges[2]) - SQRD(ctr))/b_edges[2];    b_edges[2] = (SQRD(b_edges[3]) - SQRD(ctr))/b_edges[3];    if(b_edges[2] < 0) b_edges[2] = FLT_MAX;    b_edges[3] = (SQRD(ctr) - SQRD(b_edges[0]))/b_edges[0];    if(b_edges[3] < 0) b_edges[3] = FLT_MAX;        if(b_edges[3] < b_edges[2])      b_edges[2] = b_edges[3];    b_edges[0] = b_edges[1];    /* lowpass proto pass band */    b_edges[1] = b_edges[2];    /* lowpass proto stop band */    b_edges[2] = ctr;           /* orig. band pass center */    break;  case FILT_BS:    /* use Eqn. 7.97 to get center freq (ctr) and Eqn. 7.100       to get the cutoff frequency */        ctr = (float)sqrt((double)(b_edges[0]*b_edges[3]));    b_edges[0] = b_edges[0]/(ctr*ctr - SQRD(b_edges[0]));    b_edges[1] = b_edges[1]/(ctr*ctr - SQRD(b_edges[1]));    if(b_edges[1] < 0) b_edges[1] = FLT_MAX;    b_edges[2] = b_edges[2]/(SQRD(b_edges[2]) - ctr*ctr);    if(b_edges[2] < 0) b_edges[2] = FLT_MAX;    if(b_edges[2] < b_edges[1])      b_edges[1] = b_edges[2];    b_edges[2] = ctr;           /* orig. band pass center */    break;  default:    Fprintf(stderr, "low_pass_pro: Invalid filter response type.\n");    exit(1);  }}int determ_order(filter_poly, pass_loss, stop_loss, freq)int filter_poly;float stop_loss, pass_loss;            /* assumed in dBs */float *freq;{  float c1, c2;  float epsilon, tmp, junk;  int order;  c1 = pow(10., -pass_loss * .05);  c2 = pow(10., -stop_loss * .05);  switch(filter_poly){  case BUTTERWORTH:    c1 = 1./SQRD(c1) - 1.;    c2 = 1./SQRD(c2) - 1.;    tmp =  log(c2/c1) / (2 * log(freq[1]/freq[0])); /*order */    order =  1 + tmp;                             /*order */    freq[3] = pow(10., -log10(c1)/(2*tmp)) * freq[0];    /* 3dB frequecny */    return(order);    break;  case CHEBYSHEV1:    epsilon = sqrt(pow(10., pass_loss*.1) - 1);    tmp =  sqrt(1-c2*c2) / (epsilon * c2*c2);    order = 1 + ARCCOSH(tmp)/ARCCOSH(freq[1]/freq[0]);    return(order);    break;  case CHEBYSHEV2:    epsilon = 1. / sqrt(pow(10., stop_loss*.1) - 1);    tmp = c1 / ( epsilon * sqrt( 1-c1*c1 ));    order = 1 + ARCCOSH(tmp)/ARCCOSH(freq[1]/freq[0]);    return(order);    break;  case ELLIPTICAL:    order = elliptical_p_and_z(1, NULL, NULL, freq, NULL,			       pass_loss, stop_loss, NULL, NULL);    return(order);    break;  default:    Fprintf(stderr,"determ_order: Invalid filter polynomial type.\n");    exit(1);  }}voidpoles_and_zeros( poles, zeros, cut_freq, order, p_loss, s_loss, type, np, nz)/* find poles and zeros corresponding to low pass response*/double_cplx *poles, *zeros;	/*real and imag poles and zeros*/float *cut_freq;		/*cutoff frequency*/int order;			/*desired filter order*/float p_loss;			/* pass band loss*/float s_loss;			/*stop band loss*/int type;			/*filter polynomial type*/int *np, *nz;                   /* size of poles and zeros, real is a single,				   complex is as double */{    int count, i, half_order;    double arg, temp_r, temp_i;    half_order = (order+1)/2; /* take advantage of integer division*/    if (2*half_order == order)	count = 1;            /* order is even */    else	count = 0;            /* order is odd */    switch(type){    case BUTTERWORTH:      /* Use Eqn. 7.13 for poles; zeros are at frequency = infinity*/      *nz = order;      for( i=0; i< *nz; i++ ){      /* treate real zero as a single */	zeros[i].real = 0;	zeros[i].imag = FLT_MAX;      }      *np = half_order;      for(i = 0; i < *np; i++){	arg = (PI/2.)*count/order;	count += 2;	poles[i].real = cut_freq[3]*-cos(arg);	poles[i].imag = cut_freq[3]*sin(arg);      }      break;    case CHEBYSHEV1:      /* Use Eqn. 7.36 to calculate epsilon, eqn 7.29 to	 calculate v, and 7.33 to calculate poles.	 The zeros all occur at infinity. */      {	double epsilon, v, sinhm, coshm;	*nz = order;	for( i=0; i< *nz; i++ ){      /* treate real zero as a single */	  zeros[i].real = 0;	  zeros[i].imag = FLT_MAX;	}	epsilon = sqrt(pow((double)10., (.1*p_loss)) - 1);	v = ARCSINH(1./epsilon)/order;	sinhm = sinh(v);	coshm = cosh(v);	*np = half_order;	for(i = 0; i < *np; i++){	  arg = (PI/2.)*count/order;	  count += 2;	  poles[i].real = cut_freq[0]*sinhm*-cos(arg);	  poles[i].imag = cut_freq[0]*coshm*sin(arg);	}      }      break;    case CHEBYSHEV2:      {	double epsilon, v, sinhm, coshm;	*nz = *np = half_order;	epsilon = 1.0 / sqrt(pow((double)10., (.1*s_loss)) - 1);	v = ARCSINH(1./epsilon)/order;	sinhm = sinh(v);	coshm = cosh(v);	for(i = 0; i < half_order; i++){	  arg = (PI/2.)*count/order;	  zeros[i].real = 0.;	  if(count != 0)	    zeros[i].imag = cut_freq[1]/sin(arg);	  else	   /* odd order, get a real zero at inf. and a real pole */	    zeros[i].imag = FLT_MAX;	  count += 2;	  temp_r = sinhm*-cos(arg);	  temp_i = coshm*sin(arg);	  poles[i].real = cut_freq[1] *temp_r/(SQRD(temp_r)+SQRD(temp_i));	  poles[i].imag = cut_freq[1] *temp_i/(SQRD(temp_r)+SQRD(temp_i));	}      }      break;    }}intelliptical_p_and_z(init, poles, zeros, b_edges, order, p_loss, s_loss, np, nz)int init;                       /* a flag to find order */double_cplx *poles, *zeros;	/*real and imag poles and zeros*/float *b_edges;			/*pass and stop band frequencies*/int order;			/*desired filter order*/float p_loss;			/* pass band loss*/float s_loss;			/*stop band loss*/int *np, *nz;                   /* size of poles and zeros */{  static double epsilon, k, kc, K, KC, k1, k1c, K1, K1C;  double v0, snc, sn, cnc, cn, dnc, dn;  double cei(), arcsc(), fk();  void elp();  int half_order, count, i, j;    if(init){    epsilon = sqrt(pow((double)10., (.1*p_loss)) - 1);    k = b_edges[0] / b_edges[1];             /* passband over stop band */    kc = sqrt(1-k*k);    k1 = epsilon / sqrt( pow((double)10., (.1*s_loss)) -1 );    k1c = sqrt(1-k1*k1);    K = cei(kc);    KC = cei(k);    K1 = cei(k1c);    K1C = cei(k1);        /* recalculate k1 */    return( (int) K*K1C/(K1*KC) + 1.);  }  k1 = fk(order*KC/K);  k1c = sqrt(1-k1*k1);  K1 = cei(k1c);  half_order = (order+1)/2; /* take advantage of integer division*/    if (2*half_order == order)    count = 1;            /* order is even */  else    count = 0;            /* order is odd */    v0 = (K/(K1* order)) * arcsc(1/epsilon, k1);  elp(v0, k, &snc, &cnc, &dnc);  if(debug_level > 20)    fprintf(stderr,"epsilon %f k %f kc %f K %f KC %f\n\tk1 %f k1c %f K1 %f K1C %f\n\tv0 %f snc %f cnc %f dnc %f\n\torder %d \n", epsilon, k, kc, K, KC, k1, k1c, K1, K1C, v0, snc, cnc, dnc, order);  zeros[0].imag = FLT_MAX;  for(i=0, j=0; i< half_order; i++, j++){    elp(K*count/order, kc, &sn, &cn, &dn);    if(debug_level >20 )      fprintf(stderr,"sn %f cn %f dn %f\n", sn, cn, dn);    zeros[j].real = 0;    if( count != 0 ) zeros[j].imag = b_edges[1]/sn;/*    else {      zeros[++j].real = 0;      zeros[j].imag = FLT_MAX;    }*/    poles[i].real = -b_edges[0] * snc*cnc*cn*dn/(1-dn*snc*dn*snc);    poles[i].imag = b_edges[0] * dnc*sn/(1-dn*snc*dn*snc);    count += 2;  }  *np = i;  *nz = j;}double fk(u)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?