summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau2012-02-28 12:36:00 -0500
committerTom Rondeau2012-02-28 12:36:00 -0500
commitd15bed21e08f97b0ac510b49124c9231289820c2 (patch)
tree94ce12ca1fbe4c44eef4662c175975b01f7f8087
parentdd4cc588d7a34f82a63c6b23ca7a1fab736bfc10 (diff)
downloadgnuradio-d15bed21e08f97b0ac510b49124c9231289820c2.tar.gz
gnuradio-d15bed21e08f97b0ac510b49124c9231289820c2.tar.bz2
gnuradio-d15bed21e08f97b0ac510b49124c9231289820c2.zip
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.
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc131
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h56
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i9
3 files changed, 159 insertions, 37 deletions
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 <cstring>
gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf
- (unsigned int numchans, const std::vector<float> &taps)
+ (unsigned int numchans, const std::vector<float> &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<float> &taps)
+ (unsigned int numchans, const std::vector<float> &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<gri_fir_filter_with_buffer_ccf*>(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<gri_fir_filter_with_buffer_ccf*>(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<float> vtaps(0, 2*d_numchans);
- for(unsigned int i = 0; i < 2*d_numchans; i++) {
+ std::vector<float> 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<float> &taps)
+gr_pfb_synthesis_filterbank_ccf::set_taps(const std::vector<float> &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<float> &taps)
{
unsigned int i,j;
@@ -118,7 +136,7 @@ gr_pfb_synthesis_filterbank_ccf::set_taps2 (const std::vector<float> &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<float> >
+gr_pfb_synthesis_filterbank_ccf::taps() const
+{
+ return d_taps;
+}
+
+void
+gr_pfb_synthesis_filterbank_ccf::set_channel_map(const std::vector<int> &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<int>
+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 <gr_core_api.h>
#include <gr_sync_interpolator.h>
#include <gri_fir_filter_with_buffer_ccf.h>
+#include <gruel/thread.h>
class gr_pfb_synthesis_filterbank_ccf;
typedef boost::shared_ptr<gr_pfb_synthesis_filterbank_ccf> 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<float> &taps);
+ (unsigned int numchans, const std::vector<float> &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 <EM>M</EM>
* \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<float> &taps);
+ (unsigned int numchans, const std::vector<float> &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<float> > d_taps;
- int d_state;
+ int d_state;
+ std::vector<int> 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<float> &taps);
+
+ /*!
+ * \brief Tap setting algorithm for 2x over-sampled channels
+ */
+ void set_taps2(const std::vector<float> &taps);
/*!
* Build the polyphase synthesis filterbank.
@@ -73,9 +88,11 @@ class GR_CORE_API gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator
channels <EM>M</EM>
* \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<float> &taps);
+ const std::vector<float> &taps,
+ bool twox);
public:
~gr_pfb_synthesis_filterbank_ccf ();
@@ -86,12 +103,41 @@ public:
populate the filterbank.
*/
void set_taps (const std::vector<float> &taps);
- void set_taps2(const std::vector<float> &taps);
/*!
* Print all of the filterbank taps to screen.
*/
void print_taps();
+
+ /*!
+ * Return a vector<vector<>> of the filterbank taps
+ */
+ std::vector<std::vector<float> > 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<int> &map);
+
+ /*!
+ * Gets the current channel map.
+ */
+ std::vector<int> 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<float> &taps);
+ (unsigned int numchans, const std::vector<float> &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<float> &taps);
+ const std::vector<float> &taps,
+ bool twox=false);
public:
~gr_pfb_synthesis_filterbank_ccf ();
void set_taps (const std::vector<float> &taps);
void print_taps();
+ std::vector< std::vector<float> > taps() const;
+
+ void set_channel_map(const std::vector<int> &map);
+ std::vector<int> channel_map() const;
};