/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include "Fft.h" #include <stdlib.h> #include <math.h> Fft::Fft(void) : mCosine(0), mSine(0), mFftSize(0), mFftTableSize(0) { } Fft::~Fft(void) { fftCleanup(); } /* Construct a FFT table suitable to perform a DFT of size 2^power. */ void Fft::fftInit(int power) { fftCleanup(); fftMakeTable(power); } void Fft::fftCleanup() { delete [] mSine; delete [] mCosine; mSine = NULL; mCosine = NULL; mFftTableSize = 0; mFftSize = 0; } /* z <- (10 * log10(x^2 + y^2)) for n elements */ int Fft::fftLogMag(float *x, float *y, float *z, int n) { float *xp, *yp, *zp, t1, t2, ssq; if(x && y && z && n) { for(xp=x+n, yp=y+n, zp=z+n; zp > z;) { t1 = *--xp; t2 = *--yp; ssq = (t1*t1)+(t2*t2); *--zp = (ssq > 0.0)? 10.0 * log10((double)ssq) : -200.0; } return 1; //true } else { return 0; // false/fail } } int Fft::fftMakeTable(int pow2) { int lmx, lm; float *c, *s; double scl, arg; mFftSize = 1 << pow2; mFftTableSize = lmx = mFftSize/2; mSine = new float[lmx]; mCosine = new float[lmx]; scl = (M_PI*2.0)/mFftSize; for (s=mSine, c=mCosine, lm=0; lm<lmx; lm++ ) { arg = scl * lm; *s++ = sin(arg); *c++ = cos(arg); } mBase = (mFftTableSize * 2)/mFftSize; mPower2 = pow2; return(mFftTableSize); } /* Compute the discrete Fourier transform of the 2**l complex sequence * in x (real) and y (imaginary). The DFT is computed in place and the * Fourier coefficients are returned in x and y. */ void Fft::fft( float *x, float *y ) { float c, s, t1, t2; int j1, j2, li, lix, i; int lmx, lo, lixnp, lm, j, nv2, k=mBase, im, jm, l = mPower2; for (lmx=mFftSize, lo=0; lo < l; lo++, k *= 2) { lix = lmx; lmx /= 2; lixnp = mFftSize - lix; for (i=0, lm=0; lm<lmx; lm++, i += k ) { c = mCosine[i]; s = mSine[i]; for ( li = lixnp+lm, j1 = lm, j2 = lm+lmx; j1<=li; j1+=lix, j2+=lix ) { t1 = x[j1] - x[j2]; t2 = y[j1] - y[j2]; x[j1] += x[j2]; y[j1] += y[j2]; x[j2] = (c * t1) + (s * t2); y[j2] = (c * t2) - (s * t1); } } } /* Now perform the bit reversal. */ j = 1; nv2 = mFftSize/2; for ( i=1; i < mFftSize; i++ ) { if ( j < i ) { jm = j-1; im = i-1; t1 = x[jm]; t2 = y[jm]; x[jm] = x[im]; y[jm] = y[im]; x[im] = t1; y[im] = t2; } k = nv2; while ( j > k ) { j -= k; k /= 2; } j += k; } } /* Compute the discrete inverse Fourier transform of the 2**l complex * sequence in x (real) and y (imaginary). The DFT is computed in * place and the Fourier coefficients are returned in x and y. Note * that this DOES NOT scale the result by the inverse FFT size. */ void Fft::ifft(float *x, float *y ) { float c, s, t1, t2; int j1, j2, li, lix, i; int lmx, lo, lixnp, lm, j, nv2, k=mBase, im, jm, l = mPower2; for (lmx=mFftSize, lo=0; lo < l; lo++, k *= 2) { lix = lmx; lmx /= 2; lixnp = mFftSize - lix; for (i=0, lm=0; lm<lmx; lm++, i += k ) { c = mCosine[i]; s = - mSine[i]; for ( li = lixnp+lm, j1 = lm, j2 = lm+lmx; j1<=li; j1+=lix, j2+=lix ) { t1 = x[j1] - x[j2]; t2 = y[j1] - y[j2]; x[j1] += x[j2]; y[j1] += y[j2]; x[j2] = (c * t1) + (s * t2); y[j2] = (c * t2) - (s * t1); } } } /* Now perform the bit reversal. */ j = 1; nv2 = mFftSize/2; for ( i=1; i < mFftSize; i++ ) { if ( j < i ) { jm = j-1; im = i-1; t1 = x[jm]; t2 = y[jm]; x[jm] = x[im]; y[jm] = y[im]; x[im] = t1; y[im] = t2; } k = nv2; while ( j > k ) { j -= k; k /= 2; } j += k; } } int Fft::fftGetSize(void) { return mFftSize; } int Fft::fftGetPower2(void) { return mPower2; }