⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ifft.c

📁 fft control
💻 C
字号:
/*	name...
		ifft

	bugs...
		Should do transforms on several functions (-b option).

	history...
		-- 1.21 --
		1 Jun 87	-a option suppresses abscissas on output.
		-- 1.20 --
		11 May 87	Using "float" rather than "double" variables
		8 May 87	Reading into doubles and performing range check
					before converting to floats.
		-- 1.1 --
		6 Apr 87	Default abscissa step is 1 (rather than 0!)
					Some printing removed.
		-- 1.0 --
		20 Mar 87	default output to STDOUT
		8 Feb 87	split off from fft program.

	performance...
		128 point transform in 14.43 sec with 7.5 MHz V-20 and no 8087.
		4096 point transform in 1:53.15 with 6 MHz 80286 and 4 MHz 80287.
*/
#include <stdio.h>
#include <math.h>

#define VERSION "1.21"


#define BIGFLOAT 6.e38	/* no floats larger than this  */
#define ENTRIES 4098
#define MAXLABELS 50
#define BUFSIZE 200
#define FLOAT float	/* change to "double" to restore higher precision */

FILE *ifile=stdin, *ofile=stdout;

char buffer[128], iname[35], oname[35];
char buf[BUFSIZE];
char *label_array[MAXLABELS];
char **p_text=label_array;


int m,			/* number of input values to be retained */
n,				/* number of data points to be Fourier transformed */
*nnn,			/* points to n */
breaking,		/* nonzero if finding separate transforms for several functions */
labels,			/* number of labels stored */
automatic_abscissas, /* nonzero if abscissas to be calculated */
abscissa_arguments,
keeping=0,		/* if nonzero, the number of input values to be kept */
f_arguments=0,
x_arguments=0,
index_array[MAXLABELS],	/* indexes into x and y */
*p_data=index_array;

FLOAT *x,		/* frequency values */
*y;				/* magnitudes (on input) or voltages (on output) */
double abscissa,
origin,			/* abscissa value to be treated as time zero */
abscissa_step=1.,
fmin, fmax,
xmin, xmax;		/* first & last data points to be used */

main(argc, argv) int argc; char **argv;
{	int i;

	{double junk;
	sscanf("3.4","%lf",&junk);		/* workaround for DESMET sscanf bug */
	}

	argc = args(argc, argv);		/* fetch switches */

	read_data(argc, argv);
	pad();

/*	fprintf(stderr, "\n\n   computing inverse fft\n\n");  */
	ifft(&n, x, y);

	i=1;
	while(1)
		{if(!automatic_abscissas)  fprintf(ofile, "%15.6g", x[i] + origin);
		fprintf(ofile, "%15.6g", y[i]);
		if(++i>n) break;
		fprintf(ofile, "\n");
		}
	fprintf(ofile, " \"\"\n");
	if(ofile!=stdout)
		{fclose(ofile);
		}
}

pad()
{	int m;
	double freq, df;
	for (m=2; m<ENTRIES; m *= 2)
		if (n<=m+1) break;
	if(n==m+1) return;
/*	printf("transforming %d points after padding\n", m+1);  */
	freq=x[n];
	df=freq-x[n-1];
	while(n<=m)
		{n++;
		freq += df;
		x[n]=freq;
		y[2*n-1]=y[2*n]=0.;
		}
}

listt(y, i, j) FLOAT y[]; int i, j;	/* display y[i] through y[j]  */
{	while (i<=j) {printf("%4d %15.9f \n", i, y[i]); ++i;}
}


