1 /*============================================================================= 2 | 3 | NAME 4 | 5 | FFT.cpp 6 | 7 | DESCRIPTION 8 | 9 | This program does an in-place one dimensional complex discrete 10 | Fourier transform. It uses an FFT algorithm for a number of 11 | input points which is a power of two. It's implemented in C++ 12 | as a derived class of the STL vector type. 13 | 14 | AUTHOR 15 | 16 | Sean O'Connor 19 November 2005 17 | 18 | LEGAL 19 | 20 | FFT Version 1.4 - An FFT utility library in C++. 21 | Copyright (C) 2005-2024 by Sean Erik O'Connor. All Rights Reserved. 22 | 23 | This program is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see <http://www.gnu.org/licenses/>. 35 | 36 | The author's address is seanerikoconnor!AT!gmail!DOT!com 37 | with !DOT! replaced by . and the !AT! replaced by @ 38 | 39 +============================================================================*/ 40 41 /*------------------------------------------------------------------------------ 42 | Include Files | 43 ------------------------------------------------------------------------------*/ 44 45 #include <iostream> // Basic stream I/O. 46 #include <fstream> // File stream I/O. 47 #include <sstream> // String stream I/O. 48 #include <cmath> // Basic math functions. 49 #include <complex> // Complex data type and operations. 50 #include <vector> // STL vector class. 51 #include <algorithm> // Iterators. 52 #include <string> // STL string class. 53 #include <stdexcept> // Exceptions. 54 55 using namespace std ; // Let us omit the std:: prefix for every STL class. 56 57 #include "FFT.h" // Our own FFT stuff. 58 59 60 /*============================================================================= 61 | 62 | NAME 63 | 64 | FastFourierTransform 65 | 66 | DESCRIPTION 67 | 68 | Default constructor. Just call the base class constructor for 69 | the vector type, then initialize the derived class field. 70 | 71 +============================================================================*/ 72 73 template <typename FloatType> 74 FastFourierTransform<FloatType>::FastFourierTransform() 75 : vector< complex<FloatType> >() 76 , direction( false ) 77 { 78 // Get the sine and cosine tables initialized. 79 /// MAX_TABLE_SIZE ) ; 80 starting_multiplier.clear(); 81 } 82 83 84 /*============================================================================= 85 | 86 | NAME 87 | 88 | ~FastFourierTransform 89 | 90 | DESCRIPTION 91 | 92 | Destructor. Doesn't need to do much. 93 | 94 +============================================================================*/ 95 96 template <typename FloatType> 97 FastFourierTransform<FloatType>::~FastFourierTransform() 98 { 99 } 100 101 102 103 /*============================================================================= 104 | 105 | NAME 106 | 107 | FastFourierTransform 108 | 109 | DESCRIPTION 110 | 111 | Copy constructor. 112 | 113 +============================================================================*/ 114 115 template <typename FloatType> 116 FastFourierTransform<FloatType>::FastFourierTransform( const FastFourierTransform & transform ) 117 : vector< complex<FloatType> >( transform ) // Initialize base class first. 118 { 119 // Copy derived class stuff. 120 direction = transform.direction ; 121 } 122 123 124 /*============================================================================= 125 | 126 | NAME 127 | 128 | = 129 | 130 | DESCRIPTION 131 | 132 | Assignment operator. 133 | 134 +============================================================================*/ 135 136 template <typename FloatType> 137 FastFourierTransform<FloatType> & FastFourierTransform<FloatType>::operator=( const FastFourierTransform & transform ) 138 { 139 // Check for initializing to oneself: pass back a reference to the unchanged object. 140 if (this == &transform) 141 { 142 // Pass back the object so we can concatenate assignments. 143 return *this ; 144 } 145 146 // Call base class assignment operator first. 147 FastFourierTransform<FloatType>::operator=( transform ) ; 148 149 // Assignment for derived class fields. 150 direction = transform.direction ; 151 152 153 // Pass back the object so we can concatenate assignments. 154 return *this ; 155 } 156 157 158 /*============================================================================= 159 | 160 | NAME 161 | 162 | fft 163 | 164 | DESCRIPTION 165 | 166 | 167 | This member function does an in-place one dimensional complex 168 | discrete Fourier transform. It uses an FFT algorithm for a number 169 | of input points which is a power of two. 170 | 171 | PARAMETERS 172 | 173 | direction The direction of the FFT, true for a forward transform and 174 | false for an inverse transform. 175 | 176 | EXCEPTIONS 177 | 178 | Throws FastFourierTransform type exceptions for the cases where 179 | 180 | -Number of points in the transform is less than 2. 181 | -Number of points is greater than the sine/cosine table can handle. 182 | -Number of points is not a power of 2. 183 | 184 | EXAMPLE 185 | 186 | Suppose the vector contains the data 187 | 188 | X ( 0 ) = 1 + i 189 | X ( 1 ) = 2 + 2 i 190 | X ( 2 ) = 3 + 3 i 191 | X ( 3 ) = 4 + 4 i 192 | 193 | then the forward FFT returns 194 | 195 | X ( 0 ) = 5 + 5 i 196 | X ( 1 ) = -2 197 | X ( 2 ) = -1 - i 198 | X ( 3 ) = - 2 i 199 | 200 | and the inverse FFT returns the original data to within roundoff. 201 | 202 | ^ 203 | The Fourier coefficients X( k ) are defined for k = 0, . . ., N - 1 204 | by the formula 205 | 206 | N - 1 2 Pi i 207 | ^ 1 ____ - ------ j k 208 | X( k ) = --------- \ N 209 | ----- / X( j ) e 210 | \ / N ---- 211 | v j = 0 212 | 213 | where e is 2.1718 . . ., Pi = 3.14159. . . and i is the square root 214 | of -1. 215 | 216 | This is the formula for the forward transform. The inverse transform 217 | is the same, except that the minus sign in the exponent above is a 218 | plus sign instead. 219 | --- 220 | The normalizing factor 1 / \/ N in front was picked so that the 221 | forward and inverse transforms look the same. 222 | 223 | The particular type of FFT algorithm we use is a 224 | 225 | Complex, 226 | Two to the N, 227 | Decimation in frequency, 228 | Input in order, output bit reversed 229 | 230 | type of FFT. It is described in the book 231 | 232 | THE FAST FOURIER TRANSFORM, 233 | F. Oran Brigham, Prentice Hall, 1974 234 | 235 | Also see my notes for an in-depth explanation. 236 | 237 | BUGS 238 | 239 | The bit-reversal routine could be made faster by using bit shifting 240 | operations. 241 | 242 | You might want to use long double precision complex numbers to get more 243 | accuracy. 244 | 245 | Check for a power of 2 probably ought to use the machine's floating point 246 | epsilon (computed automatically). 247 | 248 +============================================================================*/ 249 250 template <typename FloatType> 251 void FastFourierTransform<FloatType>::fft( bool direction ) 252 { 253 // Number of complex points in the FFT from the vector's size. 254 unsigned int N = this->size() ; 255 256 /* 257 * Compute log base 2 of N. Perturb slightly to avoid roundoff error. 258 * For example, (int)( 4.99999999999 ) = 4 (wrong!), but 259 * (int)( 4.999999999 + .01 ) = 5 (correct!) 260 */ 261 int log_of_n = (int) ( log( (FloatType) N ) / ( log( 2.0 ) ) + .01 ) ; 262 263 264 /* 265 * Error checking. Print a message to the terminal if any one of these 266 * conditions is true: 267 * 268 * N < 2. 269 * log2( N ) > MAX_TABLE_SIZE + 1. 270 * N is not a power of 2. 271 */ 272 if (N < 2) 273 { 274 ostringstream os ; 275 os << "FFT has less than two points. N = " << N << " file: " << __FILE__ << " line: " << __LINE__ ;; 276 throw FastFourierTransformException( os.str() ) ; 277 } 278 else if ( (log_of_n - 1) > MAX_TABLE_SIZE) 279 { 280 ostringstream os ; 281 os << "FFT has too many points for its sin/cos table. Table size = " << MAX_TABLE_SIZE << " file: " << __FILE__ << " line: " << __LINE__ ; 282 throw FastFourierTransformException( os.str() ) ; 283 284 } 285 else if ( (int) pow( 2.0, log_of_n ) != N ) 286 { 287 ostringstream os ; 288 os << "Number of points in the FFT is not a power of 2. N = " << N << " file: " << __FILE__ << " line: " << __LINE__ ;; 289 throw FastFourierTransformException( os.str() ) ; 290 } 291 292 293 /* 294 * If called_already is false, generate the sine and cosine table for 295 * the first time, then set called_already to true. Now later calls to 296 * this function don't recreate the sine and cosine table. 297 */ 298 if (!called_already) 299 { 300 for (int i = 0 ; i <= MAX_TABLE_SIZE - 1 ; ++i) 301 { 302 // Current angle in sine and cosine table. 303 FloatType angle = -PI / pow( (FloatType) 2, (FloatType) i ) ; 304 305 // e^t = cos t + i sin t 306 starting_multiplier[ i ] = complex<FloatType>(cos(angle), sin(angle)) ; 307 } 308 309 called_already = true ; 310 } 311 312 313 314 /* 315 * Compute the FFT according to its signal flow graph with 316 * computations arranged into butterflies, groups of butterflies 317 * with the same multiplier, and columns. 318 */ 319 int butterfly_height = N / 2 ; 320 int number_of_groups = 1 ; 321 322 323 /* 324 * A column refers to a column of the FFT signal flow graph. A group is 325 * a collection of butterflies which have the same multiplier W^p. A 326 * butterfly is the basic computational unit of the FFT. 327 */ 328 for (int column = 1 ; column <= log_of_n ; ++column) 329 { 330 // The multiplier W^p for a group of butterflies. 331 complex<FloatType> multiplier = starting_multiplier[ column - 1 ] ; 332 333 // Modify starting multiplier W^p when computing the inverse transform. 334 if (direction == false) 335 multiplier = conj( multiplier ) ; 336 337 // Difference between current multiplier and next. 338 complex<FloatType> increment = multiplier ; 339 340 // Compute the first group. 341 for (int i = 0 ; i <= butterfly_height - 1 ; ++i) 342 { 343 // Lower branch of a butterfly. 344 int offset = i + butterfly_height ; 345 346 complex<FloatType> temp = (*this)[ i ] + (*this)[ offset ] ; 347 (*this)[ offset ] = (*this)[ i ] - (*this)[ offset ] ; 348 (*this)[ i ] = temp ; 349 } 350 351 // Now do the remaining groups. 352 for (int group = 2 ; group <= number_of_groups ; ++group) 353 { 354 // Array index of first butterfly in group. 355 int start_of_group = reverse_bits( group - 1, log_of_n ) ; 356 357 // Array index of last butterfly in group. 358 int end_of_group = start_of_group + butterfly_height - 1 ; 359 360 // Compute all butterflies in a group. 361 for (int i = start_of_group ; i <= end_of_group ; ++i) 362 { 363 int offset = i + butterfly_height ; 364 365 // Temporary storage in a butterfly calculation. 366 complex<FloatType> product = (*this)[ offset ] * multiplier ; 367 368 complex<FloatType> temp = (*this)[ i ] + product ; 369 (*this)[ offset ] = (*this)[ i ] - product ; 370 (*this)[ i ] = temp ; 371 372 } 373 374 multiplier *= increment ; 375 } // end group 376 377 butterfly_height = butterfly_height / 2 ; 378 number_of_groups = number_of_groups * 2 ; 379 380 } // end column 381 382 383 384 // Normalize the results by \/ N and permute them into order, two at a time. 385 FloatType normalizer = (FloatType) 1.0 / sqrt( (FloatType) N ) ; 386 387 388 for (int i = 0 ; i <= N - 1 ; ++i) 389 { 390 // Bit-reversed array index i. 391 int rev_i = reverse_bits( i, log_of_n ) ; 392 393 if ( rev_i > i ) // Exchange is not yet done. 394 { 395 complex<FloatType> temp = (*this)[ i ] ; 396 (*this)[ i ] = (*this)[ rev_i ] * normalizer ; 397 (*this)[ rev_i ] = temp * normalizer ; 398 } 399 else if ( rev_i == i ) // exchange with itself 400 { 401 (*this)[ i ] = (*this)[ i ] * normalizer ; 402 } 403 } 404 405 return ; 406 407 } /* ====================== end of function fft ============================= */ 408 409 410 411 /*============================================================================= 412 | 413 | NAME 414 | 415 | reverse_bits 416 | 417 | DESCRIPTION 418 | 419 | This function reverses the order of the bits in a number. 420 | 421 | INPUT 422 | 423 | n The number whose bits are to be reversed. 424 | num_bits The number of bits in N, counting leading zeros. 425 | 426 | OUTPUT 427 | 428 | The number N with all its num_bits bits reversed. 429 | 430 | EXAMPLE CALLING SEQUENCE 431 | 432 | reverse_bits( (10) , 2 ) = (01) = 1, but 433 | 2 2 434 | 435 | reverse_bits( (10) , 3 ) = reverse_bits( (010) , 3 ) = (010) = (10) 436 | 2 2 2 2 437 | = 10 438 | 439 | 440 | METHOD 441 | 442 | The algorithm works by a method similar to base conversion. 443 | As the low order bits are broken off, one by one, they are 444 | multiplied by 2 and accumulated to generate the bit-reversed 445 | number. 446 | 447 | BUGS 448 | 449 | The bit-reversal routine could be made faster by using C shift operators. 450 | 451 +============================================================================*/ 452 453 template <typename FloatType> 454 int FastFourierTransform<FloatType>::reverse_bits( int n, int num_bits ) 455 { 456 int 457 remainder = n, // Bits remaining to be reversed. 458 reversed_n = 0 ; // Bit-reversed value of n. 459 460 for (int bit_num = 1 ; bit_num <= num_bits ; ++bit_num) 461 { 462 int bit = remainder % 2 ; /* Next least significant bit. */ 463 reversed_n = bit + 2 * reversed_n ; /* Shift left and add to buffer. */ 464 remainder = (int)( remainder / 2 ) ; /* Remaining bits. */ 465 } 466 467 return( reversed_n ) ; 468 469 } /* ===================== end of function reverse_bits ===================== */ 470 471 472 /*============================================================================== 473 | Forced Template Instantiations | 474 ==============================================================================*/ 475 476 // C++ doesn't automatically generate templated classes or functions until they 477 // are first used. So depending on the order of compilation, the linker may say 478 // the templated functions are undefined. 479 // 480 // Therefore, explicitly instantiate ALL templates here: 481 482 template FastFourierTransform<float>::FastFourierTransform() ; 483 template FastFourierTransform<float>::FastFourierTransform( const FastFourierTransform<float> & ) ; 484 template FastFourierTransform<float>::~FastFourierTransform() ; 485 template void FastFourierTransform<float>::fft( bool ) ; 486 487 template FastFourierTransform<double>::FastFourierTransform() ; 488 template FastFourierTransform<double>::FastFourierTransform( const FastFourierTransform<double> & ) ; 489 template FastFourierTransform<double>::~FastFourierTransform() ; 490 template void FastFourierTransform<double>::fft( bool ) ; 491