shithub: aacenc

ref: 84208056bcc6fe6eb49750d5cd45fe41c4e33fbe
dir: /fft.c/

View raw version
/*
** FFT and FHT routines
**  Copyright 1988, 1993; Ron Mayer
**  
**  fht(fz,n);
**      Does a hartley transform of "n" points in the array "fz".
**      
** NOTE: This routine uses at least 2 patented algorithms, and may be
**       under the restrictions of a bunch of different organizations.
**       Although I wrote it completely myself; it is kind of a derivative
**       of a routine I once authored and released under the GPL, so it
**       may fall under the free software foundation's restrictions;
**       it was worked on as a Stanford Univ project, so they claim
**       some rights to it; it was further optimized at work here, so
**       I think this company claims parts of it.  The patents are
**       held by R. Bracewell (the FHT algorithm) and O. Buneman (the
**       trig generator), both at Stanford Univ.
**       If it were up to me, I'd say go do whatever you want with it;
**       but it would be polite to give credit to the following people
**       if you use this anywhere:
**           Euler     - probable inventor of the fourier transform.
**           Gauss     - probable inventor of the FFT.
**           Hartley   - probable inventor of the hartley transform.
**           Buneman   - for a really cool trig generator
**           Mayer(me) - for authoring this particular version and
**                       including all the optimizations in one package.
**       Thanks,
**       Ron Mayer; mayer@acuson.com
** and added some optimization by
**           Mather    - idea of using lookup table
**           Takehiro  - some dirty hack for speed up
*/

#include <math.h>

#define SQRT2 sqrt(2)

static float costab[20]=
    {
     .00000000000000000000000000000000000000000000000000,
     .70710678118654752440084436210484903928483593768847,
     .92387953251128675612818318939678828682241662586364,
     .98078528040323044912618223613423903697393373089333,
     .99518472667219688624483695310947992157547486872985,
     .99879545620517239271477160475910069444320361470461,
     .99969881869620422011576564966617219685006108125772,
     .99992470183914454092164649119638322435060646880221,
     .99998117528260114265699043772856771617391725094433,
     .99999529380957617151158012570011989955298763362218,
     .99999882345170190992902571017152601904826792288976,
     .99999970586288221916022821773876567711626389934930,
     .99999992646571785114473148070738785694820115568892,
     .99999998161642929380834691540290971450507605124278,
     .99999999540410731289097193313960614895889430318945,
     .99999999885102682756267330779455410840053741619428
    };

static void fht(float *fz, int n)
{
    int i,k1,k2,k3,k4;
    float *fi, *fn, *gi;
    float *tri;

    fn = fi = fz + n;
    do {
	float f0,f1,f2,f3;
	fi -= 4;
	f1    = fi[0]-fi[1];
	f0    = fi[0]+fi[1];
	f3    = fi[2]-fi[3];
	f2    = fi[2]+fi[3];
	fi[2] = (f0-f2);
	fi[0] = (f0+f2);
	fi[3] = (f1-f3);
	fi[1] = (f1+f3);
    } while (fi != fz);

    tri = &costab[0];
    k1 = 1;
    do {
	float s1, c1;
	int kx;
	k1  *= 4;
	k2  = k1 << 1;
	kx  = k1 >> 1;
	k4  = k2 << 1;
	k3  = k2 + k1;
	fi  = fz;
	gi  = fi + kx;
	do {
	    float f0,f1,f2,f3;
	    f1      = fi[0]  - fi[k1];
	    f0      = fi[0]  + fi[k1];
	    f3      = fi[k2] - fi[k3];
	    f2      = fi[k2] + fi[k3];
	    fi[k2]  = f0     - f2;
	    fi[0 ]  = f0     + f2;
	    fi[k3]  = f1     - f3;
	    fi[k1]  = f1     + f3;
	    f1      = gi[0]  - gi[k1];
	    f0      = gi[0]  + gi[k1];
	    f3      = SQRT2  * gi[k3];
	    f2      = SQRT2  * gi[k2];
	    gi[k2]  = f0     - f2;
	    gi[0 ]  = f0     + f2;
	    gi[k3]  = f1     - f3;
	    gi[k1]  = f1     + f3;
	    gi     += k4;
	    fi     += k4;
	} while (fi<fn);
	c1 = tri[0];
	s1 = tri[1];
	for (i = 1; i < kx; i++) {
	    float c2,s2;
	    c2 = 1.0 - 2.0*s1*s1;
	    s2 = 2.0*s1*c1;
	    fi = fz + i;
	    gi = fz + k1 - i;
	    do {
		float a,b,g0,f0,f1,g1,f2,g2,f3,g3;
		b       = s2*fi[k1] - c2*gi[k1];
		a       = c2*fi[k1] + s2*gi[k1];
		f1      = fi[0 ]    - a;
		f0      = fi[0 ]    + a;
		g1      = gi[0 ]    - b;
		g0      = gi[0 ]    + b;
		b       = s2*fi[k3] - c2*gi[k3];
		a       = c2*fi[k3] + s2*gi[k3];
		f3      = fi[k2]    - a;
		f2      = fi[k2]    + a;
		g3      = gi[k2]    - b;
		g2      = gi[k2]    + b;
		b       = s1*f2     - c1*g3;
		a       = c1*f2     + s1*g3;
		fi[k2]  = f0        - a;
		fi[0 ]  = f0        + a;
		gi[k3]  = g1        - b;
		gi[k1]  = g1        + b;
		b       = c1*g2     - s1*f3;
		a       = s1*g2     + c1*f3;
		gi[k2]  = g0        - a;
		gi[0 ]  = g0        + a;
		fi[k3]  = f1        - b;
		fi[k1]  = f1        + b;
		gi     += k4;
		fi     += k4;
	    } while (fi<fn);
	    c2 = c1;
	    c1 = c2 * tri[0] - s1 * tri[1];
	    s1 = c2 * tri[1] + s1 * tri[0];
        }
	tri += 2;
    } while (k4<n);
}

void fft(float *x_real, float *energy, int N)
{
	float a,b;
	int i,j;

	fht(x_real,N);

	energy[0] = x_real[0] * x_real[0];
	for (i=1,j=N-1;i<N/2;i++,j--) {
		a = x_real[i];
		b = x_real[j];
		energy[i]=(a*a + b*b)/2;
		
		if (energy[i] < 0.0005f) {
			energy[i] = 0.0005f;
		}
	}
	energy[N/2] = x_real[N/2] * x_real[N/2];
}

void fft_side(float x_real0[],float x_real1[], float *x_real, float *energy, int N, int sign)
/*
x_real0 = x_real from channel 0
x_real1 = x_real from channel 1
sign = 1:    compute mid channel energy, ax, bx
sign =-1:    compute side channel energy, ax, bx
*/
{
	float a,b;
	int i,j;

#define XREAL(j) ((x_real0[j]+sign*x_real1[j])/SQRT2)

	energy[0] = XREAL(0) * XREAL(0);
	x_real[0] = XREAL(0);

	for (i=1,j=N-1;i<N/2;i++,j--) {
		a = x_real[i] = XREAL(i);
		b = x_real[j] = XREAL(j);
		energy[i]=(a*a + b*b)/2;
		
		if (energy[i] < 0.0005) {
			energy[i] = 0.0005;
			x_real[i] = x_real[j] = 0.0223606797749978970790696308768019662239; /* was sqrt(0.0005) */
		}
	}
	energy[N/2] = XREAL(N/2) * XREAL(N/2);
}