summaryrefslogtreecommitdiff
path: root/gnuradio-core
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core')
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc45
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h45
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i5
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py22
4 files changed, 99 insertions, 18 deletions
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<gr_fir_ccf*>(d_numchans);
+ d_channel_map.resize(d_numchans);
// Create an FIR filter for each channel and zero out the taps
std::vector<float> 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<float> &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<float> >
+gr_pfb_channelizer_ccf::taps() const
+{
+ return d_taps;
+}
+
+void
+gr_pfb_channelizer_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_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<int>
+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 <gr_core_api.h>
#include <gr_block.h>
+#include <gruel/thread.h>
class gr_pfb_channelizer_ccf;
typedef boost::shared_ptr<gr_pfb_channelizer_ccf> 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<int> 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<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 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<int> &map);
+
+ /*!
+ * Gets the current channel map.
+ */
+ std::vector<int> 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<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;
};
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)