diff --git a/Makefile b/Makefile index 84f4aa3..545730e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -all: kiss_fft_s kiss_fft_f kiss_fft_d +all: kiss_fft_s kiss_fft_f kiss_fft_d freqpeak tones kiss_fft_s: kiss_fft.h kiss_fft.c gcc -Wall -O3 -o kiss_fft_s -DFIXED_POINT -DFFT_UTIL kiss_fft.c -lm @@ -9,12 +9,28 @@ kiss_fft_f: kiss_fft.h kiss_fft.c kiss_fft_d: kiss_fft.h kiss_fft.c gcc -Wall -O3 -o kiss_fft_d -Dkiss_fft_scalar=double -DFFT_UTIL kiss_fft.c -lm + +freqpeak: kiss_fft.h kiss_fft.c freqpeak.c + gcc -Wall -O3 -o freqpeak freqpeak.c kiss_fft.c -lm +testsig: testsig.c + gcc -Wall -O3 -o testsig testsig.c -lm + +tones: tones.c + gcc -Wall -O3 -o tones tones.c -lm + clean: - rm -f kiss_fft_s kiss_fft_f kiss_fft_d *~ fftin.dat fftout.dat + rm -f kiss_fft_s kiss_fft_f kiss_fft_d *~ fftin.dat fftout.dat \ + freqpeak testsig tones -test: clean all +test: all ./test.oct +speedtest: /dev/shm/junk kiss_fft_f + time ./kiss_fft_f < /dev/shm/junk > /dev/null + +/dev/shm/junk: + dd if=/dev/urandom bs=8192 count=1000 of=/dev/shm/junk + tarball: clean tar -czf kiss_fft.tar.gz . diff --git a/freqpeak.c b/freqpeak.c new file mode 100644 index 0000000..df3fcf0 --- /dev/null +++ b/freqpeak.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include "kiss_fft.h" + +#define NFFT 1024 +int main(int argc, char ** argv) +{ + int k; + void * st; + float fs=44100; + + short sampsin[2*NFFT]; + float lmag2[NFFT/2]; + float rmag2[NFFT/2]; + int peakr=0,peakl=0; + int removedc=1; + + kiss_fft_cpx cbuf[NFFT]; + int nbufs=0; + + st = kiss_fft_alloc(NFFT,0); + + memset( lmag2 , 0 , sizeof(lmag2) ); + memset( rmag2 , 0 , sizeof(rmag2) ); + + while ( fread( sampsin , sizeof(short) * 2*NFFT, 1 , stdin ) == 1 ) { + //perform two ffts in parallel by packing the channels into the real and imaginary + // + + for (k=0;k> 1 );\ (x).i = ( ( (a).i+(b).i +1) >> 1 ); }while(0) # define C_SUB(x,a,b) \ do{ (x).r = ( ( (a).r-(b).r +1) >> 1 );\ (x).i = ( ( (a).i-(b).i +1) >> 1 ); }while(0) -# 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 // floating point + /* 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) + (TWIDDLE_RANGE>>1) ) >> FIXED_POINT_FRAC_BITS;\ + (m).i = ( ( (a).r*(b).i + (a).i*(b).r) + (TWIDDLE_RANGE>>1) ) >> FIXED_POINT_FRAC_BITS;\ + }while(0) +#else // not FIXED_POINT #define C_ADD(x,a,b) \ do{ (x).r = (a).r+(b).r;\ @@ -55,8 +65,8 @@ typedef struct { do{ (x).r = (a).r-(b).r;\ (x).i = (a).i-(b).i;}while(0) #define C_MUL(m,a,b) \ - do{ (m).r = (a).r*(b.r) - (a).i*(b).i;\ - (m).i = (a).r*(b.i) + (a).i*(b).r; }while(0) + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) #endif @@ -69,12 +79,15 @@ void make_twiddles(kiss_fft_cpx * twiddle,int nfft,int inverse_fft) int n; for (n=0;n< (nfft>>1);++n) { #ifdef FIXED_POINT + // TODO: find another way to calculate these without so much floating point math twiddle[n].r = (kiss_fft_scalar)(TWIDDLE_RANGE*cos(2*pi*n/nfft)+.5); twiddle[n].i = -(kiss_fft_scalar)(TWIDDLE_RANGE*sin(2*pi*n/nfft)+.5); #else twiddle[n].r = cos(2*pi*n/nfft); twiddle[n].i = -sin(2*pi*n/nfft); #endif + + // inverse fft uses complex conjugate twiddle factors if (inverse_fft) twiddle[n].i *= -1; } @@ -126,6 +139,8 @@ void undo_bit_rev( kiss_fft_cpx * f, const int * swap_indices,int nswap) } } + +#define OPT1 // the heart of the fft static void fft_work(int N,kiss_fft_cpx *f,const kiss_fft_cpx * twid,int twid_step) @@ -134,17 +149,36 @@ void fft_work(int N,kiss_fft_cpx *f,const kiss_fft_cpx * twid,int twid_step) { // declare automatic variables in here to reduce stack usage int n; kiss_fft_cpx csum,cdiff; - - for (n=0;n1 && 0==strcmp("-i",argv[1])) { - inverse_fft = 1; + + // parse args + while (argc>1 && argv[1][0]=='-'){ + if (0==strcmp("-i",argv[1])) { + inverse_fft = 1; + }else if(0==strcmp("-s",argv[1])) { + scale = 1; + } --argc;++argv; } - if (argc>1) { nfft = atoi(argv[1]); } + // do we need to scale? + if (scale) { +#ifdef FIXED_POINT + if ( ! inverse_fft ) { + scaling.r = nfft; + scaling.i = nfft; + fprintf(stderr,"scaling by %d\n",scaling.r); + } +#else + if (inverse_fft ){ + scaling.r = 1.0/nfft; + scaling.i = 1.0/nfft; + fprintf(stderr,"scaling by %e\n",scaling.r); + } +#endif + else + scale = 0; // no need + } + buf=(kiss_fft_cpx*)malloc( sizeof(kiss_fft_cpx) * nfft ); st = kiss_fft_alloc( nfft ,inverse_fft ); - while ( fread( buf , sizeof(kiss_fft_cpx) , nfft , stdin ) > 0 ) { kiss_fft( st , buf ); + if (scale) { + int k; + for (k=0;k fftout.dat',prog,nfft) + if use_inverse_fft, + cmd = sprintf('%s -s -i %d < %s > %s',prog,nfft,infile,outfile) + comp = ifft(input); + else + cmd = sprintf('%s -s %d < %s > %s',prog,nfft,infile,outfile) + comp = fft(input); + endif system(cmd); # read the output - f = fopen("fftout.dat","r", "native"); + f = fopen(outfile,"r", "native"); from_read = fread(f,Inf,prec)'; - output = (from_read(1:2:nfft*2) + j*from_read(2:2:nfft*2)) ; - - comp = fft(input)/scale; - if test_case == 1, - comp = floor( real(comp) +.5) + j*floor( imag(comp) +.5); - endif + output = (from_read(1:2:nfft*2) + j*from_read(2:2:nfft*2)); + diff = output - comp; + noise_pow = sum( conj(diff).*diff ); + sig_pow = sum( conj(comp).*comp ); + snr = 10*log10( sig_pow / noise_pow ) + avg_scale = mean( abs(output) ./ abs(comp) ) + var_scale = var( abs(output) ./ abs(comp) ) if showdiff, x=linspace(0,2*pi,nfft); figure(1); @@ -53,12 +60,5 @@ for test_case =1:3 figure(3); plot( x, abs(output-comp) ); pause - else - diff = output - comp; - noise_pow = sum( conj(diff).*diff ); - sig_pow = sum( conj(comp).*comp ); - snr = 10*log10( sig_pow / noise_pow ) - - avg_scale = mean( abs(output) ./ abs(comp) ) endif endfor diff --git a/testsig.c b/testsig.c new file mode 100644 index 0000000..7b2c007 --- /dev/null +++ b/testsig.c @@ -0,0 +1,32 @@ +#include +#include +#include + +int usage() +{ + fprintf(stderr,"usage:testsig nsamps\n"); + exit(1); + return 1; +} + +double randphase() +{ + return (double)rand()*2*3.14159/RAND_MAX; +} + +int main(int argc, char ** argv) +{ + float samps[2]; + int nsamps; + + if (argc != 2) + return usage(); + nsamps = atoi( argv[1] ); + + while (nsamps-- > 0) { + samps[0]=sin( randphase() ); + samps[1]=sin( randphase() ); + fwrite(samps,sizeof(samps),1,stdout); + } + return 0; +} diff --git a/tones.c b/tones.c new file mode 100644 index 0000000..43f9f89 --- /dev/null +++ b/tones.c @@ -0,0 +1,35 @@ + +#include +#include +#include +#include +#include +#include +#include "kiss_fft.h" + +#define PI 3.14159 + +int main(int argc, char ** argv) +{ + int k; + float fs=44100; + + float fr=1,fl=300; + + float th[2] = {0,0}; + float thinc[2] = {2*PI*fr/fs,2*PI*fl/fs }; + + while (1){ + for (k=0;k<2;++k){ + short s; + th[k] += thinc[k]; + if (th[k] > 2*PI){ + th[k] -= 2*PI; + } + s=(short)32767*cos( th[k] ); + fwrite(&s,sizeof(s),1,stdout); + } + } + + return 0; +}