static void LTFAT_NAME(dctMexAtExitFnc)() { if (LTFAT_NAME(p_old) != 0) { LTFAT_FFTW(destroy_plan)(LTFAT_NAME(p_old)); } }
void LTFAT_NAME(fftrealAtExit)() { if(LTFAT_NAME(p_old)!=0) { LTFAT_FFTW(destroy_plan)(LTFAT_NAME(p_old)); } }
LTFAT_API void ltfat_free(const void* ptr) { if (ltfat_custom_free) (*ltfat_custom_free)((void*)ptr); else #ifdef FFTW LTFAT_FFTW(free)((void*)ptr); #elif KISS ltfat_aligned_free((void*)ptr); #endif }
LTFAT_API void* ltfat_malloc (size_t n) { void* outp; if (ltfat_custom_malloc) outp = (*ltfat_custom_malloc)(n); else #ifdef FFTW outp = LTFAT_FFTW(malloc)(n); #elif KISS outp = ltfat_aligned_malloc(n); #else #error "No FFT backend specified. Use -DKISS or -DFFTW" #endif return outp; }
void LTFAT_NAME(ltfatMexFnc)( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] ) { #ifdef LTFAT_DOUBLE if(p_old==0) { mexAtExit(ifftrealAtExit); } #endif mwSize ii, L, W, L2; LTFAT_FFTW(plan) p; LTFAT_REAL *f, s; LTFAT_REAL *fin_r, *fin_i; L2 = (mwSize) mxGetM(prhs[0]); W = (mwSize) mxGetN(prhs[0]); L = (mwSize) mxGetScalar(prhs[1]); if(L/2+1!=L2) mexErrMsgTxt("Invalid output length"); fin_r = (LTFAT_REAL*)mxGetPr(prhs[0]); fin_i = (LTFAT_REAL*)mxGetPi(prhs[0]); // Case when input is real if(!mxIsComplex(prhs[0])) { mxArray* tmpIn = ltfatCreateMatrix(L2, W, LTFAT_MX_CLASSID , mxCOMPLEX); LTFAT_REAL *fin_r_old = (LTFAT_REAL*)mxGetPr(prhs[0]); fin_r = (LTFAT_REAL*)mxGetPr(tmpIn); fin_i = (LTFAT_REAL*)mxGetPi(tmpIn); for(mwIndex jj=0;jj<L2*W;jj++) { fin_r[jj]= fin_r_old[jj]; fin_i[jj]= (LTFAT_REAL )0.0; } } // Create output and get pointer plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID , mxREAL); f= (LTFAT_REAL*) mxGetPr(plhs[0]); // This section is not being compiled. It contains a segmentation // faults. The idea is to pass Matlab's split memory layout directly // to FFTW LTFAT_FFTW(iodim) dims[1], howmanydims[1]; // Create plan. Copy data from cin to f. dims[0].n = L; dims[0].is = 1; dims[0].os = 1; howmanydims[0].n = W; howmanydims[0].is = L2; howmanydims[0].os = L; // The calling prototype // fftw_plan fftw_plan_guru_split_dft_c2r( // int rank, const fftw_iodim *dims, // int howmany_rank, const fftw_iodim *howmany_dims, // double *ri, double *ii, double *out, // unsigned flags); p = LTFAT_FFTW(plan_guru_split_dft_c2r)(1, dims, 1, howmanydims, fin_r,fin_i,f, FFTW_OPTITYPE); if(p_old!=0) { fftw_destroy_plan(*p_old); free(p_old); } p_old = malloc(sizeof(p)); memcpy(p_old,&p,sizeof(p)); // Real IFFT. LTFAT_FFTW(execute)(p); //LTFAT_FFTW(destroy_plan)(p); // Scale, because FFTW's normalization is different. s = (LTFAT_REAL) (1.0/((LTFAT_REAL)L)); for (ii=0; ii<L*W; ii++) { f[ii] *=s; } return; }
LTFAT_EXTERN void LTFAT_NAME(idgt_fb)(const LTFAT_COMPLEX *cin, const LTFAT_COMPLEX *g, const int L, const int gl, const int W, const int a, const int M, LTFAT_COMPLEX *f) { /* --------- initial declarations -------------- */ const int N=L/a; int ep, sp; /* This is a floor operation. */ const int glh=gl/2; /* This is a ceil operation. */ const int glh_d_a=(int)ceil((glh*1.0)/(a)); LTFAT_COMPLEX *fw; LTFAT_COMPLEX *cbuf = (LTFAT_COMPLEX*)ltfat_malloc(M*sizeof(LTFAT_COMPLEX)); /* Create plan. In-place. */ LTFAT_FFTW(plan) p_small = LTFAT_FFTW(plan_dft_1d)(M, cbuf, cbuf, FFTW_BACKWARD, FFTW_MEASURE); /* % The fftshift actually makes some things easier. */ LTFAT_COMPLEX *gw = (LTFAT_COMPLEX*)ltfat_malloc(gl*sizeof(LTFAT_COMPLEX)); for (int l=0;l<glh;l++) { gw[l][0] = g[l+(gl-glh)][0]; gw[l][1] = g[l+(gl-glh)][1]; } for (int l=glh;l<gl;l++) { gw[l][0] = g[l-glh][0]; gw[l][1] = g[l-glh][1]; } LTFAT_COMPLEX *ff = (LTFAT_COMPLEX*)ltfat_malloc(gl*sizeof(LTFAT_COMPLEX)); for (int w=0; w<W; w++) { fw=f+w*L; for (int l=0;l<L;l++) { fw[l][0]=0.0; fw[l][1]=0.0; } /* ----- Handle the first boundary using periodic boundary conditions. --- */ for (int n=0; n<glh_d_a; n++) { THE_SUM; sp=positiverem(n*a-glh,L); ep=positiverem(n*a-glh+gl-1,L); /* % Add the ff vector to f at position sp. */ for (int ii=0;ii<L-sp;ii++) { fw[sp+ii][0]+=ff[ii][0]; fw[sp+ii][1]+=ff[ii][1]; } for (int ii=0; ii<ep+1;ii++) { fw[ii][0] +=ff[L-sp+ii][0]; fw[ii][1] +=ff[L-sp+ii][1]; } } /* ----- Handle the middle case. --------------------- */ for (int n=glh_d_a; n<(L-(gl+1)/2)/a+1; n++) { THE_SUM; sp=positiverem(n*a-glh,L); ep=positiverem(n*a-glh+gl-1,L); /* Add the ff vector to f at position sp. */ for (int ii=0;ii<ep-sp+1;ii++) { fw[ii+sp][0] += ff[ii][0]; fw[ii+sp][1] += ff[ii][1]; } } /* Handle the last boundary using periodic boundary conditions. */ for (int n=(L-(gl+1)/2)/a+1; n<N; n++) { THE_SUM; sp=positiverem(n*a-glh,L); ep=positiverem(n*a-glh+gl-1,L); /* Add the ff vector to f at position sp. */ for (int ii=0;ii<L-sp;ii++) { fw[sp+ii][0]+=ff[ii][0]; fw[sp+ii][1]+=ff[ii][1]; } for (int ii=0; ii<ep+1;ii++) { fw[ii][0] +=ff[L-sp+ii][0]; fw[ii][1] +=ff[L-sp+ii][1]; } } } ltfat_free(cbuf); ltfat_free(ff); ltfat_free(gw); LTFAT_FFTW(destroy_plan)(p_small); }
void LTFAT_NAME(ltfatMexFnc)( int UNUSED(nlhs), mxArray *plhs[], int UNUSED(nrhs), const mxArray *prhs[] ) { // Register exit function only once static int atExitFncRegistered = 0; if (!atExitFncRegistered) { LTFAT_NAME(ltfatMexAtExit)(LTFAT_NAME(dctMexAtExitFnc)); atExitFncRegistered = 1; } LTFAT_REAL *c_r, *c_i=NULL; const LTFAT_REAL *f_r, *f_i=NULL; dct_kind kind = DCTI; // This is overwritten mwIndex L = mxGetM(prhs[0]); mwIndex W = mxGetN(prhs[0]); mwIndex type = (mwIndex) mxGetScalar(prhs[1]); // Copy inputs and get pointers if ( mxIsComplex(prhs[0])) { f_i = mxGetImagData(prhs[0]); plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxCOMPLEX); c_i = mxGetImagData(plhs[0]); } else { plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxREAL); } f_r = mxGetData(prhs[0]); c_r = mxGetData(plhs[0]); switch (type) { case 1: kind = DCTI; break; case 2: kind = DCTII; break; case 3: kind = DCTIII; break; case 4: kind = DCTIV; break; default: mexErrMsgTxt("Unknown type."); } LTFAT_FFTW(plan) p = LTFAT_NAME(dct_init)( L, W, c_r, kind); /* The old plan is freed after the new one is cretaed. According to the FFTW doc. creating new plan is quick as long as there already exists a plan for the same length. */ LTFAT_NAME(dctMexAtExitFnc)(); LTFAT_NAME(p_old) = p; LTFAT_NAME(dct_execute)(p, f_r, L, W, c_r, kind); if ( mxIsComplex(prhs[0])) { LTFAT_NAME(dct_execute)(p, f_i, L, W, c_i, kind); } return; }
/* wfac for real valued input. */ LTFAT_EXTERN void LTFAT_NAME(wfac_r)(const LTFAT_REAL *g, const int L, const int R, const int a, const int M, LTFAT_COMPLEX *gf) { int h_a, h_m; LTFAT_REAL *sbuf, *gfp; int s; int rem, negrem; LTFAT_FFTW(plan) p_before; const int b=L/M; const int c=gcd(a, M,&h_a, &h_m); const int p=a/c; const int q=M/c; const int d=b/p; const double sqrtM=sqrt(M); sbuf = (LTFAT_REAL*)ltfat_malloc(2*d*sizeof(LTFAT_REAL)); /* Create plan. In-place. */ p_before = LTFAT_FFTW(plan_dft_1d)(d, (LTFAT_COMPLEX*)sbuf, (LTFAT_COMPLEX*)sbuf, FFTW_FORWARD, FFTW_MEASURE); const int ld3=c*p*q*R; gfp=(LTFAT_REAL*)gf; for (int r=0;r<c;r++) { for (int w=0;w<R;w++) { for (int l=0;l<q;l++) { for (int k=0;k<p;k++) { negrem = positiverem(k*M-l*a,L); for (s=0;s<d;s++) { rem = (negrem+s*p*M)%L; sbuf[2*s] = sqrtM*g[r+rem+L*w]; sbuf[2*s+1] = 0.0; } LTFAT_FFTW(execute)(p_before); for (s=0;s<2*d;s+=2) { gfp[s*ld3] = sbuf[s]; gfp[s*ld3+1]= sbuf[s+1]; } gfp+=2; } } } } ltfat_free(sbuf); }
/* wfac for real valued input. Produces only half the output coefficients of wfac_r */ LTFAT_EXTERN void LTFAT_NAME(wfacreal)(const LTFAT_REAL *g, const int L, const int R, const int a, const int M, LTFAT_COMPLEX *gf) { int h_a, h_m; LTFAT_REAL *gfp; int s; int rem, negrem; LTFAT_FFTW(plan) p_before; const int b=L/M; const int c=gcd(a, M,&h_a, &h_m); const int p=a/c; const int q=M/c; const int d=b/p; /* This is a floor operation. */ const int d2= d/2+1; const double sqrtM=sqrt(M); LTFAT_REAL *sbuf = (LTFAT_REAL*)ltfat_malloc(d*sizeof(LTFAT_REAL)); LTFAT_COMPLEX *cbuf = (LTFAT_COMPLEX*)ltfat_malloc(d2*sizeof(LTFAT_COMPLEX)); /* Create plan. In-place. */ p_before = LTFAT_FFTW(plan_dft_r2c_1d)(d, sbuf, cbuf, FFTW_MEASURE); const int ld3=2*c*p*q*R; gfp=(LTFAT_REAL*)gf; for (int r=0;r<c;r++) { for (int w=0;w<R;w++) { for (int l=0;l<q;l++) { for (int k=0;k<p;k++) { negrem = positiverem(k*M-l*a,L); for (s=0;s<d;s++) { rem = (negrem+s*p*M)%L; sbuf[s] = sqrtM*g[r+rem+L*w]; } LTFAT_FFTW(execute)(p_before); for (s=0;s<d2;s++) { gfp[s*ld3] = cbuf[s][0]; gfp[s*ld3+1]= cbuf[s][1]; } gfp+=2; } } } } ltfat_free(sbuf); }
void LTFAT_NAME(ltfatMexFnc)( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] ) { #ifdef LTFAT_DOUBLE if(p_old==0) { mexAtExit(fftrealAtExit); } #endif int L, W, L2; LTFAT_REAL *f, *cout_r, *cout_i; LTFAT_FFTW(iodim) dims[1], howmanydims[1]; LTFAT_FFTW(plan) p; L = mxGetM(prhs[0]); W = mxGetN(prhs[0]); L2 = (L/2)+1; // Get pointer to input. f= (LTFAT_REAL*) mxGetPr(prhs[0]); plhs[0] = ltfatCreateMatrix(L2, W, LTFAT_MX_CLASSID, mxCOMPLEX); // Get pointer to output. cout_r = (LTFAT_REAL*) mxGetPr(plhs[0]); cout_i = (LTFAT_REAL*) mxGetPi(plhs[0]); // Create plan. Copy data from f to cout. dims[0].n = L; dims[0].is = 1; dims[0].os = 1; howmanydims[0].n = W; howmanydims[0].is = L; howmanydims[0].os = L2; // The calling prototype //fftw_plan fftw_plan_guru_split_dft_r2c( // int rank, const fftw_iodim *dims, // int howmany_rank, const fftw_iodim *howmany_dims, // double *in, double *ro, double *io, // unsigned flags); /* We are violating this here: You must create the plan before initializing the input, because FFTW_MEASURE overwrites the in/out arrays. (Technically, FFTW_ESTIMATE does not touch your arrays, but you should always create plans first just to be sure.) */ p = LTFAT_FFTW(plan_guru_split_dft_r2c)(1, dims, 1, howmanydims, f, cout_r, cout_i, FFTW_ESTIMATE); /* FFTW documentation qote http://www.fftw.org/fftw3_doc/New_002darray-Execute-Functions.html#New_002darray-Execute-Functions: ... creating a new plan is quick once one exists for a given size ... so why not to store the old plan.. */ if(p_old!=0) { fftw_destroy_plan(*p_old); free(p_old); } p_old = malloc(sizeof(p)); memcpy(p_old,&p,sizeof(p)); // Real FFT. LTFAT_FFTW(execute)(p); // LTFAT_FFTW(destroy_plan)(p); return; }
void LTFAT_NAME(ltfatMexFnc)( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { static int atExitRegistered = 0; if(!atExitRegistered) { LTFAT_NAME(ltfatMexAtExit)(LTFAT_NAME(fftrealAtExit)); atExitRegistered = 1; } mwSignedIndex L, W, L2; LTFAT_REAL *f, *cout_r, *cout_i; LTFAT_FFTW(iodim) dims[1], howmanydims[1]; LTFAT_FFTW(plan) p; L = mxGetM(prhs[0]); W = mxGetN(prhs[0]); L2 = (L/2)+1; // Get pointer to input. f= mxGetData(prhs[0]); plhs[0] = ltfatCreateMatrix(L2, W, LTFAT_MX_CLASSID, mxCOMPLEX); // Get pointer to output. cout_r = mxGetData(plhs[0]); cout_i = mxGetImagData(plhs[0]); // Create plan. Copy data from f to cout. dims[0].n = L; dims[0].is = 1; dims[0].os = 1; howmanydims[0].n = W; howmanydims[0].is = L; howmanydims[0].os = L2; // The calling prototype //fftw_plan fftw_plan_guru_split_dft_r2c( // int rank, const fftw_iodim *dims, // int howmany_rank, const fftw_iodim *howmany_dims, // double *in, double *ro, double *io, // unsigned flags); /* We are violating this here: You must create the plan before initializing the input, because FFTW_MEASURE overwrites the in/out arrays. (Technically, FFTW_ESTIMATE does not touch your arrays, but you should always create plans first just to be sure.) */ p = LTFAT_FFTW(plan_guru_split_dft_r2c)(1, dims, 1, howmanydims, f, cout_r, cout_i, FFTW_ESTIMATE); /* ... creating a new plan is quick once one exists for a given size ... so why not to store the old plan.. */ LTFAT_NAME(fftrealAtExit)(); LTFAT_NAME(p_old) = p; // Real FFT. LTFAT_FFTW(execute)(p); // LTFAT_FFTW(destroy_plan)(p); return; }
void LTFAT_NAME(ltfatMexFnc)( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { // Register exit function only once static int atExitFncRegistered = 0; if(!atExitFncRegistered) { LTFAT_NAME(ltfatMexAtExit)(LTFAT_NAME(dctMexAtExitFnc)); atExitFncRegistered = 1; } LTFAT_REAL *c_r, *c_i; const LTFAT_REAL *f_r, *f_i; dct_kind kind; mwIndex L = mxGetM(prhs[0]); mwIndex W = mxGetN(prhs[0]); mwIndex type = (mwIndex) mxGetScalar(prhs[1]); // Copy inputs and get pointers if( mxIsComplex(prhs[0])) { f_i = mxGetImagData(prhs[0]); plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxCOMPLEX); c_i = mxGetImagData(plhs[0]); } else { plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxREAL); } f_r = mxGetData(prhs[0]); c_r = mxGetData(plhs[0]); switch(type) { case 1: kind = DSTI; break; case 2: kind = DSTII; break; case 3: kind = DSTIII; break; case 4: kind = DSTIV; break; default: mexErrMsgTxt("Unknown type."); } LTFAT_FFTW(plan) p = LTFAT_NAME(dst_init)( L, W, c_r, kind); LTFAT_NAME(dctMexAtExitFnc)(); LTFAT_NAME(p_old) = p; LTFAT_NAME(dst_execute)(p,f_r,L,W,c_r,kind); if( mxIsComplex(prhs[0])) { LTFAT_NAME(dst_execute)(p,f_i,L,W,c_i,kind); } return; }
void LTFAT_NAME(ltfatMexFnc)( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[] ) { // Register exit function only once #ifdef LTFAT_DOUBLE if(p_old==0) { mexAtExit(fftrealAtExit); } #endif mwIndex L, W, N, type; LTFAT_REAL *f_r, *f_i; LTFAT_FFTW(iodim) dims[1], howmanydims[1]; LTFAT_FFTW(plan) p; LTFAT_FFTW(r2r_kind) kind[1]; L = mxGetM(prhs[0]); W = mxGetN(prhs[0]); N = 2*L; type = (mwIndex) mxGetScalar(prhs[1]); // Copy inputs and get pointers if( mxIsComplex(prhs[0])) { plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxCOMPLEX); f_i = (LTFAT_REAL*) mxGetPi(plhs[0]); memcpy(f_i,mxGetPi(prhs[0]),W*L*sizeof(LTFAT_REAL)); } else { plhs[0] = ltfatCreateMatrix(L, W, LTFAT_MX_CLASSID, mxREAL); } f_r = (LTFAT_REAL*) mxGetPr(plhs[0]); memcpy(f_r,mxGetPr(prhs[0]),W*L*sizeof(LTFAT_REAL)); // Create plan. Copy data from f to cout. dims[0].n = L; dims[0].is = 1; dims[0].os = 1; howmanydims[0].n = W; howmanydims[0].is = L; howmanydims[0].os = L; LTFAT_REAL sqrt2 = (LTFAT_REAL) sqrt(2.0); LTFAT_REAL postScale = (LTFAT_REAL) 1.0/sqrt2; LTFAT_REAL scale = (LTFAT_REAL) sqrt2*(1.0/(double)N)*sqrt((double)L); // Re-allocate and prescale input if(type==1||type==3) { for(mwIndex ii=0; ii<W; ii++) { f_r[ii*L] *= sqrt2; } if(mxIsComplex(prhs[0])) { for(mwIndex ii=0; ii<W; ii++) { f_i[ii*L] *= sqrt2; } } } switch(type) { case 1: N -= 2; for(mwIndex ii=0; ii<W; ii++) { f_r[(ii+1)*L-1] *= sqrt2; } if(mxIsComplex(prhs[0])) { for(mwIndex ii=0; ii<W; ii++) { f_i[(ii+1)*L-1] *= sqrt2; } } scale = (LTFAT_REAL) sqrt2*(1.0/((double)N))*sqrt((double)L-1); kind[0] = FFTW_REDFT00; break; case 2: kind[0] = FFTW_REDFT10; break; case 3: kind[0] = FFTW_REDFT01; break; case 4: kind[0] = FFTW_REDFT11; break; default: mexErrMsgTxt("Unknown type."); } // The calling prototype //fftw_plan fftw_plan_guru_split_dft_r2c( // int rank, const fftw_iodim *dims, // int howmany_rank, const fftw_iodim *howmany_dims, // double *in, double *ro, double *io, // unsigned flags); p = LTFAT_FFTW(plan_guru_r2r)(1, dims, 1, howmanydims, f_r, f_r, kind, FFTW_OPTITYPE); /* FFTW documentation qote http://www.fftw.org/fftw3_doc/New_002darray-Execute-Functions.html#New_002darray-Execute-Functions: ... creating a new plan is quick once one exists for a given size ... so why not to store the old plan.. */ if(p_old!=0) { fftw_destroy_plan(*p_old); free(p_old); } p_old = malloc(sizeof(p)); memcpy(p_old,&p,sizeof(p)); // Real FFT. LTFAT_FFTW(execute)(p); // Do the normalization for(int ii=0; ii<L*W; ii++) { f_r[ii] *= scale; } if(type==1||type==2) { // Scale DC component for(int ii=0; ii<W; ii++) { f_r[ii*L] *= postScale; } } if(type==1) { // Scale AC component for(int ii=0; ii<W; ii++) { f_r[(ii+1)*L-1] *= postScale; } } // If the input is complex, process the imaginary part if(mxIsComplex(prhs[0])) { LTFAT_FFTW(execute_r2r)(p,f_i,f_i); // Do the normalization for(int ii=0; ii<L*W; ii++) { f_i[ii] *= scale; } if(type==1||type==2) { // Scale DC component for(int ii=0; ii<W; ii++) { f_i[ii*L] *= postScale; } } if(type==1) { // Scale AC component for(int ii=0; ii<W; ii++) { f_i[(ii+1)*L-1] *= postScale; } } } // LTFAT_FFTW(destroy_plan)(p); return; }