/* ------------------------------------------------------------------------------ * * Copyright (C) 2013, see file AUTHORS for list of authors/contributors * * This file is part of PROTEUS. * * PROTEUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2.0 of the License only. * * PROTEUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PROTEUS. See file COPYING and/or * . * ------------------------------------------------------------------------------ */ /************************************************************** * kube-gustavson-fft.c * * Forward and inverse discrete 2D Fourier transforms. * * Originally a FORTRAN implementation published in: * Programming for Digital Signal Processing, IEEE Press 1979, * Section 1, by G. D. Bergland and M. T. Dolan. * Ported long ago from Fortran to old-fashioned Standard C by * someone who failed to put his or her name in the source. * Ported from Standard C to ANSI C by Stefan Gustavson * (stegu@itn.liu.se) 2003-10-20. * * This is a pretty fast FFT algorithm. Not super-optimized * lightning-fast, but very good considering its age and * relative simplicity. There are several places in the code * where clock cycles could be saved, for example by getting rid * of some copying of data back and forth, but the savings * would not be that great. If you want optimally fast FFTs, * consider the excellent FFTW package. (http://www.fftw.org) * * This software is in the public domain. * ************************************************************** * * int forward_fft2f(COMPLEX *array, int rows, int cols) * int inverse_fft2f(COMPLEX *array, int rows, int cols) * int forward_fft2d(DCOMPLEX *array, int rows, int cols) * int inverse_fft2d(DCOMPLEX *array, int rows, int cols) * * These functions compute the forward and inverse DFT's, respectively, * of a single-precision COMPLEX or DCOMPLEX array by means of an * FFT algorithm. * * The result is a COMPLEX/DCOMPLEX array of the same size, returned * in the same space as the input array. That is, the original array * is overwritten and destroyed. * * Rows and columns must each be an integral power of 2. * * These routines return integer value ERROR if an error was detected, * NO_ERROR otherwise. * * This particular implementation of the DFT uses the transform pair * defined as follows: * Let there be two complex arrays each with n rows and m columns. * Index them as * f(x,y): 0 <= x <= m - 1, 0 <= y <= n - 1 * F(u,v): -m/2 <= u <= m/2 - 1, -n/2 <= v <= n/2 - 1 * * Then the forward and inverse transforms are related as follows. * Forward: * F(u,v) = \sum_{x=0}^{m-1} \sum_{y=0}^{n-1} * f(x,y) \exp{-2\pi i (ux/m + vy/n)} * * Inverse: * f(x,y) = 1/(mn) \sum_{u=-m/2}^{m/2-1} \sum_{v=-n/2}^{n/2-1} * F(u,v) \exp{2\pi i (ux/m + vy/n)} * * Therefore, the transforms have these properties: * 1. \sum_x \sum_y f(x,y) = F(0,0) * 2. m n \sum_x \sum_y |f(x,y)|^2 = \sum_u \sum_v |F(u,v)|^2 * */ #include "fd.h" /* * These somewhat awkward macros move data between the input/output array * and stageBuff, while also performing any conversions float<->double. */ #define LoadRow(buffer,row,cols) if (1){\ register int j,k;\ for (j = row*cols, k = 0 ; k < cols ; j++, k++){\ stageBuff[k].re = buffer[j].re;\ stageBuff[k].im = buffer[j].im;\ }\ } else {} #define StoreRow(buffer,row,cols) if (1){\ register int j,k;\ for (j = row*cols, k = 0 ; k < cols ; j++, k++){\ buffer[j].re = stageBuff[k].re;\ buffer[j].im = stageBuff[k].im;\ }\ } else {} #define LoadCol(buffer,col,rows,cols) if (1){\ register int j,k;\ for (j = i,k = 0 ; k < rows ; j+=cols, k++){\ stageBuff[k].re = buffer[j].re;\ stageBuff[k].im = buffer[j].im;\ }\ } else {} #define StoreCol(buffer,col,rows,cols) if (1){\ register int j,k;\ for (j = i,k = 0 ; k < rows ; j+=cols, k++){\ buffer[j].re = stageBuff[k].re;\ buffer[j].im = stageBuff[k].im;\ }\ } else {} /* Do something useful with an error message */ #define handle_error(msg) fprintf(stderr,msg) DCOMPLEX *stageBuff; /* buffer to hold a row or column at a time */ COMPLEX *bigBuff; /* a pointer to a float input array */ DCOMPLEX *bigBuffd; /* a pointer to a double input array */ /* Allocate space for stageBuff */ int allocateBuffer(int size) { stageBuff = (DCOMPLEX*) malloc(size*sizeof(DCOMPLEX)); if(stageBuff==(DCOMPLEX*)NULL) { handle_error("Insufficient storage for fft buffers"); return(ERROR); } else return(NO_ERROR); } /* Free space for stageBuff */ void freeBuffer(void) { free((char*)stageBuff); } /* See if exactly one bit is set in integer argument */ int power_of_2(int n) { int bits=0; while(n) { bits += n & 1; n >>= 1; } return(bits==1); } /* Get binary log of integer argument - exact if n is a power of 2 */ int fastlog2(int n) { int log = -1; while(n) { log++; n >>= 1; } return(log); } /* Radix-2 iteration subroutine */ void R2TX(int nthpo, DCOMPLEX *c0, DCOMPLEX *c1) { int k,kk; double *cr0, *ci0, *cr1, *ci1, r1, fi1; cr0 = &(c0[0].re); ci0 = &(c0[0].im); cr1 = &(c1[0].re); ci1 = &(c1[0].im); for(k=0; k1) { cr1[kk] = c4*(br0-br1) - s4*(bi0-bi1); cr2[kk] = c2*(br2-bi3) - s2*(bi2+br3); cr3[kk] = c6*(br2+bi3) - s6*(bi2-br3); ci1[kk] = c4*(bi0-bi1) + s4*(br0-br1); ci2[kk] = c2*(bi2+br3) + s2*(br2-bi3); ci3[kk] = c6*(bi2-br3) + s6*(br2+bi3); tr = IRT2*(br5-bi5); ti = IRT2*(br5+bi5); cr4[kk] = c1*(br4+tr) - s1*(bi4+ti); ci4[kk] = c1*(bi4+ti) + s1*(br4+tr); cr5[kk] = c5*(br4-tr) - s5*(bi4-ti); ci5[kk] = c5*(bi4-ti) + s5*(br4-tr); tr = -IRT2*(br7+bi7); ti = IRT2*(br7-bi7); cr6[kk] = c3*(br6+tr) - s3*(bi6+ti); ci6[kk] = c3*(bi6+ti) + s3*(br6+tr); cr7[kk] = c7*(br6-tr) - s7*(bi6-ti); ci7[kk] = c7*(bi6-ti) + s7*(br6-tr); } else { cr1[kk] = br0 - br1; cr2[kk] = br2 - bi3; cr3[kk] = br2 + bi3; ci1[kk] = bi0 - bi1; ci2[kk] = bi2 + br3; ci3[kk] = bi2 - br3; tr = IRT2*(br5-bi5); ti = IRT2*(br5+bi5); cr4[kk] = br4 + tr; ci4[kk] = bi4 + ti; cr5[kk] = br4 - tr; ci5[kk] = bi4 - ti; tr = -IRT2*(br7+bi7); ti = IRT2*(br7-bi7); cr6[kk] = br6 + tr; ci6[kk] = bi6 + ti; cr7[kk] = br6 - tr; ci7[kk] = bi6 - ti; } } } } /* * FFT842 (Name kept from the original Fortran version) * This routine replaces the input DCOMPLEX vector by its * finite discrete complex fourier transform if in==FFT_FORWARD. * It replaces the input DCOMPLEX vector by its finite discrete * complex inverse fourier transform if in==FFT_INVERSE. * * The implementation is a radix-2 FFT, but with faster shortcuts for * radix-4 and radix-8. It performs as many radix-8 iterations as * possible, and then finishes with a radix-2 or -4 iteration if needed. */ void FFT842(int direction, int n, DCOMPLEX *b) /* direction: FFT_FORWARD or FFT_INVERSE * n: length of vector * *b: input vector */ { double fn, r, fi; int L[16],L1,L2,L3,L4,L5,L6,L7,L8,L9,L10,L11,L12,L13,L14,L15; /* int j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14;*/ int j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14; int i, j, ij, ji, ij1, ji1; /* int nn, n2pow, n8pow, nthpo, ipass, nxtlt, length;*/ int n2pow, n8pow, nthpo, ipass, nxtlt, length; n2pow = fastlog2(n); nthpo = n; fn = 1.0 / (double)nthpo; /* Scaling factor for inverse transform */ if(direction==FFT_FORWARD) /* Conjugate the input */ for(i=0;icols ? rows : cols; errflag = allocateBuffer(maxsize); if(errflag != NO_ERROR) return(errflag); /* Compute transform row by row */ if(cols>1) for(i=0;i1) for(i=0;icols ? rows : cols; // errflag = allocateBuffer(maxsize); // if(errflag != NO_ERROR) return(errflag); // // /* Compute transform row by row */ // if(cols>1) // for(i=0;i1) // for(i=0;i