From 47b9d7918ff888643c2ec46dd24f2150b945d963 Mon Sep 17 00:00:00 2001 From: Tom Date: Fri, 18 Dec 2009 00:09:17 -0500 Subject: New way to handle arbitrary resampler. Now featuring lower noise! --- .../src/lib/filter/gr_pfb_arb_resampler_ccf.cc | 78 +++++++++++++--------- .../src/lib/filter/gr_pfb_arb_resampler_ccf.h | 12 +++- .../src/lib/filter/gr_pfb_arb_resampler_ccf.i | 2 +- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc index d00ba6739..d4b14c594 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc @@ -59,24 +59,26 @@ gr_pfb_arb_resampler_ccf::gr_pfb_arb_resampler_ccf (float rate, d_dec_rate = (unsigned int)floor(d_int_rate/rate); d_flt_rate = (d_int_rate/rate) - d_dec_rate; - // The accumulator keeps track of overflow to increment the stride correctly. - d_acc = 0; - // Store the last filter between calls to work d_last_filter = 0; d_start_index = 0; d_filters = std::vector(d_int_rate); + d_diff_filters = std::vector(d_int_rate); // Create an FIR filter for each channel and zero out the taps std::vector vtaps(0, d_int_rate); - for(unsigned int i = 0; i < d_int_rate; i++) { + for(int i = 0; i < d_int_rate; i++) { d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); + d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); } // Now, actually set the filters' taps - set_taps(taps); + std::vector dtaps; + create_diff_taps(taps, dtaps); + set_taps(taps, d_taps, d_filters); + set_taps(dtaps, d_dtaps, d_diff_filters); } gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf () @@ -87,20 +89,22 @@ gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf () } void -gr_pfb_arb_resampler_ccf::set_taps (const std::vector &taps) +gr_pfb_arb_resampler_ccf::set_taps (const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter) { - unsigned int i,j; + int i,j; - unsigned int ntaps = taps.size(); + unsigned int ntaps = newtaps.size(); d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate); // Create d_numchan vectors to store each channel's taps - d_taps.resize(d_int_rate); - + ourtaps.resize(d_int_rate); + // Make a vector of the taps plus fill it out with 0's to fill // each polyphase filter with exactly d_taps_per_filter std::vector tmp_taps; - tmp_taps = taps; + tmp_taps = newtaps; while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) { tmp_taps.push_back(0.0); } @@ -108,21 +112,44 @@ gr_pfb_arb_resampler_ccf::set_taps (const std::vector &taps) // Partition the filter for(i = 0; i < d_int_rate; i++) { // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out - d_taps[i] = std::vector(d_taps_per_filter, 0); + ourtaps[d_int_rate-1-i] = std::vector(d_taps_per_filter, 0); for(j = 0; j < d_taps_per_filter; j++) { - d_taps[i][j] = tmp_taps[i + j*d_int_rate]; // add taps to channels in reverse order + ourtaps[d_int_rate - 1 - i][j] = tmp_taps[i + j*d_int_rate]; } // Build a filter for each channel and add it's taps to it - d_filters[i]->set_taps(d_taps[i]); + ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]); } // Set the history to ensure enough input items for each filter - set_history (d_taps_per_filter); + set_history (d_taps_per_filter + 1); d_updated = true; } +void +gr_pfb_arb_resampler_ccf::create_diff_taps(const std::vector &newtaps, + std::vector &difftaps) +{ + float maxtap = 1e-20; + difftaps.clear(); + difftaps.push_back(0); //newtaps[0]); + for(unsigned int i = 1; i < newtaps.size()-1; i++) { + float tap = newtaps[i+1] - newtaps[i-1]; + difftaps.push_back(tap); + if(tap > maxtap) { + maxtap = tap; + } + } + difftaps.push_back(0);//-newtaps[newtaps.size()-1]); + + // Scale the differential taps; helps scale error term to better update state + // FIXME: should this be scaled this way or use the same gain as the taps? + for(unsigned int i = 0; i < difftaps.size(); i++) { + difftaps[i] /= maxtap; + } +} + void gr_pfb_arb_resampler_ccf::print_taps() { @@ -163,27 +190,12 @@ gr_pfb_arb_resampler_ccf::general_work (int noutput_items, while((j < d_int_rate) && (i < noutput_items)) { // Take the current filter output o0 = d_filters[j]->filter(&in[count]); + o1 = d_diff_filters[j]->filter(&in[count]); - // Take the next filter output; wrap around to 0 if necessary - if(j+1 == d_int_rate) - // Use the sample of the next input item through the first filter - o1 = d_filters[0]->filter(&in[count+1]); - else { - // Use the sample from the current input item through the nex filter - o1 = d_filters[j+1]->filter(&in[count]); - } - - //out[i] = o0; // nearest-neighbor approach - out[i] = o0 + (o1 - o0)*d_acc; // linearly interpolate between samples + out[i] = o0 + o1*d_flt_rate; // linearly interpolate between samples i++; - // Accumulate the position in the stream for the interpolated point. - // If it goes above 1, roll around to zero and increment the stride - // length this time by the decimation rate plus 1 for the increment - // due to the acculated position. - d_acc += d_flt_rate; - j += d_dec_rate + (int)floor(d_acc); - d_acc = fmodf(d_acc, 1.0); + j += d_dec_rate; } if(i < noutput_items) { // keep state for next entry float ss = (int)(j / d_int_rate); // number of items to skip ahead by diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h index bc5b91a5e..531e9726f 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h @@ -112,11 +112,12 @@ class gr_pfb_arb_resampler_ccf : public gr_block unsigned int filter_size); std::vector d_filters; + std::vector d_diff_filters; std::vector< std::vector > d_taps; + std::vector< std::vector > d_dtaps; unsigned int d_int_rate; // the number of filters (interpolation rate) unsigned int d_dec_rate; // the stride through the filters (decimation rate) float d_flt_rate; // residual rate for the linear interpolation - float d_acc; unsigned int d_last_filter; int d_start_index; unsigned int d_taps_per_filter; @@ -134,16 +135,21 @@ class gr_pfb_arb_resampler_ccf : public gr_block gr_pfb_arb_resampler_ccf (float rate, const std::vector &taps, unsigned int filter_size); + + void create_diff_taps(const std::vector &newtaps, + std::vector &difftaps); public: ~gr_pfb_arb_resampler_ccf (); - + /*! * Resets the filterbank's filter taps with the new prototype filter * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps * should be generated at the interpolated sampling rate. */ - void set_taps (const std::vector &taps); + void set_taps (const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter); /*! * Print all of the filterbank taps to screen. diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i index e365e0314..4f07af861 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i @@ -36,6 +36,6 @@ class gr_pfb_arb_resampler_ccf : public gr_block public: ~gr_pfb_arb_resampler_ccf (); - void set_taps (const std::vector &taps); + //void set_taps (const std::vector &taps); void print_taps(); }; -- cgit