fwd, inverse N-d real FFTs now work to the best of my knowledge

This commit is contained in:
Mark Borgerding
2006-11-14 18:57:44 +00:00
parent b4d5ded242
commit 97ce553a94
4 changed files with 68 additions and 77 deletions

View File

@ -14,18 +14,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#include "kiss_fftndr.h"
#include "_kiss_fft_guts.h"
// copied from kiss_fftnd.c
struct kiss_fftnd_state{
int dimprod;
int ndims;
int *dims;
kiss_fft_cfg *states; /* cfg states for each dimension */
kiss_fft_cpx * tmpbuf; /*buffer capable of hold the entire input */
};
#define MAX(x,y) ( ( (x)<(y) )?(y):(x) )
struct kiss_fftndr_state
{
@ -44,22 +33,19 @@ static int prod(const int *dims, int ndims)
return x;
}
#define CHK fprintf(stderr,"line=%d\t",__LINE__)
kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void*mem,size_t*lenmem)
{
kiss_fftndr_cfg st = NULL;
size_t nr=0 , nd=0,ntmp=0;
int dimReal = dims[0];
int dimOther = prod(dims+1,ndims-1);
int dimReal = dims[ndims-1];
int dimOther = prod(dims,ndims-1);
(void)kiss_fftr_alloc(dims[0],inverse_fft,NULL,&nr);
(void)kiss_fftnd_alloc(dims+1,ndims-1,inverse_fft,NULL,&nd);
(void)kiss_fftr_alloc(dimReal,inverse_fft,NULL,&nr);
(void)kiss_fftnd_alloc(dims,ndims-1,inverse_fft,NULL,&nd);
ntmp =
dimReal * sizeof(kiss_fft_scalar) // time buffer for one pass
+ (dimReal+2) * sizeof(kiss_fft_scalar) // freq buffer for one pass
MAX( 2*dimOther , dimReal+2) * sizeof(kiss_fft_scalar) // freq buffer for one pass
+ dimOther*(dimReal+2) * sizeof(kiss_fft_scalar); // large enough to hold entire input in case of in-place
size_t memneeded = sizeof( struct kiss_fftndr_state ) + nr + nd + ntmp;
if (lenmem==NULL) {
@ -75,12 +61,8 @@ kiss_fftndr_cfg kiss_fftndr_alloc(const int *dims,int ndims,int inverse_fft,void
st->dimReal = dimReal;
st->dimOther = dimOther;
st->cfg_r = kiss_fftr_alloc( dims[0],inverse_fft,st+1,&nr);
st->cfg_nd = kiss_fftnd_alloc(dims+1,ndims-1,inverse_fft, ((char*) st->cfg_r)+nr,&nd);
// tell the N-D complex FFT to stride the input
st->cfg_nd->dimprod *= (dims[0]/2+1);
st->cfg_r = kiss_fftr_alloc( dimReal,inverse_fft,st+1,&nr);
st->cfg_nd = kiss_fftnd_alloc(dims,ndims-1,inverse_fft, ((char*) st->cfg_r)+nr,&nd);
st->tmpbuf = (char*)st->cfg_nd + nd;
return st;
@ -92,44 +74,50 @@ void kiss_fftndr(kiss_fftndr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx
int dimReal = st->dimReal;
int dimOther = st->dimOther;
kiss_fft_scalar * t1 = (kiss_fft_scalar*)st->tmpbuf; // enough to hold dimReal scalars
kiss_fft_cpx * t2 = (kiss_fft_cpx*)(t1+dimReal); // enough to hold the entire input (only used if in==out)
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
kiss_fft_cpx * tmp2;
if (dimReal/2+1 > dimOther)
tmp2 = tmp1+dimReal/2+1;
else
tmp2 = tmp1+dimOther;
fprintf(stderr,"dimReal=%d\n",dimReal);
fprintf(stderr,"dimOther=%d\n",dimOther);
fprintf(stderr,"t1=%p\n",t1);
fprintf(stderr,"t2=%p\n",t2);
// timedata is N0 x N1 x ... x Nk real
// take the real data, fft it and transpose
// take a real chunk of data, fft it and place the output at correct intervals
for (k1=0;k1<dimOther;++k1) {
for (k2=0;k2<dimReal;++k2)
t1[k2] = timedata[k1 + k2*dimOther]; // select the appropriate samples into a contiguous buffer
//then fft the N real samples to create N/2+1 complex points
kiss_fftr( st->cfg_r, t1, t2 + k1*(dimReal/2+1) );
fprintf(stderr,"t1=fft([ " );
for (k2=0;k2<dimReal;++k2)
fprintf(stderr,"%f ",t1[k2] );
fprintf(stderr,"])\n" );
kiss_fftr( st->cfg_r, timedata + k1*dimReal , tmp1 ); // tmp1 now holds dimReal/2+1 complex points
for (k2=0;k2<dimReal/2+1;++k2)
tmp2[ k2*dimOther+k1 ] = tmp1[k2];
}
// fft the remaining dimensions just like the N-D complex case
kiss_fftnd(st->cfg_nd, t2,freqdata);
fprintf(stderr,"out=[ " );
for (k1=0;k1<dimOther;++k1) {
for (k2=0;k2<dimReal/2+1;++k2) {
kiss_fft_cpx c = freqdata[k1*(dimReal/2+1) +k2];
fprintf(stderr,"%f%+fi ",c.r , c.i );
}
fprintf(stderr,"\n" );
for (k2=0;k2<dimReal/2+1;++k2) {
kiss_fftnd(st->cfg_nd, tmp2+k2*dimOther, tmp1); // tmp1 now holds dimOther complex points
for (k1=0;k1<dimOther;++k1)
freqdata[ k1*(dimReal/2+1) + k2] = tmp1[k1];
}
fprintf(stderr,"]\n" );
}
void kiss_fftndri(kiss_fftndr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
memset(timedata,0,sizeof(kiss_fft_scalar) * st->dimReal * st->dimOther);
int k1,k2;
int dimReal = st->dimReal;
int dimOther = st->dimOther;
kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf;
kiss_fft_cpx * tmp2;
if (dimReal/2+1 > dimOther)
tmp2 = tmp1+dimReal/2+1;
else
tmp2 = tmp1+dimOther;
for (k2=0;k2<dimReal/2+1;++k2) {
for (k1=0;k1<dimOther;++k1)
tmp1[k1] = freqdata[ k1*(dimReal/2+1) + k2 ];
kiss_fftnd(st->cfg_nd, tmp1, tmp2+k2*dimOther);
}
for (k1=0;k1<dimOther;++k1) {
for (k2=0;k2<dimReal/2+1;++k2)
tmp1[k2] = tmp2[ k2*dimOther+k1 ];
kiss_fftri( st->cfg_r,tmp1,timedata + k1*dimReal);
}
}