read_data(argc, argv) int argc; char **argv;
{	int i, j, length, nums;
	double xx, yyr, yyi, d, *pd, sum;
	char *s, *t, *stop;
	char *malloc();
	char *strchr();

	x=(FLOAT *)malloc(ENTRIES*sizeof(FLOAT));
	y=(FLOAT *)malloc(2*ENTRIES*sizeof(FLOAT));
	if(x==0 || y==0) {fprintf(stderr, "can\'t allocate buffer"); exit(1);}
	argc--; argv++;
	if(strchr(argv[0], '?')) help();
/*            open input file         */
	if(argc && *argv[0]!='-')
		{ifile=fopen(argv[0], "r");
		if(ifile==0) {fprintf(stderr, "file %s not found\n", argv[0]); exit(1);}
		strcpy(iname, argv[0]);
		argc--; argv++;
		}
/*            open output file         */
	if(argc && *argv[0]!='-')
		{strcpy(oname, argv[0]);
		argc--; argv++;
		unlink(oname);
		if((ofile=fopen(oname, "w"))==0)
			{fprintf(stderr, "can\'t open output file %s", oname);
			exit(1);
			}		
		}

	fprint_cmd(ofile, "; ifft %s\n");

	p_data[0]=-1;
	i=1;		/* note x[0] and y[0] aren't defined */
	while(i<ENTRIES)
		{if(fgets(buf, BUFSIZE, ifile)==0) break;
		t=buf;
		while(*t && isspace(*t)) t++;
		if(*t == 0) continue;		/* skip blank lines */
		buf[strlen(buf)-1]=0;		/* zero out the line feed */
		if(buf[0]==';')				/* skip comment */
			{fprintf(ofile, "%s\n", buf); continue;
			}
		if(t = strchr(buf, ';')) *t=0;	/* zap same-line comment */
		if(automatic_abscissas)
			{xx=abscissa;
			abscissa+=abscissa_step;
			sscanf(buf, "%lf %lf", &yyr, &yyi);
			}
		else
			{sscanf(buf, "%lf %lf %lf", &xx, &yyr, &yyi);
			}
		range_check(xx); range_check(yyr); range_check(yyi);
		x[i]=xx; y[i+i-1]=yyr; y[i+i]=yyi; /* convert doubles to floats here */
		s=buf;                      /* start looking for label */
		nums=3;
		if(automatic_abscissas) nums--;
		while(nums--)					/* skip the numbers */
			{while(*s==' ')s++;
			while(*s && (*s!=' '))s++;
			}
		while(*s==' ')s++;
		if((length=strlen(s))&&(labels<MAXLABELS))
			{if(*s=='\"')           /* label in quotes */
				{t=s+1;
				while(*t && (*t!='\"')) t++;
				t++;
				}
			else                    /* label without quotes */
				{t=s;
				while(*t && (*t!=' '))t++;
				}
			*t=0;
			length=t-s;
			p_data[labels]=i;
			p_text[labels]=(char *)malloc(length+1);
			if(p_text[labels]) strcpy(p_text[labels++], s);
			}
		i++;
		}
	n=i-1;
	if(breaking && (!labels || p_data[labels-1]!=n-1))
		{p_data[labels]=i-1;
		if(p_text[labels]=(char *)malloc(1)) *p_text[labels++]=0;
		}
}

/* check whether number is too big for a float */
range_check(x) double x;
{	if(fabs(x)>BIGFLOAT)
		{printf("input number too large: %f\n", x);
		exit(1);
		}
}

int streq(a,b) char *a,*b;
{	while(*a)
		{if(*a!=*b)return 0;
		a++; b++;
		}
	return (*b==0);
}

/* get_parameter - process one command line option
		(return # parameters used) */
get_parameter(argc, argv) int argc; char **argv;
{	int i;
	if(streq(*argv, "-a"))
		{i=get_double(argc, argv, 1, &abscissa_step, &abscissa, &abscissa);
		abscissa_arguments=i-1;
		automatic_abscissas=1;
		return i;
		}
	else if(streq(*argv, "-z"))
		{origin=0.;
		i=get_double(argc, argv, 1, &origin, &fmax, &fmax);
		return i;
		}

	else gripe(argv);
}

char *message[]={
"ifft   version ", VERSION,
" - calculate inverse fast Fourier transform \n",
"                     of frequency domain function\n",
"usage: ifft  [infile  [outfile]]  [options]\n",
"options are:\n",
"  -a  [step]     automatic abscissas \n",
"  -z  val        add <val> to each abscissa value\n",
/*
"  -b             break input after each label, \n",
"                 find separate transforms\n",
"  -f  min [max]  minimum and maximum frequencies\n",
"  -t  min [max]  minimum and maximum times\n",
*/
0
};


/*	name...
		fft

	purpose...
		perform forward or inverse FFT

	history...
		May 84  translated from FORTRAN
		12 Jun 84  diagnostic printouts shortened
*/

	int ip, n2, i, j, k, nu, nn;
	int k1n2, l, nu1;
	double arg, p, q, s, c;
	double ninv, time, dt, freq, df;
	double xplus, xminus, yplus, yminus;
	double uplus, uminus, vplus, vminus;

