FFT - faq

From
Ilia Kantor (2:5020/175.2)
To
Nick Poroshin
Date
2002-12-16T20:27:27Z
Area
RU.ALGORITHMS
From: "Ilia Kantor" <ilia@manual.ru>

Mon Dec 16 2002 10:10, Nick Poroshin wrote to Evgeny Sharandin:

 NP> Можешь пpивести лучший на твой взгляд cdft/rdft в pамках 4-5 кб?
Интересно, какие результаты покажет преобразование, данное ниже ?

Прилагаемая реализация несколько упрощена в принципиальных местах, поэтому
всегда будет уступать Ооуре. В реальных тестах, на больших количествах точек
отставание где-то в 2 раза по времени и незначительное - по точности.

Пример, тем не менее, учебный.. Потому - простой.


---------------- fft.cpp -------------------------

#include <math.h>
#include "general.h"
#include "Complex.h"

#define TRIG_VARS                 	\
	ulong TLen,TNdx;int TDir;	\
	Complex PRoot,Root;

#define INIT_TRIG(LENGTH,DIR)    		\
	TNdx=0;TLen=(LENGTH);TDir=(DIR);    	\
	PRoot.r=1.0;PRoot.i=0.0;          	\
	Root.r=sin(CONST_PI/((LENGTH)*2.0)); 	\
	Root.r=-2.0*Root.r*Root.r;         	\
	Root.i=sin(CONST_PI/(LENGTH))*(DIR);

#define NEXT_TRIG_POW               			\
	if (((++TNdx)&15)==0) {            		\
		real Angle=(CONST_PI*(TNdx))/TLen;      \
		PRoot.r=sin(Angle*0.5);         	\
		PRoot.r=1.0-2.0*PRoot.r*PRoot.r;	\
		PRoot.i=sin(Angle)*(TDir);      	\
	} else {             				\
		Complex Temp;                     	\
		Temp=PRoot;                     	\
		PRoot = PRoot*Root;     		\
		PRoot = PRoot+Temp;     		\
	}


inline ulong rev_next(ulong r, ulong n) { 
	do {
		n = n >> 1;
		r = r^n;
	} while ( (r&n) == 0);
	return r;
}


void FFTReOrder(Complex *Data, ulong Len) {
	Complex temp;
	if (Len <= 2) return;
	ulong r=0;
	for ( ulong x=1; x<Len; x++) {
		r = rev_next(r, Len);
		if (r>x) { temp=Data[x]; Data[x]=Data[r]; Data[r]=temp; } 
	}
}


void IFFT_T(Complex *Data, ulong Len, int Dir) {
	ulong Step, HalfStep;
	ulong b;
	TRIG_VARS;

	Step = 1;
	while (Step < Len) {
		HalfStep = Step;
		Step *= 2;

		INIT_TRIG(HalfStep,Dir);

		for (b = 0; b < HalfStep; b++) {
			ulong L,R;
			for (L=b; L<Len; L+=Step) {
				Complex TRight,TLeft;
				R=L+HalfStep;
				TLeft=Data[L];TRight=Data[R];
				TRight  = TRight * PRoot;
				Data[L] = TLeft + TRight;
				Data[R] = TLeft - TRight;
			}
			NEXT_TRIG_POW;
		}

	}
}


void FFT_T(Complex *Data, ulong Len, int Dir) {
	ulong k;

	TRIG_VARS;

	if (Len <= (CACHE_HALF/sizeof(Complex)) ) {
		IFFT_T(Data, Len,Dir);
		return;
	}

	Len /= 2;

	INIT_TRIG(Len, Dir);

	FFT_T(Data,    Len,Dir);
	FFT_T(Data+Len,Len,Dir);

	for (k=0; k<Len; k++) {
		Complex b,c;
		b=Data[k];
		c = Data[k+Len] * PRoot;
		Data[k] = b + c;
		Data[k+Len] = b - c;
		NEXT_TRIG_POW;
	}
}



void RealFFT(real *ddata, ulong Len, int Dir) {
	ulong i, j;
	Complex *Data=(Complex*)ddata;
	TRIG_VARS;

	Len /= 2;

	if (Dir > 0) {
		FFTReOrder(Data,Len);
		FFT_T(Data,Len,1);
	}

	INIT_TRIG(Len,Dir);
	NEXT_TRIG_POW;

	for (i = 1, j = Len - i; i < Len/2; i++, j--) {
    		Complex p1,p2,t;
		t = conj(Data[j]);
		p1 = Data[i] + t;
		p2 = Data[i] - t;
		p2 = p2 * PRoot;

		t = Complex(-Dir*p2.i,Dir*p2.r);

		Data[i] = p1 + t;
		Data[j] = p1 - t;
		Data[j] = conj(Data[j]);

		Data[i] = Data[i]/2;
		Data[j] = Data[j]/2;

		NEXT_TRIG_POW;
	}

	{	real r,i;
		r=Data[0].r;i=Data[0].i;
		Data[0] = Complex(r+i,r-i);
	}

	if (Dir < 0) {
		Data[0] = Data[0]/2.0;
		FFTReOrder(Data,Len);
		FFT_T(Data,Len,-1);
	}
}


------------------- general.h --------------
#define CACHE_HALF 65536
#define CONST_PI      3.1415926535897932384626433832
typedef double real;
typedef unsigned long ulong;
typedef unsigned short ushort;
---------------- complex.h ----------------------------
class Complex {
public:
	real r, i; 
	Complex(void) { }
	Complex(real a, real b) { r=a; i=b; }
	inline const Complex operator+(const Complex &c) const {
		return Complex( r + c.r, i + c.i);
	}
	inline const Complex operator-(const Complex &c) const {
		return Complex( r - c.r, i - c.i);
	}	
	inline const Complex operator*(const Complex &c) const {
		return Complex( r*c.r - i*c.i, r*c.i + i*c.r);
	}
	inline const Complex operator/(const real &divisor) const {
		return Complex( r/divisor, i/divisor);
	}

};

inline const Complex conj(const Complex &c) {
	return Complex( c.r, -c.i);
}

--- ifmail v.2.15dev5
 * Origin: FidoNet Online - http://www.fido-online.com (2:5020/175.2)