annotate src/samer/units/FFT.java @ 8:5e3cbbf173aa tip

Reorganise some more
author samer
date Fri, 05 Apr 2019 22:41:58 +0100
parents bf79fb79ee13
children
rev   line source
samer@0 1 /*
samer@0 2 * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0 3 * All rights reserved.
samer@0 4 *
samer@0 5 * This software is provided AS iS and WITHOUT ANY WARRANTY;
samer@0 6 * without even the implied warranty of MERCHANTABILITY or
samer@0 7 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 8 */
samer@0 9
samer@0 10 package samer.units;
samer@0 11 import samer.maths.*; // uses ComplexVector and Vec
samer@0 12
samer@0 13 /**
samer@0 14 * <h2>Fast Fourier Transform</h2>
samer@0 15 * <h4>by Samer Abdallah</h4>
samer@0 16 * <h4>15 December 1999</h4>
samer@0 17 *
samer@0 18 * <p>
samer@0 19 * Mostly from my old C++ version, though I should credit the following
samer@0 20 * FFT code for the idea of using a lookup table for the bit reversal
samer@0 21 * and also a complete lookup table of sines:
samer@0 22 *
samer@0 23 * <pre>
samer@0 24 * > From the Unix Version 2.4 by Steve Sampson, Public Domain,
samer@0 25 * > September 1988.
samer@0 26 * > Adapted for Java by Ben Stoltz <stoltz@sun.com>, September 1997
samer@0 27 * >
samer@0 28 * > Refer to http://www.neato.org/~ben/Fft.html for updates and related
samer@0 29 * > resources.
samer@0 30 * </pre>
samer@0 31 *
samer@0 32 * <p>
samer@0 33 * My old version computed the bit-reversed indices on the fly - silly
samer@0 34 * really - don't know why I didn't think of a lookup table myself.
samer@0 35 * Also, it had a lookup table of sines and cosines of the form
samer@0 36 * sin( 2*PI/k) with k going 1, 2, 4, 8 .. N. This version has complete
samer@0 37 * tables for sin and cosine - which is a bit of a waste of memory,
samer@0 38 * but frankly, who cares?
samer@0 39 *
samer@0 40 * <h3>Usage</h3>
samer@0 41 * <p>
samer@0 42 * It is the user's responsibility to fill the arrays real
samer@0 43 * and imag with data IN THE CORRECT BITREVERSED ORDER. This
samer@0 44 * is easy enough using the bitrev lookup table - something like this
samer@0 45 * would do the trick:
samer@0 46 * <pre>
samer@0 47 * for (int i=0; i<N; i++) {
samer@0 48 * int k=fft.bitrev[i]
samer@0 49 * fft.real[k] = theRealData[i];
samer@0 50 * fft.imag[k] = 0;
samer@0 51 * }
samer@0 52 * </pre>
samer@0 53 * The arrays are used destructively, so it is also the user's
samer@0 54 * responsibility, eg, to reset the imaginary parts to zero even
samer@0 55 * if they are always zero.
samer@0 56 *
samer@0 57 * <p>
samer@0 58 * The results ends up in the arrays real and imag
samer@0 59 */
samer@0 60
samer@0 61
samer@0 62 public class FFT
samer@0 63 {
samer@0 64 public int bitrev[]; // lookup table
samer@0 65 public double H[]; // window - not yet used internally
samer@0 66 public double real[];
samer@0 67 public double imag[];
samer@0 68
samer@0 69 protected ComplexVector W; // sines and cosines lookup table
samer@0 70 protected int N;
samer@0 71 protected double zeros[];
samer@0 72
samer@0 73 public FFT( int n)
samer@0 74 {
samer@0 75 N=n;
samer@0 76 real = new double[N];
samer@0 77 imag = new double[N];
samer@0 78 W = new ComplexVector(N);
samer@0 79 bitrev = new int[N];
samer@0 80 H = new double[N];
samer@0 81
samer@0 82 // calculate bit reversal lookup table
samer@0 83 int m=N/2, j=0;
samer@0 84 for (int i=0; i<n; i++) {
samer@0 85 bitrev[i]=j;
samer@0 86 int b;
samer@0 87 for (b=m; (b>1) && (j>=b); b>>=1) j-=b;
samer@0 88 j+=b;
samer@0 89 }
samer@0 90
samer@0 91 // calculate sines and cosines lookup
samer@0 92 double th=2*Math.PI/N;
samer@0 93 for (int i=0; i<n; i++) {
samer@0 94 W.real[i] = Math.cos(i*th);
samer@0 95 W.imag[i] = Math.sin(i*th);
samer@0 96 }
samer@0 97
samer@0 98 // table of zeros for fast initialisation
samer@0 99 zeros = new double[N];
samer@0 100 for (int i=0; i<N; i++) zeros[i]=0.0;
samer@0 101 }
samer@0 102
samer@0 103 public int size() { return N; }
samer@0 104 public final void input( double Y[])
samer@0 105 {
samer@0 106 System.arraycopy(zeros,0,imag,0,N);
samer@0 107 for (int i=0; i<N; i++) {
samer@0 108 real[bitrev[i]] = H[i]*Y[i];
samer@0 109 }
samer@0 110 }
samer@0 111
samer@0 112 public final void brevcopy( double src[], double dst[] )
samer@0 113 {
samer@0 114 for (int i=0; i<src.length; i++) {
samer@0 115 dst[bitrev[i]] = src[i];
samer@0 116 }
samer@0 117 }
samer@0 118
samer@0 119 public final void input( Vec.Iterator it)
samer@0 120 {
samer@0 121 System.arraycopy(zeros,0,imag,0,N);
samer@0 122 for (int i=0; i<N; i++) {
samer@0 123 real[bitrev[i]] = H[i]*it.next();
samer@0 124 }
samer@0 125 }
samer@0 126
samer@0 127 public final void outputPower( double S[])
samer@0 128 {
samer@0 129 // extract power
samer@0 130 for (int i=0; i<S.length; i++) {
samer@0 131 S[i] = real[i]*real[i] + imag[i]*imag[i];
samer@0 132 }
samer@0 133 }
samer@0 134
samer@0 135 public final void calculate()
samer@0 136 {
samer@0 137 double a1,a2,b1,b2;
samer@0 138 int step, jump, i, k;
samer@0 139 int m=N/2, p;
samer@0 140 double wReal, wImag;
samer@0 141
samer@0 142 // these are cached for performance -
samer@0 143 // the COMPILER ought to be doing this!
samer@0 144 double Real[] = real;
samer@0 145 double Imag[] = imag;
samer@0 146 double wr[] = W.real;
samer@0 147 double wi[] = W.imag;
samer@0 148
samer@0 149 step=1; jump=2;
samer@0 150 while (step<N) {
samer@0 151
samer@0 152 p = 0;
samer@0 153 for (k=0; k<step; k++) {
samer@0 154
samer@0 155 // look up exp( (2*PI*i/N)*p );
samer@0 156 wReal = wr[p];
samer@0 157 wImag = wi[p];
samer@0 158 p+=m;
samer@0 159
samer@0 160 for (i=k; i<N; i+=jump) {
samer@0 161
samer@0 162 int j=i+step;
samer@0 163
samer@0 164 // complex butterfly between i and j
samer@0 165 a1 = Real[i];
samer@0 166 a2 = Imag[i];
samer@0 167
samer@0 168
samer@0 169 b1 = wReal*Real[j] - wImag*Imag[j];
samer@0 170 b2 = wImag*Real[j] + wReal*Imag[j];
samer@0 171
samer@0 172 Real[i] = a1 + b1;
samer@0 173 Imag[i] = a2 + b2;
samer@0 174 Real[j] = a1 - b1;
samer@0 175 Imag[j] = a2 - b2;
samer@0 176 }
samer@0 177 }
samer@0 178 step=jump; jump<<=1; m>>=1;
samer@0 179 }
samer@0 180 }
samer@0 181
samer@0 182 // make everything conjugate - does inverse fft
samer@0 183 public void invert() {
samer@0 184 for (int i=0; i<W.length; i++) W.imag[i] = -W.imag[i];
samer@0 185 }
samer@0 186
samer@0 187 // useful window functions
samer@0 188 public void setWindow(Function fn) {
samer@0 189 for (int i=0; i<N; i++) H[i] = (double)i/N;
samer@0 190 fn.apply(H); Mathx.mul(H,1/Math.sqrt(N));
samer@0 191 }
samer@0 192 }