From dd4cc588d7a34f82a63c6b23ca7a1fab736bfc10 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 20 Feb 2012 10:12:57 -0500 Subject: core: wip on pfb synthesis. It works, but is a bit hacked together. Need to determine the best way to handle the two filter cases, with and without oversampling. --- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 98 ++++++++++++++++------ .../lib/filter/gr_pfb_synthesis_filterbank_ccf.h | 3 +- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.i | 1 + 3 files changed, 74 insertions(+), 28 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index 9fad1bd0d..25a5f500e 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -44,21 +44,24 @@ gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf gr_make_io_signature (1, numchans, sizeof(gr_complex)), gr_make_io_signature (1, 1, sizeof(gr_complex)), numchans), - d_updated (false), d_numchans(numchans) + d_updated (false), d_numchans(numchans), d_state(0) { - d_filters = std::vector(d_numchans); + d_filters = std::vector(2*d_numchans); // Create an FIR filter for each channel and zero out the taps - std::vector vtaps(0, d_numchans); - for(unsigned int i = 0; i < d_numchans; i++) { + std::vector vtaps(0, 2*d_numchans); + for(unsigned int i = 0; i < 2*d_numchans; i++) { d_filters[i] = new gri_fir_filter_with_buffer_ccf(vtaps); } // Now, actually set the filters' taps - set_taps(taps); + set_taps2(taps); // Create the IFFT to handle the input channel rotations - d_fft = new gri_fft_complex (d_numchans, true); + d_fft = new gri_fft_complex (2*d_numchans, false); + memset(d_fft->get_inbuf(), 0, 2*d_numchans*sizeof(gr_complex)); + + set_output_multiple(d_numchans); } gr_pfb_synthesis_filterbank_ccf::~gr_pfb_synthesis_filterbank_ccf () @@ -105,11 +108,63 @@ gr_pfb_synthesis_filterbank_ccf::set_taps (const std::vector &taps) d_updated = true; } +void +gr_pfb_synthesis_filterbank_ccf::set_taps2 (const std::vector &taps) +{ + unsigned int i,j; + int state = 0; + + unsigned int ntaps = taps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans); + + // Create d_numchan vectors to store each channel's taps + d_taps.resize(2*d_numchans); + + // 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; + while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_numchans; 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); + d_taps[d_numchans+i] = std::vector(d_taps_per_filter, 0); + state = 0; + for(j = 0; j < d_taps_per_filter; j++) { + // add taps to channels in reverse order + // Zero out every other tap + if(state == 0) { + d_taps[i][j] = tmp_taps[i + j*d_numchans]; + d_taps[d_numchans + i][j] = 0; + state = 1; + } + else { + d_taps[i][j] = 0; + d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans]; + state = 0; + } + } + + // Build a filter for each channel and add it's taps to it + d_filters[i]->set_taps(d_taps[i]); + d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]); + } + + // Set the history to ensure enough input items for each filter + set_history (d_taps_per_filter+1); + + d_updated = true; +} + void gr_pfb_synthesis_filterbank_ccf::print_taps() { unsigned int i, j; - for(i = 0; i < d_numchans; i++) { + for(i = 0; i < 2*d_numchans; i++) { printf("filter[%d]: [", i); for(j = 0; j < d_taps_per_filter; j++) { printf(" %.4e", d_taps[i][j]); @@ -126,9 +181,6 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, { gr_complex *in = (gr_complex*) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; - int numsigs = input_items.size(); - int ndiff = d_numchans - numsigs; - unsigned int nhalf = (unsigned int)ceil((float)numsigs/2.0f); if (d_updated) { d_updated = false; @@ -137,30 +189,22 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, unsigned int n, i; for(n = 0; n < noutput_items/d_numchans; n++) { - // fill up the populated channels based on the - // number of real input streams - for(i = 0; i < nhalf; i++) { + for(i = 0; i < d_numchans; i++) { in = (gr_complex*)input_items[i]; - d_fft->get_inbuf()[i] = (in+i)[n]; + d_fft->get_inbuf()[i] = in[n]; } - - // Make the ndiff channels around N/2 0 - for(; i < nhalf+ndiff; i++) { - d_fft->get_inbuf()[i] = gr_complex(0,0); - } - - // Finish off channels with data - for(; i < d_numchans; i++) { - in = (gr_complex*)input_items[i-ndiff]; - d_fft->get_inbuf()[i] = (in+i)[n]; - } - + // spin through IFFT d_fft->execute(); + // Output is sum of two filters, but the input buffer to the filters must be circularly + // shifted by numchans every time through, done by using d_state to determine which IFFT + // buffer position to pull from. for(i = 0; i < d_numchans; i++) { - out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(d_fft->get_outbuf()[i]); + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); + out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); } + d_state ^= 1; out += d_numchans; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h index 1f772b1dd..06e5462c7 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -65,7 +65,7 @@ class GR_CORE_API gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator gri_fft_complex *d_fft; std::vector< gri_fir_filter_with_buffer_ccf*> d_filters; std::vector< std::vector > d_taps; - + int d_state; /*! * Build the polyphase synthesis filterbank. @@ -86,6 +86,7 @@ public: populate the filterbank. */ void set_taps (const std::vector &taps); + void set_taps2(const std::vector &taps); /*! * Print all of the filterbank taps to screen. diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i index 02a9f0255..0a75269cb 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i @@ -35,4 +35,5 @@ class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator ~gr_pfb_synthesis_filterbank_ccf (); void set_taps (const std::vector &taps); + void print_taps(); }; -- cgit From d15bed21e08f97b0ac510b49124c9231289820c2 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 28 Feb 2012 12:36:00 -0500 Subject: core: pfb synth: can now set channel map and to use 1 or 2 sps on output. The channel map allows the user to set the streams anywhere in the channel output. --- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 131 ++++++++++++++++----- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.h | 56 ++++++++- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.i | 9 +- 3 files changed, 159 insertions(+), 37 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index 25a5f500e..f999a2b92 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -31,48 +31,66 @@ #include gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf - (unsigned int numchans, const std::vector &taps) + (unsigned int numchans, const std::vector &taps, bool twox) { return gr_pfb_synthesis_filterbank_ccf_sptr - (new gr_pfb_synthesis_filterbank_ccf (numchans, taps)); + (new gr_pfb_synthesis_filterbank_ccf (numchans, taps, twox)); } gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf - (unsigned int numchans, const std::vector &taps) + (unsigned int numchans, const std::vector &taps, bool twox) : gr_sync_interpolator ("pfb_synthesis_filterbank_ccf", gr_make_io_signature (1, numchans, sizeof(gr_complex)), gr_make_io_signature (1, 1, sizeof(gr_complex)), numchans), d_updated (false), d_numchans(numchans), d_state(0) { - d_filters = std::vector(2*d_numchans); + // set up 2x multiplier; if twox==True, set to 2, otherwise to 1 + d_twox = (twox ? 2 : 1); + if(d_numchans % d_twox != 0) { + throw std::invalid_argument("gr_pfb_synthesis_filterbank_ccf: number of channels must be even for 2x oversampling.\n"); + } + + d_filters = std::vector(d_twox*d_numchans); + d_channel_map.resize(d_twox*d_numchans); // Create an FIR filter for each channel and zero out the taps - std::vector vtaps(0, 2*d_numchans); - for(unsigned int i = 0; i < 2*d_numchans; i++) { + std::vector vtaps(0, d_twox*d_numchans); + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { d_filters[i] = new gri_fir_filter_with_buffer_ccf(vtaps); + d_channel_map[i] = i; } // Now, actually set the filters' taps - set_taps2(taps); + set_taps(taps); // Create the IFFT to handle the input channel rotations - d_fft = new gri_fft_complex (2*d_numchans, false); - memset(d_fft->get_inbuf(), 0, 2*d_numchans*sizeof(gr_complex)); + d_fft = new gri_fft_complex (d_twox*d_numchans, false); + memset(d_fft->get_inbuf(), 0, d_twox*d_numchans*sizeof(gr_complex)); set_output_multiple(d_numchans); } gr_pfb_synthesis_filterbank_ccf::~gr_pfb_synthesis_filterbank_ccf () { - for(unsigned int i = 0; i < d_numchans; i++) { + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { delete d_filters[i]; } } void -gr_pfb_synthesis_filterbank_ccf::set_taps (const std::vector &taps) +gr_pfb_synthesis_filterbank_ccf::set_taps(const std::vector &taps) +{ + gruel::scoped_lock guard(d_mutex); + if(d_twox == 1) + set_taps1(taps); + else + set_taps2(taps); +} + +void +gr_pfb_synthesis_filterbank_ccf::set_taps1(const std::vector &taps) { unsigned int i,j; @@ -118,7 +136,7 @@ gr_pfb_synthesis_filterbank_ccf::set_taps2 (const std::vector &taps) d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans); // Create d_numchan vectors to store each channel's taps - d_taps.resize(2*d_numchans); + d_taps.resize(d_twox*d_numchans); // Make a vector of the taps plus fill it out with 0's to fill // each polyphase filter with exactly d_taps_per_filter @@ -164,7 +182,7 @@ void gr_pfb_synthesis_filterbank_ccf::print_taps() { unsigned int i, j; - for(i = 0; i < 2*d_numchans; i++) { + for(i = 0; i < d_twox*d_numchans; i++) { printf("filter[%d]: [", i); for(j = 0; j < d_taps_per_filter; j++) { printf(" %.4e", d_taps[i][j]); @@ -174,11 +192,41 @@ gr_pfb_synthesis_filterbank_ccf::print_taps() } +std::vector< std::vector > +gr_pfb_synthesis_filterbank_ccf::taps() const +{ + return d_taps; +} + +void +gr_pfb_synthesis_filterbank_ccf::set_channel_map(const std::vector &map) +{ + gruel::scoped_lock guard(d_mutex); + + unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); + unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); + if((max >= d_twox*d_numchans) || (min < 0)) { + throw std::invalid_argument("gr_pfb_synthesis_filterbank_ccf::set_channel_map: map range out of bounds.\n"); + } + d_channel_map = map; + + // Zero out fft buffer so that unused channels are always 0 + memset(d_fft->get_inbuf(), 0,d_twox*d_numchans*sizeof(gr_complex)); +} + +std::vector +gr_pfb_synthesis_filterbank_ccf::channel_map() const +{ + return d_channel_map; +} + int gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gruel::scoped_lock guard(d_mutex); + gr_complex *in = (gr_complex*) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; @@ -188,25 +236,48 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, } unsigned int n, i; - for(n = 0; n < noutput_items/d_numchans; n++) { - for(i = 0; i < d_numchans; i++) { - in = (gr_complex*)input_items[i]; - d_fft->get_inbuf()[i] = in[n]; + size_t ninputs = input_items.size(); + + // Algoritm for critically sampled channels + if(d_twox == 1) { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[i]); + } + out += d_numchans; } - - // spin through IFFT - d_fft->execute(); - - // Output is sum of two filters, but the input buffer to the filters must be circularly - // shifted by numchans every time through, done by using d_state to determine which IFFT - // buffer position to pull from. - for(i = 0; i < d_numchans; i++) { - out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); - out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + } + + // Algorithm for oversampling by 2x + else { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + // Output is sum of two filters, but the input buffer to the filters must be circularly + // shifted by numchans every time through, done by using d_state to determine which IFFT + // buffer position to pull from. + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); + out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + } + d_state ^= 1; + + out += d_numchans; } - d_state ^= 1; - - out += d_numchans; } return noutput_items; diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h index 06e5462c7..d7f9d26c7 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -27,11 +27,12 @@ #include #include #include +#include class gr_pfb_synthesis_filterbank_ccf; typedef boost::shared_ptr gr_pfb_synthesis_filterbank_ccf_sptr; GR_CORE_API gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf - (unsigned int numchans, const std::vector &taps); + (unsigned int numchans, const std::vector &taps, bool twox=false); class gri_fft_complex; @@ -55,9 +56,10 @@ class GR_CORE_API gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator channels M * \param taps (vector/list of floats) The prototype filter to populate the filterbank. + * \param twox (bool) use 2x oversampling or not (default is no) */ friend GR_CORE_API gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf - (unsigned int numchans, const std::vector &taps); + (unsigned int numchans, const std::vector &taps, bool twox); bool d_updated; unsigned int d_numchans; @@ -65,7 +67,20 @@ class GR_CORE_API gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator gri_fft_complex *d_fft; std::vector< gri_fir_filter_with_buffer_ccf*> d_filters; std::vector< std::vector > d_taps; - int d_state; + int d_state; + std::vector d_channel_map; + unsigned int d_twox; + gruel::mutex d_mutex; // mutex to protect set/work access + + /*! + * \brief Tap setting algorithm for critically sampled channels + */ + void set_taps1(const std::vector &taps); + + /*! + * \brief Tap setting algorithm for 2x over-sampled channels + */ + void set_taps2(const std::vector &taps); /*! * Build the polyphase synthesis filterbank. @@ -73,9 +88,11 @@ class GR_CORE_API gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator channels M * \param taps (vector/list of floats) The prototype filter to populate the filterbank. + * \param twox (bool) use 2x oversampling or not (default is no) */ gr_pfb_synthesis_filterbank_ccf (unsigned int numchans, - const std::vector &taps); + const std::vector &taps, + bool twox); public: ~gr_pfb_synthesis_filterbank_ccf (); @@ -86,12 +103,41 @@ public: populate the filterbank. */ void set_taps (const std::vector &taps); - void set_taps2(const std::vector &taps); /*! * Print all of the filterbank taps to screen. */ void print_taps(); + + /*! + * Return a vector> of the filterbank taps + */ + std::vector > taps() const; + + /*! + * Set the channel map. Channels are numbers as: + * N/2+1 | ... | N-1 | 0 | 1 | 2 | ... | N/2 + * <------------------- 0 --------------------> + * freq + * + * So input stream 0 goes to channel 0, etc. Setting a new channel + * map allows the user to specify where in frequency he/she wants + * the input stream to go. This is especially useful to avoid + * putting signals into the channels on the edge of the spectrum + * which can either wrap around (in the case of odd number of + * channels) and be affected by filter rolloff in the transmitter. + * + * The map must be at least the number of streams being sent to the + * block. Less and the algorithm will not have enough data to + * properly setup the buffers. Any more channels specified will be + * ignored. + */ + void set_channel_map(const std::vector &map); + + /*! + * Gets the current channel map. + */ + std::vector channel_map() const; int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i index 0a75269cb..c24abecf0 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i @@ -23,17 +23,22 @@ GR_SWIG_BLOCK_MAGIC(gr,pfb_synthesis_filterbank_ccf); gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf - (unsigned int numchans, const std::vector &taps); + (unsigned int numchans, const std::vector &taps, bool twox=false); class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator { private: gr_pfb_synthesis_filterbank_ccf (unsigned int numchans, - const std::vector &taps); + const std::vector &taps, + bool twox=false); public: ~gr_pfb_synthesis_filterbank_ccf (); void set_taps (const std::vector &taps); void print_taps(); + std::vector< std::vector > taps() const; + + void set_channel_map(const std::vector &map); + std::vector channel_map() const; }; -- cgit From 3d3d3c05291aebb1ad90d22f9674546347cb96d6 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 28 Feb 2012 16:02:16 -0500 Subject: core: pfb channelizer: can now set a channel map to direct the channels to a specific output stream. Now, not all output channels must be connected; can connect M of N channels (M <= N) and use the channel_map to set which channel from the original wideband signal go to which output streams. --- .../src/lib/filter/gr_pfb_channelizer_ccf.cc | 45 ++++++++++++++++++++-- .../src/lib/filter/gr_pfb_channelizer_ccf.h | 45 ++++++++++++++++++++++ .../src/lib/filter/gr_pfb_channelizer_ccf.i | 5 +++ .../python/gnuradio/blks2impl/pfb_channelizer.py | 22 ++++------- 4 files changed, 99 insertions(+), 18 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc index db16a634b..24fc35a19 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc @@ -46,7 +46,7 @@ gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans, float oversample_rate) : gr_block ("pfb_channelizer_ccf", gr_make_io_signature (numchans, numchans, sizeof(gr_complex)), - gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))), + gr_make_io_signature (1, numchans, sizeof(gr_complex))), d_updated (false), d_numchans(numchans), d_oversample_rate(oversample_rate) { // The over sampling rate must be rationally related to the number of channels @@ -62,11 +62,13 @@ gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans, set_relative_rate(1.0/intp); d_filters = std::vector(d_numchans); + d_channel_map.resize(d_numchans); // Create an FIR filter for each channel and zero out the taps std::vector vtaps(0, d_numchans); for(unsigned int i = 0; i < d_numchans; i++) { d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); + d_channel_map[i] = i; } // Now, actually set the filters' taps @@ -104,6 +106,7 @@ gr_pfb_channelizer_ccf::~gr_pfb_channelizer_ccf () void gr_pfb_channelizer_ccf::set_taps (const std::vector &taps) { + gruel::scoped_lock guard(d_mutex); unsigned int i,j; unsigned int ntaps = taps.size(); @@ -151,6 +154,31 @@ gr_pfb_channelizer_ccf::print_taps() } } +std::vector< std::vector > +gr_pfb_channelizer_ccf::taps() const +{ + return d_taps; +} + +void +gr_pfb_channelizer_ccf::set_channel_map(const std::vector &map) +{ + gruel::scoped_lock guard(d_mutex); + + unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); + unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); + if((max >= d_numchans) || (min < 0)) { + throw std::invalid_argument("gr_pfb_channelizer_ccf::set_channel_map: map range out of bounds.\n"); + } + d_channel_map = map; +} + +std::vector +gr_pfb_channelizer_ccf::channel_map() const +{ + return d_channel_map; +} + int gr_pfb_channelizer_ccf::general_work (int noutput_items, @@ -158,6 +186,8 @@ gr_pfb_channelizer_ccf::general_work (int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gruel::scoped_lock guard(d_mutex); + gr_complex *in = (gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; @@ -166,7 +196,9 @@ gr_pfb_channelizer_ccf::general_work (int noutput_items, return 0; // history requirements may have changed. } - int n=1, i=-1, j=0, last; + size_t noutputs = output_items.size(); + + int n=1, i=-1, j=0, oo=0, last; int toconsume = (int)rintf(noutput_items/d_oversample_rate); while(n <= toconsume) { j = 0; @@ -191,8 +223,13 @@ gr_pfb_channelizer_ccf::general_work (int noutput_items, // despin through FFT d_fft->execute(); - memcpy(out, d_fft->get_outbuf(), d_numchans*sizeof(gr_complex)); - out += d_numchans; + + // Send to output channels + for(unsigned int nn = 0; nn < noutputs; nn++) { + out = (gr_complex*)output_items[nn]; + out[oo] = d_fft->get_outbuf()[d_channel_map[nn]]; + } + oo++; } consume_each(toconsume); diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h index 8fd5c4f78..ce578c426 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h @@ -26,6 +26,7 @@ #include #include +#include class gr_pfb_channelizer_ccf; typedef boost::shared_ptr gr_pfb_channelizer_ccf_sptr; @@ -146,6 +147,8 @@ class GR_CORE_API gr_pfb_channelizer_ccf : public gr_block int *d_idxlut; int d_rate_ratio; int d_output_multiple; + std::vector d_channel_map; + gruel::mutex d_mutex; // mutex to protect set/work access /*! * Build the polyphase filterbank decimator. @@ -170,6 +173,48 @@ public: * Print all of the filterbank taps to screen. */ void print_taps(); + + /*! + * Return a vector> of the filterbank taps + */ + std::vector > taps() const; + + /*! + * Set the channel map. Channels are numbers as: + * + * N/2+1 | ... | N-1 | 0 | 1 | 2 | ... | N/2 + * <------------------- 0 --------------------> + * freq + * + * So output stream 0 comes from channel 0, etc. Setting a new + * channel map allows the user to specify which channel in frequency + * he/she wants to got to which output stream. + * + * The map should have the same number of elements as the number of + * output connections from the block. The minimum value of the map + * is 0 (for the 0th channel) and the maximum number is N-1 where N + * is the number of channels. + * + * We specify M as the number of output connections made where M <= + * N, so only M out of N channels are driven to an output + * stream. The number of items in the channel map should be at least + * M long. If there are more channels specified, any value in the + * map over M-1 will be ignored. If the size of the map is less than + * M the behavior is unknown (we don't wish to check every entry + * into the work function). + + * This means that if the channelizer is splitting the signal up + * into N channels but only M channels are specified in the map + * (where M < N), then M output streams must be connected and the + * map can only contain numbers from 0 to M-1. By default, the map + * is [0...M-1] with M = N. + */ + void set_channel_map(const std::vector &map); + + /*! + * Gets the current channel map. + */ + std::vector channel_map() const; int general_work (int noutput_items, gr_vector_int &ninput_items, diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i index 63e3e0fe6..f5edba5b7 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i @@ -37,4 +37,9 @@ class gr_pfb_channelizer_ccf : public gr_block ~gr_pfb_channelizer_ccf (); void set_taps (const std::vector &taps); + void print_taps(); + std::vector > taps() const; + + void set_channel_map(const std::vector &map); + std::vector channel_map() const; }; diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py index 3ddc1749a..dea71b286 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py @@ -34,7 +34,7 @@ class pfb_channelizer_ccf(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(numchans, numchans, gr.sizeof_gr_complex)) # Output signature - self._numchans = numchans + self._nchans = numchans self._oversample_rate = oversample_rate if taps is not None: @@ -47,7 +47,7 @@ class pfb_channelizer_ccf(gr.hier_block2): made = False while not made: try: - self._taps = optfir.low_pass(1, self._numchans, bw, bw+tb, ripple, atten) + self._taps = optfir.low_pass(1, self._nchans, bw, bw+tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 @@ -58,22 +58,16 @@ class pfb_channelizer_ccf(gr.hier_block2): if(ripple >= 1.0): raise RuntimeError("optfir could not generate an appropriate filter.") - self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans) - self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps, + self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._nchans) + self.pfb = gr.pfb_channelizer_ccf(self._nchans, self._taps, self._oversample_rate) - self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans) - self.connect(self, self.s2ss) - for i in xrange(self._numchans): + for i in xrange(self._nchans): self.connect((self.s2ss,i), (self.pfb,i)) + self.connect((self.pfb,i), (self,i)) - # Get independent streams from the filterbank and send them out - self.connect(self.pfb, self.v2s) - - for i in xrange(self._numchans): - self.connect((self.v2s,i), (self,i)) - - + def set_channel_map(self, newmap): + self.pfb.set_channel_map(newmap) -- cgit From 68a36d3e2c78d477e9c793df9ec9f540aa5f327d Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 28 Feb 2012 16:24:43 -0500 Subject: core: simple formatting. --- gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h index ce578c426..040b93e73 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h @@ -202,12 +202,13 @@ public: * map over M-1 will be ignored. If the size of the map is less than * M the behavior is unknown (we don't wish to check every entry * into the work function). - + * * This means that if the channelizer is splitting the signal up * into N channels but only M channels are specified in the map - * (where M < N), then M output streams must be connected and the - * map can only contain numbers from 0 to M-1. By default, the map - * is [0...M-1] with M = N. + * (where M <= N), then M output streams must be connected and the + * map and the channel numbers used must be less than N-1. Output + * channel number can be reused, too. By default, the map is + * [0...M-1] with M = N. */ void set_channel_map(const std::vector &map); -- cgit