From 5a46f15d1b886dc2842d23a34117d5f8385ce0e7 Mon Sep 17 00:00:00 2001 From: Tatu Peltola Date: Sun, 23 Oct 2016 19:27:37 +0300 Subject: [PATCH 1/3] Add fft_fc: FFT for real input signal --- csdr.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fft_fftw.h | 1 + libcsdr.c | 7 +++++ libcsdr.h | 1 + 4 files changed, 100 insertions(+) diff --git a/csdr.c b/csdr.c index 18160d6..1f31c81 100644 --- a/csdr.c +++ b/csdr.c @@ -1314,6 +1314,97 @@ int main(int argc, char *argv[]) TRY_YIELD; } } + + if(!strcmp(argv[1],"fft_fc")) + { + /* For real FFT, the parameter is the number of output complex bins + instead of the actual FFT size. + Thus, the number of input samples used for each FFT is twice the given parameter + and for this reason, out_of_every_n_samples is also doubled + to get correct amount of overlap. + This is not very neat but makes it easier to replace fft_cc by fft_fc + in some applications. */ + if(argc<=3) return badsyntax("need required parameters (fft_out_size, out_of_every_n_samples)"); + int fft_in_size=0, fft_out_size=0; + sscanf(argv[2],"%d",&fft_out_size); + if(log2n(fft_out_size)==-1) return badsyntax("fft_out_size should be power of 2"); + fft_in_size = 2*fft_out_size; + int every_n_samples; + sscanf(argv[3],"%d",&every_n_samples); + every_n_samples *= 2; + int benchmark=0; + int octave=0; + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + if(argc>=6) + { + benchmark|=!strcmp("--benchmark",argv[5]); + octave|=!strcmp("--octave",argv[5]); + } + if(argc>=7) + { + benchmark|=!strcmp("--benchmark",argv[6]); + octave|=!strcmp("--octave",argv[6]); + } + + if(!initialize_buffers()) return -2; + sendbufsize(fft_out_size); + + //make FFT plan + float* input=(float*)fft_malloc(sizeof(float)*fft_in_size); + float* windowed=(float*)fft_malloc(sizeof(float)*fft_in_size); + complexf* output=(complexf*)fft_malloc(sizeof(complexf)*fft_out_size); + if(benchmark) fprintf(stderr,"fft_cc: benchmarking..."); + FFT_PLAN_T* plan=make_fft_r2c(fft_in_size, windowed, output, benchmark); + if(benchmark) fprintf(stderr," done\n"); + //if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size); // TODO + float *windowt; + windowt = precalculate_window(fft_in_size, window); + for(;;) + { + FEOF_CHECK; + if(every_n_samples>fft_in_size) + { + fread(input, sizeof(float), fft_in_size, stdin); + //skipping samples before next FFT (but fseek doesn't work for pipes) + for(int seek_remain=every_n_samples-fft_in_size;seek_remain>0;seek_remain-=the_bufsize) + { + fread(temp_f, sizeof(complexf), MIN_M(the_bufsize,seek_remain), stdin); + } + } + else + { + //overlapped FFT + for(int i=0;i Date: Sun, 23 Oct 2016 20:25:34 +0300 Subject: [PATCH 2/3] Implement shift_addition_fc for downconversion of real signal --- csdr.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ libcsdr_gpl.c | 27 +++++++++++++++++++++++++++ libcsdr_gpl.h | 1 + 3 files changed, 77 insertions(+) diff --git a/csdr.c b/csdr.c index 1f31c81..a87e29e 100644 --- a/csdr.c +++ b/csdr.c @@ -717,6 +717,55 @@ int main(int argc, char *argv[]) return 0; } + if(!strcmp(argv[1],"shift_addition_fc")) + { + bigbufs=1; + + float starting_phase=0; + float rate; + + int fd; + if(fd=init_fifo(argc,argv)) + { + while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000); + } + else + { + if(argc<=2) return badsyntax("need required parameter (rate)"); + sscanf(argv[2],"%g",&rate); + } + + if(!sendbufsize(initialize_buffers())) return -2; + for(;;) + { + shift_addition_data_t data=shift_addition_init(rate); + fprintf(stderr,"shift_addition_fc: reinitialized to %g\n",rate); + int remain, current_size; + float* ibufptr; + float* obufptr; + for(;;) + { + FEOF_CHECK; + if(!FREAD_R) break; + remain=the_bufsize; + ibufptr=input_buffer; + obufptr=output_buffer; + while(remain) + { + current_size=(remain>1024)?1024:remain; + starting_phase=shift_addition_fc(ibufptr, (complexf*)obufptr, current_size, data, starting_phase); + ibufptr+=current_size; + obufptr+=current_size*2; + remain-=current_size; + } + FWRITE_C; + if(read_fifo_ctl(fd,"%g\n",&rate)) break; + TRY_YIELD; + } + } + return 0; + } + if(!strcmp(argv[1],"shift_addition_cc_test")) { if(argc<=2) return badsyntax("need required parameter (rate)"); diff --git a/libcsdr_gpl.c b/libcsdr_gpl.c index b895e00..f9a651e 100644 --- a/libcsdr_gpl.c +++ b/libcsdr_gpl.c @@ -51,6 +51,33 @@ float shift_addition_cc(complexf *input, complexf* output, int input_size, shift return starting_phase; } +float shift_addition_fc(float *input, complexf* output, int input_size, shift_addition_data_t d, float starting_phase) +{ + //The original idea was taken from wdsp: + //http://svn.tapr.org/repos_sdr_hpsdr/trunk/W5WC/PowerSDR_HPSDR_mRX_PS/Source/wdsp/shift.c + + //However, this method introduces noise (from floating point rounding errors), which increases until the end of the buffer. + //fprintf(stderr, "cosd=%g sind=%g\n", d.cosdelta, d.sindelta); + float cosphi=cos(starting_phase); + float sinphi=sin(starting_phase); + float cosphi_last, sinphi_last; + for(int i=0;iPI) starting_phase-=2*PI; //@shift_addition_cc: normalize starting_phase + while(starting_phase<-PI) starting_phase+=2*PI; + return starting_phase; +} + shift_addition_data_t shift_addition_init(float rate) { rate*=2; diff --git a/libcsdr_gpl.h b/libcsdr_gpl.h index a4bfd23..2e3e4da 100644 --- a/libcsdr_gpl.h +++ b/libcsdr_gpl.h @@ -31,6 +31,7 @@ typedef struct shift_addition_data_s } shift_addition_data_t; shift_addition_data_t shift_addition_init(float rate); float shift_addition_cc(complexf *input, complexf* output, int input_size, shift_addition_data_t d, float starting_phase); +float shift_addition_fc(float *input, complexf* output, int input_size, shift_addition_data_t d, float starting_phase); void shift_addition_cc_test(shift_addition_data_t d); float agc_ff(float* input, float* output, int input_size, float reference, float attack_rate, float decay_rate, float max_gain, short hang_time, short attack_wait_time, float gain_filter_alpha, float last_gain); From b6f50cbf06a98dc61d5c28b34f272eb44b906305 Mon Sep 17 00:00:00 2001 From: Tatu Peltola Date: Mon, 31 Oct 2016 19:14:16 +0200 Subject: [PATCH 3/3] Changed every_n_samples in fft_fc to be based on actual input samples --- csdr.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/csdr.c b/csdr.c index a87e29e..c6f8acf 100644 --- a/csdr.c +++ b/csdr.c @@ -1366,13 +1366,11 @@ int main(int argc, char *argv[]) if(!strcmp(argv[1],"fft_fc")) { - /* For real FFT, the parameter is the number of output complex bins + /* + For real FFT, the parameter is the number of output complex bins instead of the actual FFT size. - Thus, the number of input samples used for each FFT is twice the given parameter - and for this reason, out_of_every_n_samples is also doubled - to get correct amount of overlap. - This is not very neat but makes it easier to replace fft_cc by fft_fc - in some applications. */ + Number of input samples used for each FFT is twice the given parameter. + This makes it easier to replace fft_cc by fft_fc in some applications. */ if(argc<=3) return badsyntax("need required parameters (fft_out_size, out_of_every_n_samples)"); int fft_in_size=0, fft_out_size=0; sscanf(argv[2],"%d",&fft_out_size); @@ -1380,7 +1378,6 @@ int main(int argc, char *argv[]) fft_in_size = 2*fft_out_size; int every_n_samples; sscanf(argv[3],"%d",&every_n_samples); - every_n_samples *= 2; int benchmark=0; int octave=0; window_t window = WINDOW_DEFAULT;