/*	format frequency domain data so its
	inverse fast Fourier transform can be calculated

	on input:
	n is one more than a power of 2:  n == 3, 9, 17, 33, 65, ...
	x[1...n]  has  f(0)  f(1)  f(2)  ...  f(n-1)
	y[1...2n] has  Qr(0) Qi(0)   Qr(1) Qi(1)  ...  Qr(n-1) Qi(n-1)

	on output:
	n has been increased:  n = 2*n-1
	x[1...n] has  t(0)  t(1)  t(2)  ...  t(n-1)
	y[1...n] has  q(0)  q(1)  q(2)  ...  q(n-1)
*/
ifft(nnn, x, y) int *nnn; FLOAT x[], y[];
{
	n= *nnn;
	if(n<= 0) {fprintf(stderr, "ifft: bad value of n: %d", n); return 1;}
	df= x[2]-x[1]; dt= .5/x[n];
	if((fabs(df*dt*(n-1)-.5)>.01) || (fabs(x[n]-x[n-1]-df)>.01*df))
		{fprintf(stderr, "ifft: frequencies not equally spaced");
		exit(1);
		}
	nn= 2; nu= 0;
	while(++nu<= 20)
		{if(nn==n-1)break;
		nn= nn+nn;
		}
	if(nu>20)
		{fprintf(stderr, "ifft: n isn\'t 1 more than a power of 2");
		return n;
		}
	ip= 2; i= 0;
	while(++i<= n) {x[i]= y[ip]; y[i]= y[ip-1]; ip=ip+2;}
	n2= n/2+1; ip= n; arg= 0.;
	n= n-1;   /* original n, minus one */
	ninv= 3.14159265358979/n;
	i= 0;
	while(++i<= n2)
		{/* printf("i= %d ", i); */
		s= sin(arg); c= cos(arg);
		yplus= y[i]+y[ip]; yminus= y[i]-y[ip];
		xplus= x[i]+x[ip]; xminus= x[i]-x[ip];
		p= s*yminus+c*xplus; q= s*xplus-c*yminus;
		x[i]= q-xminus; x[ip]= q+xminus;
		y[i]= yplus-p;  y[ip]= yplus+p;
		--ip;
		arg= arg+ninv;   /* faster than: arg=ninv*i; */
		}

	fft2(y, x, n, nu);

/*	fprintf(stderr, "ifft: transform calculated\n");
	i=0; while(++i<=10) {printf("%6d %15.6f %15.6f\n", i, y[i], x[i]);}
*/
	ip=n;
	while(ip)
		{y[ip+ip]= -df*x[ip]; y[ip+ip-1]=df*y[ip];
		--ip;
		}
	time=0.; i=0;
	*nnn=n=n+n;  /* twice (original n, minus 1) */
	while(++i<=n) {x[i]=time; time=time+dt;}
}
fft2(xreal, ximag, n, nu)
FLOAT xreal[], ximag[];
int n, nu;
{	double treal, timag;
	FLOAT *xr1, *xr2, *xi1, *xi2;

	n2=n/2; nu1=nu-1; k=0; l=0;
	while(++l<=nu)
		{while(k<n)
			{p=ibitr(k>>nu1, nu);
			arg=3.14159265358979*2*p/n;
			c=cos(arg); s=sin(arg); i=0;
			while(++i<=n2)
			    {++k; k1n2=k+n2;
			    /* initialize four pointers */
			    xr1=xreal+k; xr2=xreal+k1n2;
			    xi1=ximag+k; xi2=ximag+k1n2;
			    treal= *xr2*c+ *xi2*s;
			    timag= *xi2*c- *xr2*s;
			    *xr2= *xr1-treal;
			    *xi2= *xi1-timag;
			    *xr1= *xr1+treal;
			    *xi1= *xi1+timag;
			    }
			k=k+n2;
			}
		k=0; --nu1; n2=n2/2;
		}
	k=0;
	while(++k<=n)
		{i=ibitr(k-1, nu)+1;
		if(i>k)
			{treal=xreal[k];   timag=ximag[k];
			xreal[k]=xreal[i]; ximag[k]=ximag[i];
			xreal[i]=treal;    ximag[i]=timag;
			}
		}
}

/* reverse the last nu bits of j */
ibitr(j, nu) int j, nu;
{	int ib;
	ib=0;
	while(nu--){ib=(ib<<1)+(j&1); j=j>>1;}
	return ib;
}


⌨️ 快捷键说明

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