diff src/samer/units/FFT.java @ 0:bf79fb79ee13

Initial Mercurial check in.
author samer
date Tue, 17 Jan 2012 17:50:20 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FFT.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,192 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.maths.*; // uses ComplexVector and Vec
+
+/**
+  *	<h2>Fast Fourier Transform</h2>
+  *	<h4>by Samer Abdallah</h4>
+  *	<h4>15 December 1999</h4>
+  *
+  *	<p>
+  *	Mostly from my old C++ version, though I should credit the following
+  *	FFT code for the idea of using a lookup table for the bit reversal
+  *   and also a complete lookup table of sines:
+  *
+  *	<pre>
+  *	>	From the Unix Version 2.4 by Steve Sampson, Public Domain,
+  *	>	September 1988.
+  *	>	Adapted for Java by Ben Stoltz <stoltz@sun.com>, September 1997
+  *	>
+  *	>	Refer to http://www.neato.org/~ben/Fft.html for updates and related
+  *	>	resources.
+  *	</pre>
+  *
+  *	<p>
+  *	My old version computed the bit-reversed indices on the fly - silly
+  *	really - don't know why I didn't think of a lookup table myself.
+  *	Also, it had a lookup table of sines and cosines of the form
+  *	sin( 2*PI/k) with k going 1, 2, 4, 8 .. N. This version has complete
+  *	tables for sin and cosine - which is a bit of a waste of memory,
+  *	but frankly, who cares?
+  *
+  *	<h3>Usage</h3>
+  *	<p>
+  *	It is the user's responsibility to fill the arrays real
+  *   and imag with data IN THE CORRECT BITREVERSED ORDER. This
+  *	is easy enough using the bitrev lookup table - something like this
+  *	would do the trick:
+  *	<pre>
+  *		for (int i=0; i<N; i++) {
+  *			int k=fft.bitrev[i]
+  *			fft.real[k] = theRealData[i];
+  *			fft.imag[k] = 0;
+  *		}				
+  *	</pre>
+  *	The arrays are used destructively, so it is also the user's 
+  *	responsibility, eg, to reset the imaginary parts to zero even
+  *	if they are always zero.
+  *
+  *	<p>
+  *	The results ends up in the arrays real and imag
+  */
+
+
+public class FFT 
+{
+	public	int				bitrev[];	// lookup table
+	public	double			H[];			// window - not yet used internally
+	public	double			real[];			
+	public	double			imag[];			
+
+	protected	ComplexVector	W;				// sines and cosines lookup table
+	protected	int				N;
+	protected	double			zeros[];
+
+	public FFT( int n)
+	{
+		N=n;
+		real = new double[N];
+		imag = new double[N];
+		W = new ComplexVector(N);
+		bitrev = new int[N];
+		H = new double[N];
+
+		// calculate bit reversal lookup table
+		int m=N/2, j=0;
+		for (int i=0; i<n; i++) {
+			bitrev[i]=j;
+			int b;
+			for (b=m; (b>1) && (j>=b); b>>=1) j-=b;
+			j+=b; 
+		}
+
+		// calculate sines and cosines lookup
+		double th=2*Math.PI/N;
+		for (int i=0; i<n; i++) {
+			W.real[i] = Math.cos(i*th); 
+			W.imag[i] = Math.sin(i*th); 
+		}
+
+		// table of zeros for fast initialisation
+		zeros = new double[N];
+		for (int i=0; i<N; i++) zeros[i]=0.0;
+	}
+
+	public int size() { return N; }
+	public final void input( double Y[])
+	{
+		System.arraycopy(zeros,0,imag,0,N);
+		for (int i=0; i<N; i++) {
+			real[bitrev[i]] = H[i]*Y[i];
+		}
+	}				
+
+	public final void brevcopy( double src[], double dst[] )
+	{
+		for (int i=0; i<src.length; i++) {
+			dst[bitrev[i]] = src[i];
+		}
+	}				
+
+	public final void input( Vec.Iterator it)
+	{
+		System.arraycopy(zeros,0,imag,0,N);
+		for (int i=0; i<N; i++) {
+			real[bitrev[i]] = H[i]*it.next();
+		}
+	}				
+
+	public final void outputPower( double S[])
+	{
+		// extract power
+		for (int i=0; i<S.length; i++) {
+			S[i] = real[i]*real[i] + imag[i]*imag[i];
+		}
+	}
+
+	public final void calculate()
+	{
+		double	a1,a2,b1,b2;
+		int		step, jump, i, k;
+		int		m=N/2, p;
+		double	wReal, wImag;
+
+		// these are cached for performance -
+		// the COMPILER ought to be doing this!
+		double	Real[] = real;
+		double	Imag[] = imag;
+		double	wr[] = W.real;
+		double	wi[] = W.imag;
+
+		step=1; jump=2;
+		while (step<N) {
+
+			p = 0; 
+			for (k=0; k<step; k++) {
+
+				// look up exp( (2*PI*i/N)*p );
+				wReal = wr[p]; 
+				wImag = wi[p]; 
+				p+=m;
+
+				for (i=k; i<N; i+=jump) {
+
+					int j=i+step;
+
+					// complex butterfly between i and j
+					a1 = Real[i];
+					a2 = Imag[i];
+
+
+					b1 = wReal*Real[j] - wImag*Imag[j];
+					b2 = wImag*Real[j] + wReal*Imag[j];
+
+					Real[i] = a1 + b1;
+					Imag[i] = a2 + b2;
+					Real[j] = a1 - b1;
+					Imag[j] = a2 - b2;
+				}
+			}
+			step=jump; jump<<=1; m>>=1;
+		}
+	}
+
+	// make everything conjugate - does inverse fft
+	public void invert()	{
+		for (int i=0; i<W.length; i++) W.imag[i] = -W.imag[i];
+	}
+
+	// useful window functions
+	public void setWindow(Function fn) {
+		for (int i=0; i<N; i++) H[i] = (double)i/N;
+		fn.apply(H); Mathx.mul(H,1/Math.sqrt(N));
+	}
+}