[comp.sources.misc] FFT in C

mh@killer.UUCP (Mike Hobgood) (08/01/87)

[]

I found this file on one of my disks, maybe useful.


#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by mh on Fri Jul 31 00:44:01 CDT 1987
# Contents:  fft.c complex.c
 
echo x - fft.c
sed 's/^XX//' > "fft.c" <<'@//E*O*F fft.c//'
XX/*
XX *	fft.c
XX *
XX *	Performs a Cooley-Tukey Fast Fourier Transform.
XX *
XX *	Original version Pascal written in "Simple Calculations with 
XX *	Complex Numbers by David Clark Doctor Dobbs Journal 10/84
XX *
XX *	Translated to C by R. Hellman 02/21/86
XX *	Released to Public Domain
XX *
XX *	Difference from original version:
XX *
XX *	As in fortran versions that I have worked with, instead of
XX *	specifying total array size in decimal - instead specify number
XX *	of array members as power of two.  Forward or reverse fft is
XX *	specified by the sign of this argument.
XX *
XX *	****IMPORTANT****
XX *	For convenience sake members of an array are taken to begin at [1]
XX *	rather than [0] thus for an fft on a 64 member array of pointers
XX *	to complex numbers, there must be  65 members.
XX *
XX *	f is a one dimensional array of pointers to complex numbers with
XX *	length (2**abs(ln)).  The sign of ln determines in which direction
XX *	the transform will be performed.  If ln is positive, then isinverse
XX *	is set to -1 and a forward transform is carried out.  If ln is
XX *	negative then isinverse is set to 1 and a reverse transform is
XX *	calculated.
XX *
XX *	For numpoints = (2**abs(ln)),
XX *		transform[j] = sum(f[i] * w ^ ((i-1) * (j-1))),
XX *	where i, j are 1 to numpoints and
XX *		w = exp(isinverse * 2 * pi * sqrt(-1)/numpoints).
XX *
XX *	The program also computes the inverse transform, for which the
XX *	defining expression is:
XX *		inverse DFT = (1/numpoints) * sum(f[i] * w ^ ((i-1) * (j-1))).
XX *
XX *	Run time is proportional to numpoints * log2(numpoints) rather than
XX *	to numpoints ** 2 for the classical discrete Fourier transform.
XX */

XX#include <stdio.h>
XX#include "complex.c"


XXfft(f, ln)
XXcomplex	*f[];
XXint	ln;
XX{
XX	int	i, isinverse, numpoints;

XX	if (ln > 0)  {
XX            puts("Calculating forward Fourier transform\n");
XX            isinverse = -1;
XX            numpoints = pow(2.0, ln);
XX	}
XX        else {
XX            puts("Calculating reverse Fourier transform\n");
XX            isinverse = 1;
XX            numpoints = (int) pow(2.0, -ln);
XX        }

XX	bitreverse(numpoints, f);
XX	butterfly(numpoints, isinverse, f);
XX}


XX/*
XX *	Reverse the bits
XX *
XX */

XXstatic bitreverse(numpoints, f)
XXint	numpoints;
XXcomplex	*f[];
XX{
XX	int	i, j, m;
XX	complex	*temp;

XX	j = 1;
XX	for (i = 1; i <= numpoints; i++)  {
XX		if (i < j)  {
XX			temp = f[j];
XX			f[j] = f[i];
XX			f[i] = temp;
XX		}

XX		m = numpoints >> 1;

XX		if (m < j)
XX			while (m < j)  {
XX				j -= m;
XX				m = (m + 1) >> 1;
XX			}

XX		j += m;
XX	}
XX}


XX/*
XX *	Calculate the butterflies for the bit reversed data
XX *	Normalize if a reverse fft is performed
XX *
XX */

XXstatic butterfly(numpoints, isinverse, f)
XXint	numpoints, isinverse;
XXcomplex	*f[];
XX{
XX	int	mmax, step, index, m, i, j;
XX	double	theta;
XX	complex	w, cn, temp;

XX	mmax = 1;

XX	while (numpoints > mmax)  {

XX		step = mmax << 1;

XX		for (m = 1; m <= mmax; m++)  {

XX			theta = M_PI * ((double)(isinverse) *
XX				       (double)(m - 1)) / (double)(mmax);

XX			w.re = cos(theta);
XX			w.im = sin(theta);

XX			for (i = 1; i <= ((numpoints-m) / step) + 1; i++)  {

XX				index = m + ((i-1) * step);
XX				j = index + mmax;

XX				cmult(&temp, &w, f[j]);
XX				csub(f[j], f[index], &temp);
XX				cadd(f[index], f[index], &temp);
XX			}
XX		}

XX		mmax = step;
XX	}

XX	if (isinverse == 1)  {
XX		cn.re = numpoints;
XX		cn.im = 0.0;

XX		for (i = 1; i <= numpoints; i++)
XX			cdiv(f[i], f[i], &cn);
XX	}
XX}
@//E*O*F fft.c//
chmod u=rw,g=r,o=r fft.c
 
