mirror of
https://github.com/mborgerding/kissfft.git
synced 2025-07-18 21:14:24 -04:00
fwd, inverse N-d real FFTs now work to the best of my knowledge
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user