iir_filt.c.sta

来自「speech signal process tools」· STA 代码 · 共 1,535 行 · 第 1/3 页

STA
1,535
字号
/*********** Start the filter design processs ***********/    /*     The basic design process is the following:	A. Prewarp the critical frequencies to the analog frequency	    domain - this is done by prewarp().	B. Find find critical frequencies for analog low pass	    prototype filter - this is done by low_pass_proto().	C. Find the poles and zeros for the prototype low pass	    filter - this is done by poles_and_zeros() for 	    BUTTERWORTH, CHEBYSHEV1, and CHEBYSHEV2 filters and by	    elliptical_p_and_z() for ELLIPTICAL fitlers.	D. Find the poles and zeros of the analog version of the	    desired filter type (LP, HP, BP, or BS) - this is done	    by freq_xfrm().	E. Find the corresponding poles and zeros in digital frequency	    domain -  this is done by blt().	F. Find the numerator and demoninator coeffs corressponding to	    the poles and zeros - this is done by pz_to_filt_co().	G. Modify the numerator coefficients so that the gain equal	    to the value specified - this is done by set_gain().	H. Write out the appropriate generics and the data record.    *//* prewarp frequencies */    /*Convert digital frequencies (Hz.) to analog frequencies (radians)*/    switch(filter_poly){	case BUTTERWORTH:	case CHEBYSHEV1:	case CHEBYSHEV2:	    for(i=0; i<num_of_3dBs; i++)		warped_3dBs[i] = prewarp(2*PI*three_dBs[i], sf);	    break;	case ELLIPTICAL:	    Fprintf(stderr, 	       "iir_filt: Elliptical filters not supported yet - exiting\n");	    exit(1);/*	    for(i=0; i<num_of_band_edges; i++)		warped_edges[i] = prewarp(2*PI*band_edges[i], sf);	    break;*/	default:	    /*should never get here*/	    Fprintf(stderr,"iir_filt: Invalid filt_method\n");	    exit(1);    }/*DEBUG*/    if (debug_level == 1 || debug_level > 9){	Fprintf(stderr, "\n\t\tPREWARP FREQUENCIES\n");	Fprintf(stderr, 	"iir_filt: Convert from Digital to Analog Frequency Domain\n");	if(filter_poly == ELLIPTICAL)	    for(i=0;i<num_of_band_edges; i++)		    Fprintf(stderr,     "iir_filt: critical freq[%d] = %f Hz, warped freq[%d] = %f radians\n",		     i, band_edges[i], i, warped_edges[i]);	else	    for(i=0; i<num_of_3dBs; i++)		Fprintf(stderr,		"critical freq[%d] = %f Hz., warped freq[%d] = %f radians\n",		    i, three_dBs[i], i, warped_3dBs[i]);    }/*END DEBUG*//* compute low pass prototype 3 dB frequency */    low_pass_proto(warped_3dBs, warped_edges, filter_response, filter_poly);/*DEBUG*/    if(debug_level == 2 || debug_level >9){	Fprintf(stderr, 		"\n\niir_filt: ANALOG LOWPASS PROTOTYPE FREQUENCIES\n");	if(filter_poly == ELLIPTICAL)	    Fprintf(stderr,"pass freq = %g radian, stop freq = %g radian\n",		warped_edges[0], warped_edges[1]);	else	    Fprintf(stderr,"pass freq = %f radian, stop freq = %f radian\n",		warped_3dBs[0], warped_3dBs[1]);    }/*END DEBUG*//* Allocate space for pole and zero coefficients - real and imaginary parts*/    r_pole = (double *)calloc((unsigned)2*(filter_order)+4, sizeof(double));    spsassert(r_pole != NULL,			"Couldn't allocate space for real part poles\n");    r_zero = (double *)calloc((unsigned)2*(filter_order)+4, sizeof(double));    spsassert(r_zero != NULL,			"Couldn't allocate space for real part zeros\n");    i_pole = (double *)calloc((unsigned)2*(filter_order)+4, sizeof(double));    spsassert(i_pole != NULL,			"Couldn't allocate space for imag part poles\n");    i_zero = (double *)calloc((unsigned)2*(filter_order)+4, sizeof(double));    spsassert(i_zero != NULL,			"Couldn't allocate space for imag part zeros\n");/* find poles and zeros for prototype low pass filter */    switch(filter_poly){	case BUTTERWORTH:	case CHEBYSHEV1:	case CHEBYSHEV2:poles_and_zeros(r_pole, r_zero, i_pole, i_zero, warped_3dBs,filter_order, pass_loss, stop_loss, filter_poly);	    break;	case ELLIPTICAL:elliptical_p_and_z(r_pole, r_zero, i_pole, i_zero, warped_edges,filter_order, pass_loss, stop_loss);	    break;	default:	    Fprintf(stderr, "iir_filt: Invalid filter polynomial type\n");	    exit(1);    }/*DEBUG*/    if(debug_level == 3 || debug_level >9){	Fprintf(stderr, 	    "\n\niir_filt: ANALOG LOW PASS PROTOTYPE POLES AND ZEROS\n\n");	for(i=0; i<=(filter_order+1)/2; i++)	    Fprintf(stderr,     "Index %d\treal_p = %lf, imag_p = %lf\n\treal_z = %lf, imag_z = %lg\n\n",		i, r_pole[i], i_pole[i], r_zero[i], i_zero[i]);    }/*END DEBUG*//* transform low pass prototype to required response type*/    switch(filter_poly){	case ELLIPTICAL:	/*first zeros */   freq_xfrm(filter_response, r_zero, i_zero, warped_edges[3], filter_order);	/* now poles*/   freq_xfrm(filter_response, r_pole, i_pole, warped_edges[3], filter_order);	    break;	case BUTTERWORTH:	case CHEBYSHEV1:	case CHEBYSHEV2:	/* first zeros */    freq_xfrm(filter_response, r_zero, i_zero, warped_3dBs[2], filter_order);	/* now poles*/    freq_xfrm(filter_response, r_pole, i_pole, warped_3dBs[2], filter_order);	    break;	default:	    Fprintf(stderr, "iir_filt: Invalid filter polynomial type\n");	    exit(1);    }/*DEBUG*/    if(debug_level == 4 || debug_level > 9){	Fprintf(stderr, 	    "\n\niir_filt: Desired Response type = %s\n", filt_resp_type);	Fprintf(stderr, "Poles and Zeros for ANALOG Filter\n\n");	for(i=0; i<=filter_order+1; i++)	    Fprintf(stderr,   "Index = %d, real_p = %lf, imag_p = %lf,\n\treal_z = %lf, imag_z = %lg\n",		i, r_pole[i], i_pole[i], r_zero[i], i_zero[i]);    }/*END DEBUG*//* Warp the frequencies back to the digital domain *//* This is done by using the digital bilinear transform*/    /*first zeros*/    blt(filter_order, filter_response, sf, r_zero, i_zero);    /*now poles*/    blt(filter_order, filter_response, sf, r_pole, i_pole);/*DEBUG*/    if(debug_level == 5 || debug_level >9){	Fprintf(stderr, "\n\nPoles and ZEROS for DIGITAL FILTER\n\n");	Fprintf(stderr, "\tFirst Poles:\n");	for(i=0; i< 2*((filter_order+1)/2); i++)	    Fprintf(stderr,  "Index = %d:\treal_pole = %lf, imag_pole = %lf\n",i, r_pole[i], i_pole[i]);	    Fprintf(stderr, "\nNow Zeros:\n");	    for(i=0; i< 2*((filter_order+1)/2); i++)		Fprintf(stderr,  "Index = %d:\treal_zero = %lf, imag_zero = %lf\n",i, r_zero[i], i_zero[i]);    }/*END DEBUG*//* Convert poles and zeros into numerator and denominator polynomials*//* Allocate space for numerator and denominator coefficients*/    num_coeff = (float *)calloc((unsigned)2*filter_order+4, sizeof(float));    spsassert(num_coeff != NULL, "Couldn't allocate space for numerator");    den_coeff = (float *)calloc((unsigned)2*filter_order+4, sizeof(float));    spsassert(den_coeff != NULL, "Couldn't allocate space for denominator");    nroots_num = (filter_order+1)/2;    nroots_den = (filter_order+1)/2;    if(filter_response == FILT_BP || filter_response == FILT_BS){	nroots_num = filter_order;	nroots_den = nroots_num;    }/* Convert from pole and zeros to filter cooefficients */    (void)pz_to_filt_co(filter_response, filter_order, nroots_num, 	    nroots_den, r_zero, i_zero, r_pole, i_pole, &num_den_co, 	    den_coeff, &num_num_co, num_coeff);/* set gain factor */    (void)set_gain(filter_response, gain, num_num_co, num_coeff, num_den_co,    den_coeff, &gain_factor, three_dBs, band_edges, sf, filter_poly);/*DEBUG*/    if(debug_level == 6 || debug_level >9){	Fprintf(stderr, "\n\niir_filt: Gain factor = %f\n\n", 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] = %f\n", i, num_coeff[i]);	Fprintf(stderr, "\nDenominator Coefficients\n");	for(i=0; i<num_den_co; i++)	    Fprintf(stderr, "\tden_coeff[%d] = %f\n", i, den_coeff[i]);    }/*END DEBUG*//* set key values in output header. */    oh->common.tag = NO;    oh->hd.filt->max_num = (short)(2*filter_order+4);    oh->hd.filt->max_den = (short)(2*filter_order+4);    oh->hd.filt->func_spec = (short)IIR;    oh->hd.filt->type = filter_response;    oh->hd.filt->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*//* * 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);    switch(filter_poly){	case BUTTERWORTH:	    (void)add_genhd_f("3dB_freqs", three_dBs, (int)2, oh);	    break;	case CHEBYSHEV1:	    (void)add_genhd_f("3dB_freqs", three_dBs, (int)2, oh);	    (void)add_genhd_f("pass_band_loss", &pass_loss, 1, oh);	    break;	case CHEBYSHEV2:	    (void)add_genhd_f("3dB_freqs", three_dBs, (int)2, oh);	    (void)add_genhd_f("stop_band_loss", &stop_loss, 1, oh);	    break;	case ELLIPTICAL:	    (void)add_genhd_f("3dB_freqs", band_edges, (int)4, oh);	    (void)add_genhd_f("pass_band_loss", &pass_loss, 1, oh);	    (void)add_genhd_f("stop_band_loss", &stop_loss, 1, oh);	    break;    }/* * Warn if filter order is too high*/    if(order >= 14)	Fprintf(stderr, "iir_filt: Filter design order probably too large to reliably design a\nfilter; please check filter design by plotting response.\n");    write_header (oh, fpout);    frec = allo_filt_rec (oh);/* Write the data to the output file. */    frec->filt_func.nsiz = num_num_co;    frec->filt_func.dsiz = num_den_co;    frec->filt_func.zeros = num_coeff;    frec->filt_func.poles  = den_coeff;    put_filt_rec (frec, oh, fpout);    (void) fclose (fpout);    exit(0);    /*NOTREACHED*/}floatprewarp(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)))));}voidlow_pass_proto(three_dBs, b_edges, filter_response, filter_poly)/* find critical low pass frequencies corresponding to filter specification*/float *three_dBs;	    /*cut off frequencies*/float *b_edges;		    /*band edges for elliptical filter*/int filter_response;	    /* filter response type*/int filter_poly;	    /* filter design polynomial*/{    float ctr;    switch(filter_response){	case FILT_LP:	    /*low pass cutoff already defined*/	    three_dBs[1] = three_dBs[0];	    break;	case FILT_HP:	    /* replace S by 1/S */	    if(filter_poly == ELLIPTICAL){		b_edges[0] = 1./b_edges[0];		b_edges[1] = 1./b_edges[1];	    }	    else{ /*BUTTERWORTH, CHEBYSHEV1, or CHEBYSHEV2*/		three_dBs[0] = 1./three_dBs[0];	    		three_dBs[1] = three_dBs[0];	    }	    break;	case FILT_BP:	    /* use Eqn 7.97 to get center freq (ctr) 		and Eqn. 7.98 to get cutoff freq */	    	    if(filter_poly == ELLIPTICAL){		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];		b_edges[3] = (SQRD(ctr) - SQRD(b_edges[0]))/b_edges[0];		if(b_edges[3] < b_edges[2])			b_edges[2] = b_edges[3];		/*shift all the values circularly around one place*/		b_edges[0] = b_edges[1];		b_edges[1] = b_edges[2];		b_edges[2] = b_edges[3];		b_edges[3] = ctr;	    }	    else{/* everything else*/		ctr = (float)sqrt((double)(three_dBs[0] * three_dBs[1]));             three_dBs[0] = (SQRD(three_dBs[1]) -ctr*ctr)/three_dBs[1];		three_dBs[1] = three_dBs[0];		three_dBs[2] = ctr;	    }	    break;	case FILT_BS:	    /* use Eqn. 7.97 to get center freq (ctr) and Eqn. 7.100		to get the cutoff frequency */	    if(filter_poly == ELLIPTICAL){		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]));		b_edges[2] = b_edges[2]/(SQRD(b_edges[2]) - ctr*ctr);		b_edges[3] = ctr;		if(b_edges[2] < b_edges[1])		    b_edges[1] = b_edges[2];	    }	    else{/*do the rest*/		ctr = sqrt(three_dBs[0]*three_dBs[1]);		three_dBs[0] = three_dBs[1]/(SQRD(three_dBs[1]) - SQRD(ctr));		three_dBs[1] = three_dBs[0];		three_dBs[2] = ctr;	    }	    break;	default:	    Fprintf(stderr, "iir_filt: Invalid filter response type.\n");	    exit(1);    }}voidpoles_and_zeros(r_p, r_z, i_p, i_z, cut_freq, order, p_loss, s_loss, type)/* find poles and zeros corresponding to low pass response*/double *r_p, *r_z, *i_p, *i_z;	/*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 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;    else	count = 0;    switch(type){	case BUTTERWORTH:	    /* Use Eqn. 7.13 for poles; zeros are at frequency = infinity*/	    for(i = 0; i < half_order; i++){		arg = (PI/2.)*count/order;		count += 2;		r_z[i] = 0.;		i_z[i] = FLT_MAX;		r_p[i] = cut_freq[0]*-cos(arg);		i_p[i] = cut_freq[0]*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;	    epsilon = sqrt(pow((double)10., (.1*p_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;		count += 2;		r_z[i] = 0.;		i_z[i] = FLT_MAX;		r_p[i] = cut_freq[0]*sinhm*-cos(arg);		i_p[i] = cut_freq[0]*coshm*sin(arg);	    }	    }	    break;	case CHEBYSHEV2:	    {	    double epsilon, v, sinhm, coshm;	    epsilon = 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;		count += 2;		r_z[i] = 0.;		if(count != 0)		    i_z[i] = cut_freq[1]/sin(arg);		else		    i_z[i] = FLT_MAX;		temp_r = sinhm*-cos(arg);		temp_i = coshm*sin(arg);		r_p[i] = cut_freq[1]*temp_r/(SQRD((temp_r)+SQRD(temp_i)));		i_p[i] = cut_freq[1]*temp_i/(SQRD((temp_r)+SQRD(temp_i)));	    }	    }	    break;    }}voidelliptical_p_and_z(r_p, r_z, i_p, i_z, b_edges, order, p_loss, s_loss)double *r_p, *r_z, *i_p, *i_z;	/*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*/{    return;}voidfreq_xfrm(type, Real, Imag, cntr, order)/* change low pass prototype to desired response type*/int type;	    /* filter response type */double Real[];	    /*real part of coefficients*/double Imag[];	    /*imaginary part of coefficients*/float cntr;	    /*warped geometric center frequency*/int order;	    /*desired filter order */{    int i, upper_order;    double_cplx a, b, c;    upper_order = 2*((order-1)/2)+1;    switch(type){	case FILT_LP:

⌨️ 快捷键说明

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