echo x - complex.c
sed 's/^XX//' > "complex.c" <<'@//E*O*F complex.c//'
XX/*
XX *	Complex number library translated from Pascal source listing
XX *	in Dr. Dobbs October, 1984 "Simple Calculations with Complex Numbers"
XX *	by David Clark.
XX *
XX *	To insure that the same structure could be used as both an 'argument'
XX *	and 'result' immediate tranfer of structure members is done to a
XX *	local variable - in many of the functions this may not be necessary,
XX *	but it was done in all of the following functions for consistency
XX *
XX *	Author: R. Hellman
XX *	Date:	02/21/86
XX *
XX *	Released to the Public Domain
XX */

XX#include <malloc.h>
XX#include <math.h>

XX#define TINY	2.2e-308	/* tiny value */
XX#define LOGHUGE	709.778		/* natural log of huge value */

XXtypedef	struct  {
XX	double	re;
XX	double	im;
XX} complex;


XX/*
XX *	Initializes storage for each address of an array of complex pointers
XX *	*f[] with 'arraysz' number of elements
XX */

XXinitcmplx(f, arraysz)
XXcomplex	*f[];
XXint	arraysz;
XX{
XX	int	i;

XX	for (i = 0; i < arraysz; i++)
XX		if ((f[i] = (complex *)malloc(sizeof(complex))) == NULL)  {
XX			puts("Error: complex number allocation\n");
XX			exit(1);
XX		}
XX}


XX/* adds arg1 and arg2 and returns sum in result */

XXcadd(result, arg1, arg2)
XXcomplex	*result, *arg1, *arg2;
XX{
XX	complex	targ1, targ2;

XX	targ1.re = arg1->re;
XX	targ1.im = arg1->im;
XX	targ2.re = arg2->re;
XX	targ2.im = arg2->im;

XX	result->re = targ1.re + targ2.re;
XX	result->im = targ1.im + targ2.im;
XX}


XX/* subtracts arg1 and arg2 and returns sum in result */

XXcsub(result, arg1, arg2)
XXcomplex	*result, *arg1, *arg2;
XX{
XX	complex	targ1, targ2;

XX	targ1.re = arg1->re;
XX	targ1.im = arg1->im;
XX	targ2.re = arg2->re;
XX	targ2.im = arg2->im;

XX	result->re = targ1.re - targ2.re;
XX	result->im = targ1.im - targ2.im;
XX}



XX/* multiplies arg1 and arg2 and returns product in result */

XXcmult(result, arg1, arg2)
XXcomplex	*result, *arg1, *arg2;
XX{
XX	complex	targ1, targ2;

XX	targ1.re = arg1->re;
XX	targ1.im = arg1->im;
XX	targ2.re = arg2->re;
XX	targ2.im = arg2->im;

XX	result->re = (targ1.re * targ2.re) - (targ1.im * targ2.im);
XX	result->im = (targ1.im * targ2.re) + (targ1.re * targ2.im);
XX}


XX/* divides arg1 and arg2 and returns quotient in result */

XXcdiv(result, arg1, arg2)
XXcomplex	*result, *arg1, *arg2;
XX{
XX	double denom;
XX	complex targ1,targ2;

XX	targ1.re = arg1->re;
XX	targ1.im = arg1->im;
XX	targ2.re = arg2->re;
XX	targ2.im = arg2->im;
XX	denom = (targ2.re * targ2.re) + (targ2.im * targ2.im);

XX	result->re = (targ1.re * targ2.re + targ1.im * targ2.im) / denom;
XX	result->im = (targ1.im * targ2.re - targ1.re * targ2.im) / denom;
XX}


XX/* converts a complex number arg in rectangular form to polar form */

