00001
00002
00003 #include "FFT.h"
00004
00005 #include <fftw.h>
00006
00007 FFT::FFT(unsigned int size) :
00008 m_size(size),
00009 m_table(0),
00010 m_spare(0)
00011 {
00012 if (m_size < 2) throw InvalidSize;
00013 if (m_size & (m_size-1)) throw InvalidSize;
00014
00015 m_table = new int[m_size];
00016
00017 unsigned int bits;
00018 unsigned int i, j, k, m;
00019
00020 for (i = 0; ; ++i) {
00021 if (m_size & (1 << i)) {
00022 bits = i;
00023 break;
00024 }
00025 }
00026
00027 for (i = 0; i < m_size; ++i) {
00028
00029 m = i;
00030
00031 for (j = k = 0; j < bits; ++j) {
00032 k = (k << 1) | (m & 1);
00033 m >>= 1;
00034 }
00035
00036 m_table[i] = k;
00037 }
00038
00039 m_spare = new double[m_size];
00040 }
00041
00042 FFT::~FFT()
00043 {
00044 delete[] m_table;
00045 delete[] m_spare;
00046 }
00047
00048 void
00049 FFT::tune()
00050 {
00051 double *a = new double[m_size];
00052 double *b = new double[m_size];
00053 double *c = new double[m_size];
00054 double *d = new double[m_size];
00055 fftw_complex *ac = new fftw_complex[m_size];
00056
00057 for (unsigned int i = 0; i < m_size; ++i) {
00058 a[i] = drand48();
00059 b[i] = 0;
00060 }
00061
00062 fftw_plan fplan = fftw_plan_dft_r2c_1d(m_size, a, ac, FFTW_MEASURE);
00063 fftw_plan iplan = fftw_plan_dft_c2r_1d(m_size, ac, a, FFTW_MEASURE);
00064
00065 Profiler *profiler = new Profiler("FFT::tune: FFTW", true);
00066
00067 for (unsigned int count = 0; count < 1000; ++count) {
00068 fftw_execute(fplan);
00069 fftw_execute(iplan);
00070 }
00071
00072 delete profiler;
00073
00074 for (unsigned int i = 0; i < m_size; ++i) {
00075 a[i] = drand48();
00076 b[i] = 0;
00077 }
00078
00079 profiler = new Profiler("FFT::tune: basefft", true);
00080
00081 for (unsigned int count = 0; count < 1000; ++count) {
00082 basefft(false, a, b, c, d);
00083 basefft(true, a, b, c, d);
00084 }
00085
00086 delete profiler;
00087 }
00088
00089 void
00090 FFT::forward(double *realIn, double *realOut, double *imagOut)
00091 {
00092 basefft(false, realIn, 0, realOut, imagOut);
00093 }
00094
00095 void
00096 FFT::inverse(double *realIn, double *imagIn, double *realOut)
00097 {
00098 basefft(true, realIn, imagIn, realOut, m_spare);
00099 }
00100
00101 void
00102 FFT::basefft(bool inverse, double *ri, double *ii, double *ro, double *io)
00103 {
00104 if (!ri || !ro || !io) return;
00105
00106 unsigned int i, j, k, m;
00107 unsigned int blockSize, blockEnd;
00108
00109 double tr, ti;
00110
00111 double angle = 2.0 * M_PI;
00112 if (inverse) angle = -angle;
00113
00114 const unsigned int n = m_size;
00115
00116 if (ii) {
00117 ro[table[0]] = ri[0];
00118 io[table[0]] = ii[0];
00119 for (i = 1; i <= n/2; ++i) {
00120 ro[table[i]] = ri[i];
00121 io[table[i]] = ii[i];
00122 ro[table[n-i]] = ri[i];
00123 io[table[n-i]] = -ii[i];
00124 }
00125 } else {
00126 for (i = 0; i < n; ++i) {
00127 ro[table[i]] = ri[i];
00128 io[table[i]] = 0.0;
00129 }
00130 }
00131
00132 blockEnd = 1;
00133
00134 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
00135
00136 double delta = angle / (double)blockSize;
00137 double sm2 = -sin(-2 * delta);
00138 double sm1 = -sin(-delta);
00139 double cm2 = cos(-2 * delta);
00140 double cm1 = cos(-delta);
00141 double w = 2 * cm1;
00142 double ar[3], ai[3];
00143
00144 for (i = 0; i < n; i += blockSize) {
00145
00146 ar[2] = cm2;
00147 ar[1] = cm1;
00148
00149 ai[2] = sm2;
00150 ai[1] = sm1;
00151
00152 for (j = i, m = 0; m < blockEnd; j++, m++) {
00153
00154 ar[0] = w * ar[1] - ar[2];
00155 ar[2] = ar[1];
00156 ar[1] = ar[0];
00157
00158 ai[0] = w * ai[1] - ai[2];
00159 ai[2] = ai[1];
00160 ai[1] = ai[0];
00161
00162 k = j + blockEnd;
00163 tr = ar[0] * ro[k] - ai[0] * io[k];
00164 ti = ar[0] * io[k] + ai[0] * ro[k];
00165
00166 ro[k] = ro[j] - tr;
00167 io[k] = io[j] - ti;
00168
00169 ro[j] += tr;
00170 io[j] += ti;
00171 }
00172 }
00173
00174 blockEnd = blockSize;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 }