wmse_filt.c

来自「speech signal process tools」· C语言 代码 · 共 491 行

C
491
字号
/* * This material contains unpublished, proprietary software of  * Entropic Research Laboratory, Inc. Any reproduction, distribution,  * or publication of this work must be authorized in writing by Entropic  * Research Laboratory, Inc., and must bear the notice:  * *    "Copyright (c) 1986-1990  Entropic Speech, Inc.  *    "Copyright (c) 1990-1992  Entropic Research Laboratory, Inc.  *                   All rights reserved" * * The copyright notice above does not evidence any actual or intended  * publication of this source code.      * *  Written By:   Brian Sublett   8/13/86 *  Modified for ESPS 3.0  by David Burton *  Modified for FEAFILT files by Bill Byrne, 5/24/91 *  Checked by:  * *  Description: This program designs an FIR filter using *		the weighted mean square error criterion. * *  Secrets:  See John Burg's notes on weighted mean square *	     error filter design. * *********************************************************/static char *sccs_id = "@(#)wmse_filt.c	3.11  6/23/98  ERL";char *Version="3.11", *Date="6/23/98";/* * System Includes */# include <stdio.h># include <math.h>/* * ESPS Includes */# include <esps/esps.h># include <esps/fea.h># include <esps/feafilt.h># include <esps/unix.h># include <esps/constants.h> /* * Defines */# define MX_S 2047  /* Max Number of characters in user entered comments. */# define COM_S 50  /* Extra characters in default comments. */# define SYNTAX USAGE ("wmse_filt [-P param_file] [-x debug_level][-n filt_length] [-d d_file][-w w_file] feafilt_file");# define SIXTY 60 /* maximum number of characters in input file name*/#define ERROR_EXIT(text) {(void) fprintf(stderr, "%s: %s - exiting\n", \					 argv[0], text); exit(1);}/* * ESPS Functions */    char *get_cmd_line ();    void get_fftd();int debug_level = 0;main (argc, argv)int argc;char *argv[];{        FILE *fpin, *fpout;        	/*input and output stream pointers*/    struct header *oh;	/*ptr to output file header*/    struct feafilt *frec;		/*output data structure*/    filtdesparams fdp;    int i, j, c;    int cflag = NO, w_flag = 0;		/*option flags*/    int nco = 0;			/* number of filter coefficients*/    int uniform_weight = 0, point_mode = 0; /*more flags*/    char *d_file=NULL, *w_file=NULL, *filt_file, *param_file = NULL;    double *h, *w, *hw, *filt;		/*hold filter related coefficients*/    double fs = 0.0, fs2;			/*sampling frequency of data*/    double offset, x, temp;    float *be, *wt, *g;			/*hold band edges, wts, and gains*/    float *points;    float *H, *W;    double *R, *f, *b, sin (), cos ();    double *data_real, *data_imag; /* time domain rep. of desired resp.*/    int nh, nw, nW, nH, nhw, size;	/* number of items*/    int Log2 ();		    /*compute closest power of 2*/    int nb = 0, nflag=0;    char *str, stri[3], *stu="band_edge", *stv="_des", *stb="band", *stw="_wt";    extern char *optarg;    extern optind;/* Check the command line options. */    while ((c = getopt (argc, argv, "P:x:n:d:w:n:")) != EOF){      switch (c){      case 'P':	param_file = optarg;	break;      case 'x':	debug_level = atoi(optarg);	break;      case 'n':	nco = atoi(optarg);	nflag++;	if (((int)(nco/2))*2 == nco) 	  ERROR_EXIT("wmse: Even number of coefficients not supported.")        break;      case 'd':	point_mode = 1;	d_file = optarg;	break;      case 'w':	w_file = optarg;	w_flag = 1;	if (strcmp (w_file, "-") == 0)	  uniform_weight = 1;	break;      default:	SYNTAX	}    }    /* Get the filenames. */        if (optind < argc){      filt_file = eopen("wmse_filt", argv [optind], "w", FT_FEA, FEA_FILT,			&oh, &fpout);      if (debug_level) Fprintf (stderr,"wmse: Output file is %s\n", filt_file);    }    else{      Fprintf (stderr,"wmse: No output file specified.\n");      SYNTAX      exit (1);    }    if(!param_file && !point_mode){      fprintf(stderr," no parameter file specified - exiting\n");      SYNTAX    }        /* read parameter file */    if( !point_mode){      if (read_params (param_file, SC_NOCOMMON, (char *)NULL) != 0)	ERROR_EXIT("read_params could not read the params file.");      if(!nflag && symtype("filt_length") != ST_UNDEF) 	nco = getsym_i("filt_length");      else ERROR_EXIT("filt_length parameter not specified");       if (((int)(nco/2))*2 == nco) 	 ERROR_EXIT("wmse: Even number of coefficients not supported.")       else	 offset = 0.0;      if( symtype("samp_freq") != ST_UNDEF) fs = getsym_d("samp_freq");      else ERROR_EXIT("samp_freq not found");	      fs2 = fs/2;      if( symtype("nbands") != ST_UNDEF) nb = getsym_i("nbands");      else ERROR_EXIT("nbands not found");	            be = (float *) malloc( sizeof(float) * (nb+1));      spsassert(be," Couldn't allocate space for bandedges values");      g = (float *) malloc( sizeof(float) * nb);      spsassert(g," Couldn't allocate space for desired gain values");      wt = (float *) malloc( sizeof(float) * nb);      spsassert(wt," Couldn't allocate space for weight values");      str = (char *) malloc(sizeof(char)*20);      for( i =1, j=0 ;i<=nb+1; i++, j++){	str = (char *) strcpy( str, stu);	sprintf(stri, "%d", i);	str = (char *) strcat(str, stri);	/* find edges */	if( symtype(str) != ST_UNDEF){	  if( (be[j] = getsym_d(str)) > fs2) 	    ERROR_EXIT("band edges greater than Nyquist rate");	}	else{	  fprintf(stderr,"%s: missing %d-th band edge\n", argv[0], i);	  exit(1);	}      }      for(j=1; j<=nb; j++)	if( be[j] < be[j-1] )	  ERROR_EXIT("band edges must be specified in an increasing order");      if( be[0] !=0 || be[nb] != fs2)	ERROR_EXIT("first and last bandedges must start at 0 and end at Nyquist rate");      /* normalize */      for(i=0; i<=nb; i++) be[i] = be[i] / fs;      for(i=1,j=0 ; i<=nb; i++, j++){	str = (char *) strcpy( str, stb);	sprintf(stri, "%d", i);	str = (char *) strcat(str, stri);	str = (char *) strcat(str, stv);	/* find desired value */	if( symtype(str) != ST_UNDEF)	  g[j] = getsym_d(str);	else{	  fprintf(stderr,"%s: missing desired value for band %d\n", argv[0], i);	  exit(1);	}      }      for(i=1,j=0 ; i<=nb; i++, j++){	str = (char *) strcpy( str, stb);	sprintf(stri, "%d", i);	str = (char *) strcat(str, stri);	str = (char *) strcat(str, stw);	/* find desired value */	if( symtype(str) != ST_UNDEF)	  wt[j] = getsym_d(str);	else{	  fprintf(stderr,"%s: missing weighting value for band %d\n", argv[0], i);	  exit(1);	}      }      /* Allocate the array space.  */      /* This is actually twice as many hw's as I need. */      nhw = nw = 2*nco - 1;      w = (double*) calloc ((unsigned)nw, sizeof(double));      spsassert(w != NULL, 		"Couldn't allocate space for weights");      hw = (double*) calloc ((unsigned)nhw, sizeof(double));      spsassert(hw != NULL, 		"Couldn't allocate space for combined weight and freq. resp");      for (i=0; i<nhw; i++) {	w[i] = 0.0;	hw[i] = 0.0;      }      /* Calculate points on a sum of sinc functions.  */      for (i=0; i<nhw; i++)      {	  x = i - nhw/2 + offset;	  /* sum over components from each band. */	  for (j=0; j<nb; j++){	    if (x == 0.0)	      temp = be[j+1] - be[j];	    else{	      if (be[j+1] == 0.0)		temp = 0.0;	      else		temp = be[j+1]*sin (2.0*PI*x*be[j+1])/(2*PI*x*be[j+1]);	      if (be[j] == 0)		temp -= 0.0;	      else		temp -= be[j]*sin (2.0*PI*x*be[j])/(2*PI*x*be[j]);	    }	    temp *= 2.0;	    w[i] += wt[j]*temp;	    hw[i] += g[j]*wt[j]*temp;	  }      }      if (debug_level)	(void)printarr ((char *)w, "lf", nw, "warray");    }    /* pointwise mode  */    else {                     if( !nflag ) ERROR_EXIT("must specify the -n filter length option for point mode")      if ((fpin = fopen (d_file, "r")) == NULL){	Fprintf (stderr,"Can't open %s\n", d_file);	exit (1);      }            /* Read the desired function. */      (void)fscanf(fpin, "%d", &nH);      H = (float*) calloc ((unsigned)2*nH, sizeof(float));      spsassert(H != NULL, 		"Couldn't allocate space for desired freq. response");            for (i=0; i<nH; i++)	(void)fscanf(fpin, "%f", &H[i]);            if (uniform_weight){	nW = nH;	W = (float*) calloc ((unsigned)2*nW, sizeof(float));	spsassert(W != NULL, 		  "Couldn't allocate space for weighting function");		for (i=0; i<nW; i++)	  W[i] = 1.0;      }      else{	if(w_file){	  if (strcmp (d_file, w_file) != 0){	    (void)fclose (fpin);	    if ((fpin = fopen (w_file, "r")) == NULL){	      Fprintf (stderr,"Can't open %s\n", w_file);	      exit (1);	    }	  }	}		/* Read the weighting function. */	if(EOF == fscanf(fpin, "%d", &nW))	  ERROR_EXIT("No weight values in file in pointwise mode");	if (nW != nH){	  Fprintf (stderr, "wmse:Weighting function and Desired response\n");	  Fprintf (stderr, "     must have same number of points.\n");	  Fprintf(stderr," points of desired values: %d\n", nH);	  Fprintf(stderr," points of weighting values: %d\n", nW);	  exit (1);	}	W = (float*) calloc ((unsigned)2*nW, sizeof(float));	spsassert(W != NULL, 		  "Couldn't allocate space for weighting function");	for (i=0; i<nW; i++){	  (void)fscanf(fpin, "%f", &W[i]);	  if (W[i] < 0.0){	    Fprintf (stderr,"wmse: Band weights can't be less than zero.\n");	    exit (1);	  }	}      }      /* Allocate space for the other arrays.  */      h = (double*) calloc ((unsigned)2*nH, sizeof (double));      spsassert(h != NULL, 		"Couldn't allocate space for desired freq. response");      w = (double*) calloc ((unsigned)2*nW, sizeof (double));      spsassert(w != NULL, 		"Couldn't allocate space for weights");      points   = (float*) calloc ((unsigned)nH, sizeof (float));      spsassert(points != NULL, 		"Couldn't allocate space for frequency points");      /* Fill in a points array for the output header.  */      for (i=0; i<nH; i++){	points[i] = (0.5*i)/nH;      }      /* Compute desired autocorrelation function.  */      /* Make it symmetrical. */      for (i=0; i < nH - 1; i++) {	H[2*nH-2-i] = H[i];      }      data_real = (double*) calloc ((unsigned)2*nH-2, sizeof(double));      spsassert(data_real != NULL, 		"Couldn't allocate space for real part of fft");      data_imag = (double*) calloc ((unsigned)2*nH-2, sizeof(double));      spsassert(data_imag != NULL, 		"Couldn't allocate space for imagunary part of fft");      for (i=0; i<2*nH-2; i++){	data_real[i] = H[i];	data_imag[i] = 0.0;      }      if (debug_level)	Fprintf (stderr,"wmse: Log2(%d)=%d\n", 2*nH-2, Log2(2*nH-2));      (void)get_fftd (data_real, data_imag, Log2 (2*nH-2));            /* Get the symmetric function in h. */      nh = 2*nH - 2;      h[nH-1] = data_real[0]/nh;      for (i=1; i<nH; i++){	h[nH - 1 + i] = h[nH - 1 - i] = data_real[i]/nh;      }      nh = 2*nH - 1;      if (debug_level)	(void)printarr ((char *)h, "lf", nh, "harray");      /* Make it symmetrical. */      for (i=0; i < nW - 1; i++) {	W[2*nW-2-i] = W[i];      }      for (i=0; i<2*nW-2; i++){	data_real[i] = W[i];	data_imag[i] = 0.0;      }      if (debug_level)	Fprintf (stderr,"wmse: Log2(%d)=%d\n", 2*nW-2, Log2(2*nW-2));      (void)get_fftd (data_real, data_imag, Log2 (2*nW-2));            nw = 2*nW - 2;      w[nH-1] = data_real[0]/nw;      for (i=1; i<nW; i++){	w[nW - 1 + i] = w[nW - 1 - i] = data_real[i]/nw;      }      nw = 2*nW - 1;      if (debug_level)	(void)printarr ((char *)w, "lf", nw, "warray");            /* Allocate and file convolution array.   */      nhw = nw + nh - 1;      hw = (double*) calloc ((unsigned)nhw, sizeof (double));      spsassert(hw != NULL, 	    "Couldn't allocate space for convolution array");            /* Convolve h and w to get the b's.   */      (void)convolv (h, nh, w, nw, hw, &nhw);    }        /*** Back to operations for both modes.  ***/    filt = (double*) calloc ((unsigned)nco, sizeof (double));	spsassert(filt != NULL, 	    "Couldn't allocate space for filt array");    if (debug_level)        (void)printarr ((char *)hw, "lf", nhw, "hwarray");/* Point the dummy pointers to the centers of the arrays. */    b = hw + (int)(nhw/2);    R = w + (int)(nw/2);    f = filt + (int)(nco/2);    size = nco/2 + 1;/* Get the filter solution.   */    (void)itopod (R, b, f, size);/* Copy over the lower half of filt.  */    for (i=0; i<size; i++)	filt[i] = filt[nco-1-i];    /* Set key values in output header. */    oh = new_header (FT_FEA);    (void)add_comment (oh, get_cmd_line (argc, argv));    oh->common.tag = NO;    fdp.method = WMSE;    fdp.type = FILT_ARB;    fdp.filter_complex = NO;    fdp.define_pz = NO;    fdp.g_size = 0;    fdp.nbits = 0;    if (point_mode)    {	fdp.func_spec = POINT;	fdp.nbands = 0;	fdp.bandedges = NULL;	fdp.npoints = nH;	fdp.gains = H;	fdp.wts = W;	fdp.points = points;    }    else    {	fdp.func_spec = BAND;	fdp.nbands = nb;	fdp.bandedges = be;	fdp.npoints = 0;	fdp.gains = g;	fdp.wts = wt;	fdp.points = NULL;    }    Strcpy (oh->common.prog, "wmse_filt");    Strcpy (oh->common.vers, Version);    Strcpy (oh->common.progdate, Date);/* add samp_freq as generic header item */    (void)add_genhd_d("samp_freq", &fs, 1, oh);/* add filter delay in samples */    {      int delay_samples = nco/2;      double delay = delay_samples;      (void)add_genhd_d("delay_samples", &delay, 1, oh);    }    init_feafilt_hd( oh, (long) nco, (long) 0, &fdp);    write_header (oh, fpout);/* Allocate the data record and fill in the values. */    frec = allo_feafilt_rec (oh);    *frec->num_size = nco;    *frec->denom_size = 0;/* Copy coefficients to a float array.  */    for (i=0; i<nco; i++)      frec->re_num_coeff[i] = filt[i];/* Write the data to the output file. */    put_feafilt_rec (frec, oh, fpout);        (void) fclose (fpout);    exit(0);    return(0); /*lint pleasing*/}/********************************************************//* This returns the greatest power of two <= num.  */int Log2 (num)int num;    {    int count = 0;    while ((num /= 2) != 0)	count ++;    return (count);    }

⌨️ 快捷键说明

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