/******************************************************************* This file extends the fftlib with 2d and 3d complex fft's and 2d real fft's. All fft's return results in-place. Temporary buffers for transposing columns are maintained privately via calls to fft2dInit, fft2dFree, fft3dInit, and fft3dFree. Note that you can call fft2dInit and fft3dInit repeatedly with the same sizes, the extra calls will be ignored. So, you could make a macro to call fft2dInit every time you call fft2d. *** Warning *** fft2dFree and fft3dFree also call fftFree so you must re-init all 1d fft sizes you are going to continue using *******************************************************************/ #include #include #include "fftlib.h" #include "fftext.h" #include "matlib.h" #include "dxpose.h" #include "fft2d.h" // use trick of using a real double transpose in place of a complex transpose if it fits #define cxpose(a,b,c,d,e,f) (2*sizeof(float)==sizeof(xdouble)) ? dxpose((xdouble *)(a), b, (xdouble *)(c), d, e, f) : cxpose(a,b,c,d,e,f); // for this trick to work you must NOT replace the xdouble declarations in // dxpose with float declarations. // pointers for temporary storage for four columns static float *Array2d[8*sizeof(long)] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; int fft2dInit(long M2, long M){ // init for fft2d, ifft2d, rfft2d, and rifft2d // malloc storage for 4 columns of 2d ffts then call fftinit for both row and column ffts sizes /* INPUTS */ /* M = log2 of number of columns */ /* M2 = log2 of number of rows */ /* of 2d matrix to be fourier transformed */ /* OUTPUTS */ /* private storage for columns of 2d ffts */ /* calls fftInit for cosine and bit reversed tables */ int theError = 1; if ((M2 >= 0) && (M2 < 8*sizeof(long))){ theError = 0; if (Array2d[M2] == 0){ Array2d[M2] = (float *) malloc( 4*2*POW2(M2)*sizeof(float) ); if (Array2d[M2] == 0) theError = 2; else{ theError = fftInit(M2); } } if (theError == 0) theError = fftInit(M); } return theError; } void fft2dFree(){ // free storage for columns of 2d ffts and call fftFree to free all BRLow and Utbl storage long i1; for (i1=8*sizeof(long)-1; i1>=0; i1--){ if (Array2d[i1] != 0){ free(Array2d[i1]); Array2d[i1] = 0; }; }; fftFree(); } void fft2d(float *data, long M2, long M){ /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ long i1; if((M2>0)&&(M>0)){ ffts(data, M, POW2(M2)); if (M>2) for (i1=0; i10)&&(M>0)){ iffts(data, M, POW2(M2)); if (M>2) for (i1=0; i1= 0) && (L < 8*sizeof(long))){ theError = 0; if (Array2d[L] == 0){ Array2d[L] = (float *) malloc( 4*2*POW2(L)*sizeof(float) ); if (Array2d[L] == 0) theError = 2; else{ theError = fftInit(L); } } if (theError == 0){ if (Array2d[M2] == 0){ Array2d[M2] = (float *) malloc( 4*2*POW2(M2)*sizeof(float) ); if (Array2d[M2] == 0) theError = 2; else{ theError = fftInit(M2); } } } if (theError == 0) theError = fftInit(M); } return theError; } void fft3dFree(){ // free storage for columns of all 2d&3d ffts and call fftFree to free all BRLow and Utbl storage fft2dFree(); } void fft3d(float *data, long M3, long M2, long M){ /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M3 = log2 of fft size number of pages */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ long i1; long i2; const long N = POW2(M); const long N2 = POW2(M2); const long N3 = POW2(M3); if((M3>0)&&(M2>0)&&(M>0)){ ffts(data, M, N3*N2); if (M>2) for (i2=0; i22) for (i1=0; i10)&&(M2>0)&&(M>0)){ iffts(data, M, N3*N2); if (M>2) for (i2=0; i22) for (i1=0; i10)&&(M>0)){ rffts(data, M, POW2(M2)); if (M==1){ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); } else if (M==2){ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); ffts(Array2d[M2], M2, 1); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 1, POW2(M2)); } else{ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 3); ffts(Array2d[M2], M2, 3); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 3, POW2(M2)); for (i1=4; i10)&&(M>0)){ if (M==1){ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); } else if (M==2){ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); iffts(Array2d[M2], M2, 1); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 1, POW2(M2)); } else{ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 3); iffts(Array2d[M2], M2, 3); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 3, POW2(M2)); for (i1=4; i1 1) && (N1>1)){ outdata[0] = data1[0] * data2[0]; // multiply the zero freq, zero wavenumber values outdata[1] = data1[1] * data2[1]; // multiply the zero freq, nyquest wavenumber values cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); outdata[N] = data1[N] * data2[N]; // multiply the nyquest freq, zero wavenumber values outdata[N+1] = data1[N+1] * data2[N+1]; // multiply the nyquest freq, nyquest wavenumber values cvprod(data1 + N+2, data2 + N+2, outdata + N+2, N/2-1); } else{ // really 1D rfft spectra N = N2 * N1; // one of these is a 1 if(N>1){ outdata[0] = data1[0] * data2[0]; // multiply the zero freq values outdata[1] = data1[1] * data2[1]; // multiply the nyquest freq values cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); // multiply the other positive freq values } else{ outdata[0] = data1[0] * data2[0]; } } }