diff --git a/README.md b/README.md index 9215045..c27117a 100644 --- a/README.md +++ b/README.md @@ -315,7 +315,12 @@ Other parameters were explained above at `firdes_lowpass_f`. fir_decimate_cc [transition_bw [window]] It is a decimator that keeps one sample out of `decimation_factor` samples. -To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency × decimation_factor`. +To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency × decimation_factor` from the input signal. + + fir_interpolate_cc [transition_bw [window]] + +It is an interpolator that generates `interpolation_factor` number of output samples from one input sample. +To avoid aliasing, it runs a filter on the signal and removes spectral components above `0.5 × nyquist_frequency / interpolation_factor` from the output signal. `transition_bw` and `window` are the parameters of the filter. diff --git a/csdr.c b/csdr.c index cc8a087..38bc915 100755 --- a/csdr.c +++ b/csdr.c @@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "fastddc.h" +#include char usage[]= "csdr - a simple commandline tool for Software Defined Radio receiver DSP.\n\n" @@ -92,6 +93,7 @@ char usage[]= " amdemod_cf\n" " amdemod_estimator_cf\n" " fir_decimate_cc [transition_bw [window]]\n" +" fir_interpolate_cc [transition_bw [window]]\n" " firdes_lowpass_f [window [--octave]]\n" " firdes_bandpass_c [window [--octave]]\n" " agc_ff [hang_time [reference [attack_rate [decay_rate [max_gain [attack_wait [filter_alpha]]]]]]]\n" @@ -1104,6 +1106,66 @@ int main(int argc, char *argv[]) //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); } } + + if(!strcmp(argv[1],"fir_interpolate_cc")) + { + bigbufs=1; + + if(argc<=2) return badsyntax("need required parameter (interpolation factor)"); + + int factor; + sscanf(argv[2],"%d",&factor); + assert(factor >= 1); + + float transition_bw = 0.05; + if(argc>=4) sscanf(argv[3],"%g",&transition_bw); + assert(transition_bw >= 0 && transition_bw < 1.); + + window_t window = WINDOW_DEFAULT; + if(argc>=5) + { + window=firdes_get_window_from_string(argv[4]); + } + else fprintf(stderr,"fir_interpolate_cc: window = %s\n",firdes_get_string_from_window(window)); + + int taps_length=firdes_filter_len(transition_bw); + fprintf(stderr,"fir_interpolate_cc: taps_length = %d\n",taps_length); + assert(taps_length > 0); + + while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low + //fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize*factor); + assert(the_bufsize > 0); + + float *taps; + taps=(float*)malloc(taps_length*sizeof(float)); + assert(taps); + + firdes_lowpass_f(taps,taps_length,0.5/(float)factor,window); + + int input_skip=0; + int output_size=0; + float* interp_output_buffer = (float*)malloc(sizeof(float)*2*the_bufsize*factor); + for(;;) + { + FEOF_CHECK; + output_size=fir_interpolate_cc((complexf*)input_buffer, (complexf*)interp_output_buffer, the_bufsize, factor, taps, taps_length); + //fprintf(stderr, "os %d\n",output_size); + fwrite(interp_output_buffer, sizeof(complexf), output_size, stdout); + fflush(stdout); + TRY_YIELD; + input_skip=output_size/factor; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+input_skip,(the_bufsize-input_skip)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-input_skip), sizeof(complexf), input_skip, stdin); + //fprintf(stderr,"iskip=%d output_size=%d start=%x target=%x skipcount=%x \n",input_skip,output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-input_skip),(BIG_BUFSIZE-input_skip)); + } + } + + + + /*if(!strcmp(argv[1],"ejw_test")) { printf("ejqd=["); diff --git a/grc_tests/test_fir_interpolate_cc.grc b/grc_tests/test_fir_interpolate_cc.grc new file mode 100644 index 0000000..65eb887 --- /dev/null +++ b/grc_tests/test_fir_interpolate_cc.grc @@ -0,0 +1,1212 @@ + + + + Tue Nov 25 18:16:05 2014 + + options + + author + + + + window_size + 1280, 1024 + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (10, 10) + + + _rotation + 0 + + + generate_options + wx_gui + + + id + top_block + + + max_nouts + 0 + + + realtime_scheduling + + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable_slider + + comment + + + + converver + float_converter + + + value + 4e3 + + + _enabled + True + + + _coordinate + (8, 331) + + + _rotation + 0 + + + grid_pos + 2,1,1,1 + + + id + input_freq + + + label + + + + max + samp_rate/2 + + + min + -samp_rate/2 + + + notebook + + + + num_steps + 100 + + + style + wx.SL_HORIZONTAL + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (432, 11) + + + _rotation + 0 + + + id + interpolation + + + value + 2 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (176, 11) + + + _rotation + 0 + + + id + samp_rate + + + value + 240000 + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (328, 11) + + + _rotation + 0 + + + id + samp_rate_2 + + + value + samp_rate*interpolation + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (536, 11) + + + _rotation + 0 + + + id + transition_bw + + + value + 0.01 + + + + analog_sig_source_x + + amp + 1 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + freq + input_freq + + + _coordinate + (8, 83) + + + _rotation + 0 + + + id + analog_sig_source_x_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + offset + 0 + + + type + complex + + + samp_rate + samp_rate + + + waveform + analog.GR_COS_WAVE + + + + blocks_throttle + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (168, 115) + + + _rotation + 0 + + + id + blocks_throttle_0 + + + ignoretag + True + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samples_per_second + samp_rate + + + type + complex + + + vlen + 1 + + + + ha5kfu_execproc_xx + + alias + + + + commandline + "csdr fir_interpolate_cc "+str(interpolation)+" "+str(transition_bw) + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (352, 115) + + + _rotation + 0 + + + id + ha5kfu_execproc_xx_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + type + cc + + + + interp_fir_filter_xxx + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (368, 643) + + + _rotation + 0 + + + id + interp_fir_filter_xxx_0 + + + interp + interpolation + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + samp_delay + 0 + + + taps + firdes.low_pass(1,1,1./(2*interpolation), transition_bw) + + + type + ccc + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 683) + + + _rotation + 0 + + + grid_pos + 1,2,1,1 + + + id + nb0 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 579) + + + _rotation + 0 + + + grid_pos + 1,1,1,1 + + + id + nb1 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + notebook + + alias + + + + comment + + + + _enabled + True + + + _coordinate + (16, 475) + + + _rotation + 0 + + + grid_pos + 2,2,1,1 + + + id + nb2 + + + labels + ['scope','fft'] + + + notebook + + + + style + wx.NB_TOP + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (640, 235) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0 + + + notebook + nb0,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate_2 + + + title + Resampled signal (csdr) + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (640, 579) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_0_0 + + + notebook + nb2,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate_2 + + + title + Resampled signal (GNU Radio) + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_fftsink2 + + avg_alpha + 0 + + + average + False + + + baseband_freq + 0 + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + fft_size + 1024 + + + freqvar + None + + + _coordinate + (360, 355) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_fftsink2_1 + + + notebook + nb1,1 + + + peak_hold + False + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_rate + 15 + + + samp_rate + samp_rate + + + title + Original signal + + + type + complex + + + win_size + + + + win + None + + + y_divs + 10 + + + y_per_div + 10 + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (640, 115) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0 + + + notebook + nb0,0 + + + num_inputs + 1 + + + samp_rate + samp_rate_2 + + + t_scale + 0 + + + title + Resampled signal (csdr) + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (360, 235) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_0 + + + notebook + nb1,0 + + + num_inputs + 1 + + + samp_rate + samp_rate + + + t_scale + 0 + + + title + Original signal + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + wxgui_scopesink2 + + ac_couple + False + + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (640, 459) + + + _rotation + 0 + + + grid_pos + + + + id + wxgui_scopesink2_0_1 + + + notebook + nb2,0 + + + num_inputs + 1 + + + samp_rate + samp_rate_2 + + + t_scale + 0 + + + title + Resampled signal (GNU Radio) + + + trig_mode + wxgui.TRIG_MODE_AUTO + + + type + complex + + + v_offset + 0 + + + v_scale + 0 + + + win_size + + + + xy_mode + False + + + y_axis_label + Counts + + + + analog_sig_source_x_0 + blocks_throttle_0 + 0 + 0 + + + blocks_throttle_0 + ha5kfu_execproc_xx_0 + 0 + 0 + + + blocks_throttle_0 + interp_fir_filter_xxx_0 + 0 + 0 + + + blocks_throttle_0 + wxgui_fftsink2_1 + 0 + 0 + + + blocks_throttle_0 + wxgui_scopesink2_0_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_fftsink2_0 + 0 + 0 + + + ha5kfu_execproc_xx_0 + wxgui_scopesink2_0 + 0 + 0 + + + interp_fir_filter_xxx_0 + wxgui_fftsink2_0_0 + 0 + 0 + + + interp_fir_filter_xxx_0 + wxgui_scopesink2_0_1 + 0 + 0 + + diff --git a/libcsdr.c b/libcsdr.c index e9fa2c3..5af8826 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -580,6 +580,34 @@ int fir_decimate_cc(complexf *input, complexf *output, int input_size, int decim } */ +int fir_interpolate_cc(complexf *input, complexf *output, int input_size, int interpolation, float *taps, int taps_length) +{ + //i: input index + //oi: output index + //ti: tap index + //ti: secondary index (inside filter function) + //ip: interpolation phase (0 <= ip < interpolation) + int oi=0; + for(int i=0; i input_size*interpolation) break; + for(int ip=0; ip