XXpolar(arg, modulus, amplitude)
XXcomplex	*arg;
XXdouble	*modulus, *amplitude;
XX{
XX	complex	targ;

XX	targ.re = arg->re;
XX	targ.im = arg->im;

XX	if (fabs(targ.re) < TINY)
XX		targ.re = 0.0;

XX	if (fabs(targ.im) < TINY)
XX		targ.im = 0.0;

XX	*modulus = sqrt((targ.re * targ.re) + (targ.im * targ.im));

XX	if (targ.im == 0.0)
XX		*amplitude = 0.0;
XX	else if (targ.re == 0.0)  {
XX		if (targ.im > 0.0)
XX			*amplitude = M_PI_2;
XX		else
XX			*amplitude = -M_PI_2;
XX	}
XX	else if ((log(fabs(targ.im)) - log(fabs(targ.re))) > LOGHUGE) {
XX		if (targ.re > 0.0)  {
XX			if (targ.im > 0.0)
XX				*amplitude = M_PI_2;
XX			else
XX				*amplitude = -M_PI_2;
XX		}
XX		else if (targ.im > 0.0)
XX			*amplitude = -M_PI_2;
XX		else
XX			*amplitude = M_PI_2;
XX		}
XX	}
XX	else
XX		*amplitude = atan(targ.im / targ.re);
XX}


XX/* raises arg to the positive integral power and returns answer in result */

XXctopower(result, arg, power)
XXcomplex	*result, *arg;
XXint	power;
XX{
XX	int	i;
XX	double	modulus, amplitude, newmod, powamp;
XX	complex targ;

XX	targ.re = arg->re;
XX	targ.im = arg->im;

XX	if (power == 0)  {
XX		result->re = 1.0;
XX		result->im = 0.0;
XX	}
XX	else {
XX		polar(&targ, &modulus, &amplitude);
XX		newmod = 1.0;

XX		if (power > 0)
XX			for (i = 0; i < power; i++)
XX				newmod = newmod * modulus;
XX		else
XX			for (i = 0; i < abs(power); i++)
XX				newmod = newmod / modulus;

XX		powamp = power * amplitude;

XX		result->re = newmod * cos(powamp);
XX		result->im = newmod * sin(powamp);
XX	}
XX}



XX/* raises e to the arg and returns the answer in result */

XXcexp(result, arg)
XXcomplex	*result, *arg;
XX{
XX	double	expo;
XX	complex	targ;

XX	targ.re = arg->re;
XX	targ.im = arg->im;
XX	expo = exp(targ.re);

XX	result->re = expo * cos(targ.im);
XX	result->im = expo * sin(targ.im);
XX}


XX/* takes the natural logarithm of arg and returns the answer in result */

XXcln(result, arg)
XXcomplex	*result, *arg;
XX{
XX	double	modulus, amplitude;
XX	complex	targ;
XX    
XX	targ.re = arg->re;
XX	targ.im = arg->im;

XX	polar(&targ, &modulus, &amplitude);

XX	result->re = log(modulus);
XX	result->im = amplitude;
XX}


XX/* raise complex number arg1 to complex power arg2 and return answer in result */

XXctoc(result, arg1, arg2)
XXcomplex *result, *arg1, *arg2;
XX{
XX	complex	logpart, expo, targ1, targ2;

XX	targ1.re = arg1->re;
XX	targ1.im = arg1->im;
XX	targ2.re = arg2->re;
XX	targ2.im = arg2->im;

XX	cln(&logpart, &targ1);
XX	cmult(&expo, &targ2, &logpart);
XX	cexp(result, &expo);
XX}


XX/* takes the sine of arg and returns it in result */

XXcsin(result, arg)
XXcomplex *result, *arg;
XX{
XX	complex	targ, exp1, exp2, part1,
XX		part2, sum, divisor;

XX	targ.re = arg->re;
XX	targ.im = arg->im;
XX	exp1.re = -targ.im;
XX	exp1.im = targ.re;

XX	cexp(&part1, &exp1);

XX	exp2.re = targ.im;
XX	exp2.im = -targ.re;

XX	cexp(&part2, &exp2);
XX	csub(&sum, &part1, &part2);

XX	divisor.re = 0.0;
XX	divisor.im = 2.0;

XX	cdiv(result, &sum, &divisor);
XX}


XX/* takes the cosine of arg and returns it in result */

XXccos(result, arg)
XXcomplex	*result, *arg;
XX{
XX	complex	targ, exp1, exp2, part1,
XX		part2, sum, divisor;

XX	targ.re = arg->re;
XX	targ.im = arg->im;
XX	exp1.re = -targ.im;
XX	exp1.im = targ.re;

XX	cexp(&part1, &exp1);

XX	exp2.re = targ.im;
XX	exp2.im = -targ.re;

XX	cexp(&part2, &exp2);
XX	cadd(&sum, &part1, &part2);

XX	divisor.re = 2.0;
XX	divisor.im = 0.0;

XX	cdiv(result, &sum, &divisor);
@//E*O*F complex.c//
chmod u=rw,g=r,o=r complex.c
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
    152    569   3300 fft.c
    306    872   5702 complex.c
    458   1441   9002 total
!!!
wc  fft.c complex.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0