mirror of
https://github.com/mborgerding/kissfft.git
synced 2025-06-04 01:28:23 -04:00
Fixed point works (in the loosest sense of the word "works")
Fixed point sums are divided by 2 each stage. This will never overflow for radix 2 ffts. For mixed radix, it may overflow, but will usually give better SNR. 'make test' output: ### testing SNR for 1024 point FFTs #### DOUBLE snr_t2f = 295.30 snr_f2t = 308.25 #### FLOAT snr_t2f = 146.92 snr_f2t = 143.25 #### SHORT snr_t2f = 54.645 snr_f2t = 24.677 #### timing 10000 x 1024 point FFTs #### DOUBLE Elapsed:0:25.96 user:19.77 sys:0.22 #### FLOAT Elapsed:0:06.62 user:5.48 sys:0.11 #### SHORT Elapsed:0:06.01 user:4.75 sys:0.12
This commit is contained in:
parent
61571342a5
commit
7ec9402d5b
126
kiss_fft.c
126
kiss_fft.c
@ -33,9 +33,31 @@ const double pi=3.14159265358979323846264338327;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int nfft;
|
int nfft;
|
||||||
int inverse;
|
int inverse;
|
||||||
|
int *factors;
|
||||||
kiss_fft_cpx * twiddles;
|
kiss_fft_cpx * twiddles;
|
||||||
|
kiss_fft_cpx * tmpbuf;
|
||||||
|
kiss_fft_cpx * scratch;
|
||||||
}kiss_fft_state;
|
}kiss_fft_state;
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
|
# define C_ADD(x,a,b) \
|
||||||
|
do{ (x).r = ( ( (a).r+(b).r ) );\
|
||||||
|
(x).i = ( ( (a).i+(b).i ) ); }while(0)
|
||||||
|
# define C_SUB(x,a,b) \
|
||||||
|
do{ (x).r = ( ( (a).r-(b).r ) );\
|
||||||
|
(x).i = ( ( (a).i-(b).i ) ); }while(0)
|
||||||
|
/* We don't have to worry about overflow from multiplying by twiddle factors since they
|
||||||
|
* all have unity magnitude. Still need to shift away fractional bits after adding 1/2 for
|
||||||
|
* rounding.
|
||||||
|
* */
|
||||||
|
# define C_MUL(m,a,b) \
|
||||||
|
do{ (m).r = ( ( (a).r*(b).r - (a).i*(b).i) + (1<<14) ) >> 15;\
|
||||||
|
(m).i = ( ( (a).r*(b).i + (a).i*(b).r) + (1<<14) ) >> 15;\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#else // not FIXED_POINT
|
||||||
|
|
||||||
#define C_ADD(x,a,b) \
|
#define C_ADD(x,a,b) \
|
||||||
do{ (x).r = (a).r+(b).r;\
|
do{ (x).r = (a).r+(b).r;\
|
||||||
(x).i = (a).i+(b).i;}while(0)
|
(x).i = (a).i+(b).i;}while(0)
|
||||||
@ -45,13 +67,19 @@ typedef struct {
|
|||||||
#define C_MUL(m,a,b) \
|
#define C_MUL(m,a,b) \
|
||||||
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||||
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
kiss_fft_cpx cexp(double phase)
|
kiss_fft_cpx cexp(double phase)
|
||||||
{
|
{
|
||||||
kiss_fft_cpx x;
|
kiss_fft_cpx x;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
x.r = (kiss_fft_scalar) ( 32767*cos(phase) );
|
||||||
|
x.i = (kiss_fft_scalar) ( -32767*sin(phase) );
|
||||||
|
#else
|
||||||
x.r = cos(phase);
|
x.r = cos(phase);
|
||||||
x.i = -sin(phase);
|
x.i = -sin(phase);
|
||||||
|
#endif
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +113,8 @@ void fft_work(
|
|||||||
int Norig,
|
int Norig,
|
||||||
int inverse,
|
int inverse,
|
||||||
kiss_fft_cpx * scratch,
|
kiss_fft_cpx * scratch,
|
||||||
kiss_fft_cpx * twiddles
|
kiss_fft_cpx * twiddles,
|
||||||
|
int * factors
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int m,p=0,q,q1,u,k;
|
int m,p=0,q,q1,u,k;
|
||||||
@ -95,58 +124,22 @@ void fft_work(
|
|||||||
*Fout = *f;
|
*Fout = *f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
p=*factors++;
|
||||||
double two_pi_divN;
|
m=*factors++;//m = n/p;
|
||||||
two_pi_divN = 2*pi/n;
|
|
||||||
if (inverse)
|
|
||||||
two_pi_divN *= -1;
|
|
||||||
*/
|
|
||||||
if (n%2 == 0) p=2;
|
|
||||||
else if(n%3 == 0) p=3;
|
|
||||||
else if(n%5 == 0) p=5;
|
|
||||||
else if(n%7 == 0) p=7;
|
|
||||||
else {
|
|
||||||
fprintf(stderr,"%d is not divisible by %d\n",n,p);
|
|
||||||
p=n;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
m = n/p;
|
|
||||||
/* n = stage->n; m = stage->m; p = stage->p; */
|
|
||||||
|
|
||||||
#ifdef LOUD
|
|
||||||
printf("n=%d,p=%d\n",n,p);
|
|
||||||
for (k=0;k<n;++k) {
|
|
||||||
t=f[k*fstride];
|
|
||||||
printf("(%.3f,%.3f) ",t.r,t.i);
|
|
||||||
}
|
|
||||||
printf(" <<< fin \n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (q=0;q<p;++q) {
|
for (q=0;q<p;++q) {
|
||||||
#ifdef LOUD
|
fft_work( Fout + m*q, f+q*fstride, fstride*p, m,Norig,inverse, scratch ,twiddles,factors);
|
||||||
for (k=0;k<m;++k) {
|
|
||||||
t = (f+q*fstride)[fstride*p*k];
|
|
||||||
printf("(%.3f,%.3f) ",t.r,t.i);
|
|
||||||
}
|
|
||||||
printf(" <<< f[fstride*k+q] \n");
|
|
||||||
#endif
|
|
||||||
fft_work( Fout + m*q, f+q*fstride, fstride*p, m,Norig,inverse, scratch ,twiddles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOUD
|
|
||||||
printf("twiddling n=%d,p=%d\n",n,p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for ( u=0; u<m; ++u ) {
|
for ( u=0; u<m; ++u ) {
|
||||||
for ( q1=0 ; q1<p ; ++q1 ) {
|
for ( q1=0 ; q1<p ; ++q1 ) {
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
scratch[q1].r = Fout[ u+q1*m ].r>>1;
|
||||||
|
scratch[q1].i = Fout[ u+q1*m ].i>>1;
|
||||||
|
#else
|
||||||
scratch[q1] = Fout[ u+q1*m ];
|
scratch[q1] = Fout[ u+q1*m ];
|
||||||
#ifdef LOUD
|
#endif
|
||||||
printf("(%.3f,%.3f) ",scratch[q1].r,scratch[q1].i);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef LOUD
|
|
||||||
printf(" <<< scratch \n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for ( q1=0 ; q1<p ; ++q1 ) {
|
for ( q1=0 ; q1<p ; ++q1 ) {
|
||||||
int twidx=0;
|
int twidx=0;
|
||||||
@ -157,21 +150,6 @@ void fft_work(
|
|||||||
if (twidx>=Norig)
|
if (twidx>=Norig)
|
||||||
twidx-=Norig;
|
twidx-=Norig;
|
||||||
t = twiddles[twidx];
|
t = twiddles[twidx];
|
||||||
/*
|
|
||||||
kiss_fft_cpx diff,tref;
|
|
||||||
tref = cexp( two_pi_divN * k * q );
|
|
||||||
diff = csub(t,tref);
|
|
||||||
if (
|
|
||||||
diff.r * diff.r + diff.i*diff.i * 100
|
|
||||||
>
|
|
||||||
tref.r * tref.r + tref.i*tref.i)
|
|
||||||
{
|
|
||||||
printf("twiddling n=%d,p=%d\n",n,p);
|
|
||||||
printf("t=(%.3f,%.3f) ",t.r,t.i);
|
|
||||||
printf("tref=(%.3f,%.3f) ",tref.r,tref.i);
|
|
||||||
printf("diff=(%.3f,%.3f) \n",diff.r,diff.i);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Fout[ k ] = cadd( Fout[ k ] ,
|
Fout[ k ] = cadd( Fout[ k ] ,
|
||||||
cmul( scratch[q] , t ) );
|
cmul( scratch[q] , t ) );
|
||||||
}
|
}
|
||||||
@ -189,6 +167,7 @@ void fft_work(
|
|||||||
* */
|
* */
|
||||||
void * kiss_fft_alloc(int nfft,int inverse_fft)
|
void * kiss_fft_alloc(int nfft,int inverse_fft)
|
||||||
{
|
{
|
||||||
|
int nstages=0;
|
||||||
int i;
|
int i;
|
||||||
kiss_fft_state * st=NULL;
|
kiss_fft_state * st=NULL;
|
||||||
st = ( kiss_fft_state *)malloc( sizeof(kiss_fft_state) );
|
st = ( kiss_fft_state *)malloc( sizeof(kiss_fft_state) );
|
||||||
@ -196,6 +175,10 @@ void * kiss_fft_alloc(int nfft,int inverse_fft)
|
|||||||
st->inverse = inverse_fft;
|
st->inverse = inverse_fft;
|
||||||
|
|
||||||
st->twiddles = (kiss_fft_cpx*)malloc( sizeof(kiss_fft_cpx)*nfft );
|
st->twiddles = (kiss_fft_cpx*)malloc( sizeof(kiss_fft_cpx)*nfft );
|
||||||
|
st->tmpbuf = (kiss_fft_cpx*)malloc( sizeof(kiss_fft_cpx)*nfft );
|
||||||
|
st->scratch = (kiss_fft_cpx*)malloc( sizeof(kiss_fft_cpx)*nfft );
|
||||||
|
|
||||||
|
st->factors = (int*)malloc( sizeof(int)*nfft );
|
||||||
|
|
||||||
for (i=0;i<nfft;++i) {
|
for (i=0;i<nfft;++i) {
|
||||||
double phase = ( 2*pi /nfft ) * i;
|
double phase = ( 2*pi /nfft ) * i;
|
||||||
@ -204,6 +187,22 @@ void * kiss_fft_alloc(int nfft,int inverse_fft)
|
|||||||
st->twiddles[i] = cexp( phase );
|
st->twiddles[i] = cexp( phase );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (nfft>1) {
|
||||||
|
const int primes[] = {2,3,5,7,11,13,17,-1};
|
||||||
|
int p=nfft;
|
||||||
|
i=0;
|
||||||
|
while ( primes[i] != -1 ) {
|
||||||
|
if ( nfft % primes[i] == 0){
|
||||||
|
p = primes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st->factors[2*nstages] = p;
|
||||||
|
nfft /= p;
|
||||||
|
st->factors[2*nstages+1] = nfft;
|
||||||
|
++nstages;
|
||||||
|
}
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,12 +210,11 @@ void kiss_fft(const void * cfg,kiss_fft_cpx *f)
|
|||||||
{
|
{
|
||||||
int i,n;
|
int i,n;
|
||||||
const kiss_fft_state * st = cfg;
|
const kiss_fft_state * st = cfg;
|
||||||
kiss_fft_cpx tmpbuf[1024];
|
|
||||||
kiss_fft_cpx scratch[1024];
|
|
||||||
n = st->nfft;
|
n = st->nfft;
|
||||||
|
|
||||||
for (i=0;i<n;++i)
|
for (i=0;i<n;++i)
|
||||||
tmpbuf[i] = f[i];
|
st->tmpbuf[i] = f[i];
|
||||||
|
|
||||||
fft_work( f, tmpbuf, 1, n,n, st->inverse, scratch ,st->twiddles);
|
fft_work( f, st->tmpbuf, 1, n,n, st->inverse, st->scratch ,st->twiddles,st->factors);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user