[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 05/06: filters: fixing up some minor issues
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 05/06: filters: fixing up some minor issues with the analysis/synthesis filterbanks. |
Date: |
Fri, 28 Feb 2014 16:53:15 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script.
trondeau pushed a commit to branch master
in repository gnuradio.
commit 92044de1fc8bbbe798071bfeeed8520b6e3c7122
Author: Tom Rondeau <address@hidden>
Date: Wed Feb 26 15:10:41 2014 -0500
filters: fixing up some minor issues with the analysis/synthesis
filterbanks.
Also adds bus ports capabilities to these filterbanks. Using the GRP
properties box, the vector for the bus ports can be set up to group and
redirect each channel as necessary.
---
gr-filter/examples/reconstruction.py | 6 +-
gr-filter/grc/filter_pfb_channelizer.xml | 13 +-
gr-filter/grc/filter_pfb_synthesizer.xml | 8 +
.../include/gnuradio/filter/pfb_channelizer_ccf.h | 12 +-
.../include/gnuradio/filter/pfb_synthesizer_ccf.h | 55 ++++-
gr-filter/lib/pfb_channelizer_ccf_impl.cc | 72 ++++--
gr-filter/lib/pfb_channelizer_ccf_impl.h | 2 +-
gr-filter/lib/pfb_synthesizer_ccf_impl.cc | 268 +++++++++++----------
gr-filter/lib/polyphase_filterbank.cc | 2 -
gr-filter/python/filter/qa_pfb_channelizer.py | 16 +-
gr-filter/python/filter/qa_pfb_decimator.py | 11 +-
gr-filter/python/filter/qa_pfb_interpolator.py | 20 +-
gr-filter/python/filter/qa_pfb_synthesizer.py | 34 +--
13 files changed, 316 insertions(+), 203 deletions(-)
diff --git a/gr-filter/examples/reconstruction.py
b/gr-filter/examples/reconstruction.py
index fd8ba87..0a83b5a 100755
--- a/gr-filter/examples/reconstruction.py
+++ b/gr-filter/examples/reconstruction.py
@@ -72,7 +72,7 @@ def main():
src = blocks.vector_source_b(data.astype(scipy.uint8).tolist(), False)
mod = digital.bpsk_mod(samples_per_symbol=2)
- chan = filter.channel_model(npwr)
+ chan = channels.channel_model(npwr)
rrc = filter.fft_filter_ccc(1, rrc_taps)
# Split it up into pieces
@@ -122,7 +122,7 @@ def main():
s12.set_title("Original Signal in Time")
start = 1
- skip = 4
+ skip = 2
s13 = f1.add_subplot(2,2,3)
s13.plot(sin.real[start::skip], sin.imag[start::skip], "o")
s13.set_title("Constellation")
@@ -153,7 +153,7 @@ def main():
s32.plot(sout.imag[1000:1500], "o-r")
s32.set_title("Reconstructed Signal in Time")
- start = 2
+ start = 0
skip = 4
s33 = f3.add_subplot(2,2,3)
s33.plot(sout.real[start::skip], sout.imag[start::skip], "o")
diff --git a/gr-filter/grc/filter_pfb_channelizer.xml
b/gr-filter/grc/filter_pfb_channelizer.xml
index 26349cd..f8a51d2 100644
--- a/gr-filter/grc/filter_pfb_channelizer.xml
+++ b/gr-filter/grc/filter_pfb_channelizer.xml
@@ -16,14 +16,13 @@
$atten)
self.$(id).set_channel_map($ch_map)
</make>
- <!-- Set taps not implemented yet
- <callback>set_taps($taps)</callback>
- -->
+ <callback>set_taps($taps)</callback>
<callback>set_channel_map($ch_map)</callback>
<param>
<name>Channels</name>
<key>nchans</key>
+ <value>1</value>
<type>int</type>
</param>
<param>
@@ -50,6 +49,13 @@ self.$(id).set_channel_map($ch_map)
<value>[]</value>
<type>int_vector</type>
</param>
+ <param>
+ <name>Bus Connections</name>
+ <key>bus_conns</key>
+ <value>[[0,],]</value>
+ <type>raw</type>
+ <hide>part</hide>
+ </param>
<sink>
<name>in</name>
<type>complex</type>
@@ -59,4 +65,5 @@ self.$(id).set_channel_map($ch_map)
<type>complex</type>
<nports>$nchans</nports>
</source>
+ <bus_structure_source>$bus_conns</bus_structure_source>
</block>
diff --git a/gr-filter/grc/filter_pfb_synthesizer.xml
b/gr-filter/grc/filter_pfb_synthesizer.xml
index e84b25e..e7e1ae3 100644
--- a/gr-filter/grc/filter_pfb_synthesizer.xml
+++ b/gr-filter/grc/filter_pfb_synthesizer.xml
@@ -45,6 +45,13 @@ self.$(id).set_channel_map($ch_map)
<value>[]</value>
<type>int_vector</type>
</param>
+ <param>
+ <name>Bus Connections</name>
+ <key>bus_conns</key>
+ <value>[[0,],]</value>
+ <type>raw</type>
+ <hide>part</hide>
+ </param>
<sink>
<name>in</name>
<type>complex</type>
@@ -54,4 +61,5 @@ self.$(id).set_channel_map($ch_map)
<name>out</name>
<type>complex</type>
</source>
+ <bus_structure_sink>$bus_conns</bus_structure_sink>
</block>
diff --git a/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h
b/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h
index f199f85..96ffd60 100644
--- a/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h
+++ b/gr-filter/include/gnuradio/filter/pfb_channelizer_ccf.h
@@ -101,8 +101,14 @@ namespace gr {
* <B><EM>f. harris, "Multirate Signal Processing for Communication
* Systems," Upper Saddle River, NJ: Prentice Hall, Inc.
2004.</EM></B>
*
+ * When dealing with oversampling, the above book is still a good
+ * reference along with this paper:
+ *
+ * <B><EM>E. Venosa, X. Chen, and fred harris, “Polyphase analysis
+ * filter bank down-converts unequal channel bandwidths with
+ * arbitrary center frequencies - design I,” in SDR’10-WinnComm,
+ * 2010.</EM></B>
*/
-
class FILTER_API pfb_channelizer_ccf : virtual public block
{
public:
@@ -151,7 +157,7 @@ namespace gr {
* Print all of the filterbank taps to screen.
*/
virtual void print_taps() = 0;
-
+
/*!
* Return a vector<vector<>> of the filterbank taps
*/
@@ -189,7 +195,7 @@ namespace gr {
* the map is [0...M-1] with M = N.
*/
virtual void set_channel_map(const std::vector<int> &map) = 0;
-
+
/*!
* Gets the current channel map.
*/
diff --git a/gr-filter/include/gnuradio/filter/pfb_synthesizer_ccf.h
b/gr-filter/include/gnuradio/filter/pfb_synthesizer_ccf.h
index f1fbad7..32465b6 100644
--- a/gr-filter/include/gnuradio/filter/pfb_synthesizer_ccf.h
+++ b/gr-filter/include/gnuradio/filter/pfb_synthesizer_ccf.h
@@ -34,6 +34,57 @@ namespace gr {
* \brief Polyphase synthesis filterbank with
* gr_complex input, gr_complex output and float taps
* \ingroup channelizers_blk
+ *
+ * \details
+ *
+ * The PFB sythesis filterbank combines multiple baseband signals
+ * into a single channelized signal. Each input stream is,
+ * essentially, modulated onto an output channel according the the
+ * channel mapping (see set_channel_map for details).
+ *
+ * Setting this filterbank up means selecting the number of output
+ * channels, the prototype filter, and whether to handle channels
+ * at 2x the sample rate (this is generally used only for
+ * reconstruction filtering).
+ *
+ * The number of channels sets the maximum number of channels to
+ * use, but not all input streams must be connected. For M total
+ * channels, we can connect inputs 0 to N where N < M-1. Because
+ * of the way GNU Radio handles stream connections, we must
+ * connect the channels consecutively, and so we must use the
+ * set_channel_map if the desired output channels are not the same
+ * as the the default mapping. This features gives us the
+ * flexibility to output to any given channel. Generally, we try
+ * to not use the channels at the edge of the spectrum to avoid
+ * issues with filtering and roll-off of the transmitter or
+ * receiver.
+ *
+ * When using the 2x sample rate mode, we specify the number of
+ * channels that will be used. However, the actual output signal
+ * will be twice this number of channels. This is mainly important
+ * to know when setting the channel map. For M channels, the
+ * channel mapping can specy from 0 to 2M-1 channels to output
+ * onto.
+ *
+ * For more details about this and the concepts of reconstruction
+ * filtering, see:
+ *
+ * <B><EM>f. harris, "Multirate Signal Processing for Communication
+ * Systems," Upper Saddle River, NJ: Prentice Hall, Inc.
2004.</EM></B>
+ *
+ * <B><EM>X. Chen, E. Venosa, and fred harris, “Polyphase analysis
+ * filter bank up-converts unequal channel bandwidths with
+ * arbitrary center frequencies - design ii,” in SDR’10-WinnComm,
+ * 2010.</EM></B>
+ *
+ * <B><EM>E. Venosa, X. Chen, and fred harris, “Polyphase analysis
+ * filter bank down-converts unequal channel bandwidths with
+ * arbitrary center frequencies - design I,” in SDR’10-WinnComm,
+ * 2010.</EM></B>
+ *
+ * <B><EM>f. j. harris, C. Dick, X. Chen, and E. Venosa, “Wideband 160-
+ * channel polyphase filter bank cable TV channeliser,” in IET
+ * Signal Processing, 2010.</EM></B>
*/
class FILTER_API pfb_synthesizer_ccf : virtual public sync_interpolator
{
@@ -50,8 +101,8 @@ namespace gr {
* \param twox (bool) use 2x oversampling or not (default is no)
*/
static sptr make(unsigned int numchans,
- const std::vector<float> &taps,
- bool twox=false);
+ const std::vector<float> &taps,
+ bool twox=false);
/*!
* Resets the filterbank's filter taps with the new prototype filter
diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.cc
b/gr-filter/lib/pfb_channelizer_ccf_impl.cc
index c28434b..62223e4 100644
--- a/gr-filter/lib/pfb_channelizer_ccf_impl.cc
+++ b/gr-filter/lib/pfb_channelizer_ccf_impl.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009,2010,2012 Free Software Foundation, Inc.
+ * Copyright 2009,2010,2012,2014 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,25 +26,28 @@
#include "pfb_channelizer_ccf_impl.h"
#include <gnuradio/io_signature.h>
+#include <stdio.h>
namespace gr {
namespace filter {
-
- pfb_channelizer_ccf::sptr pfb_channelizer_ccf::make(unsigned int nfilts,
- const
std::vector<float> &taps,
- float oversample_rate)
+
+ pfb_channelizer_ccf::sptr
+ pfb_channelizer_ccf::make(unsigned int nfilts,
+ const std::vector<float> &taps,
+ float oversample_rate)
{
- return gnuradio::get_initial_sptr(new pfb_channelizer_ccf_impl(nfilts,
taps,
-
oversample_rate));
+ return gnuradio::get_initial_sptr
+ (new pfb_channelizer_ccf_impl(nfilts, taps,
+ oversample_rate));
}
pfb_channelizer_ccf_impl::pfb_channelizer_ccf_impl(unsigned int nfilts,
const std::vector<float>
&taps,
float oversample_rate)
: block("pfb_channelizer_ccf",
- io_signature::make(nfilts, nfilts, sizeof(gr_complex)),
- io_signature::make(1, nfilts, sizeof(gr_complex))),
- polyphase_filterbank(nfilts, taps),
+ io_signature::make(nfilts, nfilts, sizeof(gr_complex)),
+ io_signature::make(1, nfilts, sizeof(gr_complex))),
+ polyphase_filterbank(nfilts, taps, false),
d_updated(false), d_oversample_rate(oversample_rate)
{
// The over sampling rate must be rationally related to the number of
channels
@@ -59,15 +62,22 @@ namespace gr {
set_relative_rate(1.0/intp);
- // Default channel map
+ // Default channel map. The channel map specifies which input
+ // goes to which output channel; so out[0] comes from
+ // channel_map[0].
d_channel_map.resize(d_nfilts);
for(unsigned int i = 0; i < d_nfilts; i++) {
d_channel_map[i] = i;
}
- // Although the filters change, we use this look up table
- // to set the index of the FFT input buffer, which equivalently
- // performs the FFT shift operation on every other turn.
+ // We use a look up table to set the index of the FFT input
+ // buffer, which equivalently performs the FFT shift operation
+ // on every other turn when the rate_ratio>1. Also, this
+ // performs the index 'flip' where the first input goes into the
+ // last filter. In the pfb_decimator_ccf, we directly index the
+ // input_items buffers starting with this last; here we start
+ // with the first and put it into the fft object properly for
+ // the same effect.
d_rate_ratio = (int)rintf(d_nfilts / d_oversample_rate);
d_idxlut = new int[d_nfilts];
for(unsigned int i = 0; i < d_nfilts; i++) {
@@ -81,10 +91,8 @@ namespace gr {
d_output_multiple++;
set_output_multiple(d_output_multiple);
- // History is the length of each filter arm plus 1.
- // The +1 comes from the channel mapping in the work function
- // where we start n=1 so that we can look at in[n-1]
- set_history(d_taps_per_filter+1);
+ // Use set_taps to also set the history requirement
+ set_taps(taps);
}
pfb_channelizer_ccf_impl::~pfb_channelizer_ccf_impl()
@@ -118,7 +126,7 @@ namespace gr {
pfb_channelizer_ccf_impl::set_channel_map(const std::vector<int> &map)
{
gr::thread::scoped_lock guard(d_mutex);
-
+
if(map.size() > 0) {
unsigned int max = (unsigned int)*std::max_element(map.begin(),
map.end());
if(max >= d_nfilts) {
@@ -142,9 +150,9 @@ namespace gr {
{
gr::thread::scoped_lock guard(d_mutex);
- gr_complex *in = (gr_complex *) input_items[0];
- gr_complex *out = (gr_complex *) output_items[0];
-
+ gr_complex *in = (gr_complex*)input_items[0];
+ gr_complex *out = (gr_complex*)output_items[0];
+
if(d_updated) {
d_updated = false;
return 0; // history requirements may have changed.
@@ -152,6 +160,18 @@ namespace gr {
size_t noutputs = output_items.size();
+ // The following algorithm looks more complex in order to handle
+ // the cases where we want more that 1 sps for each
+ // channel. Otherwise, this would boil down into a single loop
+ // that operates from input_items[0] to [d_nfilts].
+
+ // When dealing with osps>1, we start not at the last filter,
+ // but nfilts/osps and then wrap around to the next symbol into
+ // the other set of filters.
+ // For details of this operation, see:
+ // fred harris, Multirate Signal Processing For Communication
+ // Systems. Upper Saddle River, NJ: Prentice Hall, 2004.
+
int n=1, i=-1, j=0, oo=0, last;
int toconsume = (int)rintf(noutput_items/d_oversample_rate);
while(n <= toconsume) {
@@ -159,16 +179,16 @@ namespace gr {
i = (i + d_rate_ratio) % d_nfilts;
last = i;
while(i >= 0) {
- in = (gr_complex*)input_items[j];
- d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n]);
+ in = (gr_complex*)input_items[j];
+ d_fft->get_inbuf()[d_idxlut[j]] = d_fir_filters[i]->filter(&in[n]);
j++;
i--;
}
i = d_nfilts-1;
while(i > last) {
- in = (gr_complex*)input_items[j];
- d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]);
+ in = (gr_complex*)input_items[j];
+ d_fft->get_inbuf()[d_idxlut[j]] = d_fir_filters[i]->filter(&in[n-1]);
j++;
i--;
}
diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.h
b/gr-filter/lib/pfb_channelizer_ccf_impl.h
index 6d72767..bfc53f8 100644
--- a/gr-filter/lib/pfb_channelizer_ccf_impl.h
+++ b/gr-filter/lib/pfb_channelizer_ccf_impl.h
@@ -31,7 +31,7 @@
namespace gr {
namespace filter {
-
+
class FILTER_API pfb_channelizer_ccf_impl : public pfb_channelizer_ccf,
kernel::polyphase_filterbank
{
private:
diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc
b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc
index 5f0e330..bdfc158 100644
--- a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc
+++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2010,2012 Free Software Foundation, Inc.
+ * Copyright 2010,2012,2014 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -33,45 +33,43 @@ namespace gr {
pfb_synthesizer_ccf::sptr
pfb_synthesizer_ccf::make(unsigned int numchans,
- const std::vector<float> &taps,
- bool twox)
+ const std::vector<float> &taps, bool twox)
{
return gnuradio::get_initial_sptr
- (new pfb_synthesizer_ccf_impl(numchans, taps, twox));
+ (new pfb_synthesizer_ccf_impl(numchans, taps, twox));
}
-
- pfb_synthesizer_ccf_impl::pfb_synthesizer_ccf_impl(unsigned int numchans,
- const std::vector<float>
&taps,
- bool twox)
+ pfb_synthesizer_ccf_impl::pfb_synthesizer_ccf_impl
+ (unsigned int numchans, const std::vector<float> &taps, bool twox)
: sync_interpolator("pfb_synthesizer_ccf",
- io_signature::make(1, numchans,
sizeof(gr_complex)),
- io_signature::make(1, 1, sizeof(gr_complex)),
- (twox ? numchans/2 : numchans)),
- d_updated(false), d_numchans(numchans), d_state(0)
+ io_signature::make(1, numchans, sizeof(gr_complex)),
+ io_signature::make(1, 1, sizeof(gr_complex)),
+ numchans),
+ d_updated(false), d_numchans(numchans), d_state(0)
{
// 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("pfb_synthesizer_ccf: number of channels
must be even for 2x oversampling.\n");
+ throw std::invalid_argument("pfb_synthesizer_ccf_impl: number of
channels must be even for 2x oversampling.\n");
}
- d_filters = std::vector<kernel::fir_filter_with_buffer_ccf*>(d_numchans);
- d_channel_map.resize(d_numchans);
+ d_filters =
std::vector<kernel::fir_filter_with_buffer_ccf*>(d_twox*d_numchans);
+ d_channel_map.resize(d_twox*d_numchans);
- // Create a 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] = new kernel::fir_filter_with_buffer_ccf(vtaps);
- d_channel_map[i] = i;
+ // Create an FIR filter for each channel and zero out the taps
+ // and set the default channel map
+ std::vector<float> vtaps(0, d_twox*d_numchans);
+ for(unsigned int i = 0; i < d_twox*d_numchans; i++) {
+ d_filters[i] = new kernel::fir_filter_with_buffer_ccf(vtaps);
+ d_channel_map[i] = i;
}
// Now, actually set the filters' taps
set_taps(taps);
// Create the IFFT to handle the input channel rotations
- d_fft = new fft::fft_complex(d_numchans, false);
- memset(d_fft->get_inbuf(), 0, d_numchans*sizeof(gr_complex));
+ d_fft = new fft::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);
}
@@ -79,8 +77,8 @@ namespace gr {
pfb_synthesizer_ccf_impl::~pfb_synthesizer_ccf_impl()
{
delete d_fft;
- for(unsigned int i = 0; i < d_numchans; i++) {
- delete d_filters[i];
+ for(unsigned int i = 0; i < d_twox*d_numchans; i++) {
+ delete d_filters[i];
}
}
@@ -89,20 +87,29 @@ namespace gr {
{
gr::thread::scoped_lock guard(d_mutex);
+ // The different modes, 1x or 2x the sampling rate, have
+ // different filtering partitions.
if(d_twox == 1)
- set_taps1(taps);
+ set_taps1(taps);
else
- set_taps2(taps);
-
- // Set the history to ensure enough input items for each filter
- set_history(d_taps_per_filter+1);
+ set_taps2(taps);
+ // Because we keep our own buffers inside the filters, we don't
+ // need history.
+ set_history(1);
d_updated = true;
}
void
pfb_synthesizer_ccf_impl::set_taps1(const std::vector<float> &taps)
{
+ // In this partitioning, we do a normal polyphase paritioning by
+ // deinterleaving the taps into each filter:
+ //
+ // Prototype filter: [t0, t1, t2, t3, t4, t5, t6]
+ // filter 0: [t0, t3, t6]
+ // filter 1: [t1, t4, 0 ]
+ // filter 2: [t2, t5, 0 ]
unsigned int i,j;
unsigned int ntaps = taps.size();
@@ -113,70 +120,77 @@ namespace gr {
// 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<float> tmp_taps;
- tmp_taps = taps;
+ std::vector<float> tmp_taps = taps;
while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) {
- tmp_taps.push_back(0.0);
+ 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<float>(d_taps_per_filter, 0);
- for(j = 0; j < d_taps_per_filter; j++) {
- d_taps[i][j] = tmp_taps[i + j*d_numchans]; // add taps to channels
in reverse order
- }
-
- // Build a filter for each channel and add it's taps to it
- d_filters[i]->set_taps(d_taps[i]);
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps
to fill out
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ d_taps[i][j] = tmp_taps[i + j*d_numchans]; // add taps to channels
in reverse order
+ }
+
+ // Set the filter taps for each channel
+ d_filters[i]->set_taps(d_taps[i]);
}
}
void
- pfb_synthesizer_ccf_impl::set_taps2 (const std::vector<float> &taps)
+ pfb_synthesizer_ccf_impl::set_taps2(const std::vector<float> &taps)
{
+ // In this partitioning, create 2M filters each in Z^2; the
+ // second half of the filters are also delayed by Z^1:
+ //
+ // Prototype filter: [t0, t1, t2, t3, t4, t5, t6]
+ // filter 0: [t0, 0, t6]
+ // filter 1: [t2, 0, 0]
+ // filter 2: [t4, 0, 0]
+ // filter 3: [ 0, t1, 0]
+ // filter 4: [ 0, t3, 0 ]
+ // filter 5: [ 0, t5, 0 ]
+
unsigned int i,j;
int state = 0;
- unsigned int ntaps = 2*taps.size();
+ 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(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
- std::vector<float> tmp_taps;
- tmp_taps = taps;
+ std::vector<float> tmp_taps = taps;
while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) {
- tmp_taps.push_back(0.0);
+ tmp_taps.push_back(0.0);
+ //tmp_taps.insert(tmp_taps.begin(), 0.0);
}
// Partition the filter
- unsigned int halfchans = d_numchans/2;
- for(i = 0; i < halfchans; i++) {
- // Each channel uses all d_taps_per_filter with 0's if not enough taps
to fill out
- d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
- d_taps[halfchans+i] = std::vector<float>(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*halfchans];
- d_taps[halfchans + i][j] = 0;
- state = 1;
- }
- else {
- d_taps[i][j] = 0;
- d_taps[halfchans + i][j] = tmp_taps[i + j*halfchans];
- 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[halfchans + i]->set_taps(d_taps[halfchans + i]);
+ 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<float>(d_taps_per_filter, 0);
+ d_taps[d_numchans+i] = std::vector<float>(d_taps_per_filter, 0);
+ state = 0;
+ for(j = 0; j < d_taps_per_filter; j++) {
+ if(state == 0) {
+ d_taps[i][j] = 0;
+ d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans];
+ state = 1;
+ }
+ else {
+ d_taps[i][j] = tmp_taps[i + j*d_numchans];
+ d_taps[d_numchans + i][j] = 0;
+ state = 0;
+ }
+ }
+
+ // Set the filter taps for each channel
+ d_filters[i]->set_taps(d_taps[i]);
+ d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]);
}
}
@@ -184,15 +198,16 @@ namespace gr {
pfb_synthesizer_ccf_impl::print_taps()
{
unsigned int i, j;
- for(i = 0; i < d_numchans; i++) {
- printf("filter[%d]: [", i);
- for(j = 0; j < d_taps_per_filter; j++) {
- printf(" %.4e", d_taps[i][j]);
- }
- printf("]\n\n");
+ 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]);
+ }
+ printf("]\n\n");
}
}
+
std::vector< std::vector<float> >
pfb_synthesizer_ccf_impl::taps() const
{
@@ -205,14 +220,15 @@ namespace gr {
gr::thread::scoped_lock guard(d_mutex);
if(map.size() > 0) {
- unsigned int max = (unsigned int)*std::max_element(map.begin(),
map.end());
- if(max >= d_numchans) {
- throw std::invalid_argument("gr_pfb_synthesizer_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_numchans*sizeof(gr_complex));
+ 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("pfb_synthesizer_ccf_impl::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));
}
}
@@ -224,63 +240,63 @@ namespace gr {
int
pfb_synthesizer_ccf_impl::work(int noutput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
{
gr::thread::scoped_lock guard(d_mutex);
- gr_complex *in = (gr_complex*)input_items[0];
- gr_complex *out = (gr_complex*)output_items[0];
+ gr_complex *in = (gr_complex*) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
if(d_updated) {
- d_updated = false;
- return 0; // history requirements may have changed.
+ d_updated = false;
+ return 0; // history requirements may have changed.
}
unsigned int n, i;
size_t ninputs = input_items.size();
- // Algoritm for critically sampled channels
+ // Algorithm 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;
- }
+ 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;
+ }
}
// Algorithm for oversampling by 2x
else {
- unsigned int halfchans = d_numchans/2;
- for(n = 0; n < noutput_items/halfchans; 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 < halfchans; i++) {
- out[i] =
d_filters[i]->filter(d_fft->get_outbuf()[d_state*halfchans+i]);
- out[i] +=
d_filters[halfchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*halfchans+i]);
- }
- d_state ^= 1;
-
- out += halfchans;
- }
+ for(n = 0; n < noutput_items/d_numchans; n++) {
+ for(i = 0; i < ninputs; i++) {
+ //in = (gr_complex*)input_items[ninputs-i-1];
+ 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;
+ }
}
return noutput_items;
diff --git a/gr-filter/lib/polyphase_filterbank.cc
b/gr-filter/lib/polyphase_filterbank.cc
index ac20eb4..5fffc02 100644
--- a/gr-filter/lib/polyphase_filterbank.cc
+++ b/gr-filter/lib/polyphase_filterbank.cc
@@ -79,8 +79,6 @@ namespace gr {
tmp_taps.push_back(0.0);
}
- std::reverse(tmp_taps.begin(), tmp_taps.end());
-
// Partition the filter
for(i = 0; i < d_nfilts; i++) {
// Each channel uses all d_taps_per_filter with 0's if not enough taps
to fill out
diff --git a/gr-filter/python/filter/qa_pfb_channelizer.py
b/gr-filter/python/filter/qa_pfb_channelizer.py
index 4c108e8..46c6e7b 100755
--- a/gr-filter/python/filter/qa_pfb_channelizer.py
+++ b/gr-filter/python/filter/qa_pfb_channelizer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2012,2013 Free Software Foundation, Inc.
+# Copyright 2012-2014 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -67,18 +67,18 @@ class test_pfb_channelizer(gr_unittest.TestCase):
self.tb.connect((s2ss,i), (pfb,i))
self.tb.connect((pfb, i), snks[i])
- self.tb.run()
+ self.tb.run()
Ntest = 50
L = len(snks[0].data())
# Adjusted phase rotations for data
- p0 = -2*math.pi * 0 / M
- p1 = -2*math.pi * 1 / M
- p2 = -2*math.pi * 2 / M
- p3 = -2*math.pi * 3 / M
- p4 = -2*math.pi * 4 / M
-
+ p0 = 0.11058379158914133
+ p1 = 4.5108246571401693
+ p2 = 3.9739891674564594
+ p3 = 2.2820531095511924
+ p4 = 1.3782797467397869
+
# Filter delay is the normal delay of each arm
tpf = math.ceil(len(taps) / float(M))
delay = -(tpf - 1.0) / 2.0
diff --git a/gr-filter/python/filter/qa_pfb_decimator.py
b/gr-filter/python/filter/qa_pfb_decimator.py
index 745ee53..4366e85 100755
--- a/gr-filter/python/filter/qa_pfb_decimator.py
+++ b/gr-filter/python/filter/qa_pfb_decimator.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2012,2013 Free Software Foundation, Inc.
+# Copyright 2012-2014 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -61,8 +61,13 @@ def run_test(tb, channel, fft_rotate, fft_filter):
L = len(snk.data())
- # Each channel is rotated by 2pi/M
- phase = -2*math.pi * channel / M
+ # Adjusted phase rotations for data
+ phase = [ 0.11058476216852586,
+ 4.5108246571401693,
+ 3.9739891674564594,
+ 2.2820531095511924,
+ 1.3782797467397869]
+ phase = phase[channel]
# Filter delay is the normal delay of each arm
tpf = math.ceil(len(taps) / float(M))
diff --git a/gr-filter/python/filter/qa_pfb_interpolator.py
b/gr-filter/python/filter/qa_pfb_interpolator.py
index 33c2267..b7ed4fe 100755
--- a/gr-filter/python/filter/qa_pfb_interpolator.py
+++ b/gr-filter/python/filter/qa_pfb_interpolator.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2012,2013 Free Software Foundation, Inc.
+# Copyright 2012-2014 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -42,9 +42,9 @@ class test_pfb_interpolator(gr_unittest.TestCase):
N = 1000 # number of samples to use
M = 5 # Number of channels
fs = 1000 # baseband sampling rate
- ifs = M*fs # input samp rate to decimator
+ ofs = M*fs # output samp rate of interpolator
- taps = filter.firdes.low_pass_2(M, ifs, fs/2, fs/10,
+ taps = filter.firdes.low_pass_2(M, ofs, fs/4, fs/10,
attenuation_dB=80,
window=filter.firdes.WIN_BLACKMAN_hARRIS)
@@ -57,20 +57,16 @@ class test_pfb_interpolator(gr_unittest.TestCase):
self.tb.connect(signal, pfb)
self.tb.connect(pfb, snk)
- self.tb.run()
+ self.tb.run()
Ntest = 50
L = len(snk.data())
- # Can only get channel 0 out; no phase rotation
- phase = 0
+ # Phase rotation through the filters
+ phase = 4.8870112969978994
- # Calculate the filter delay
- delay = -(len(taps) - 1) / 2.0 - (M-1)
- delay = int(delay)
-
- # Create a time scale that's delayed to match the filter delay
- t = map(lambda x: float(x)/ifs, xrange(delay, L+delay))
+ # Create a time scale
+ t = map(lambda x: float(x)/ofs, xrange(0, L))
# Create known data as complex sinusoids for the baseband freq
# of the extracted channel is due to decimator output order.
diff --git a/gr-filter/python/filter/qa_pfb_synthesizer.py
b/gr-filter/python/filter/qa_pfb_synthesizer.py
index baba904..0b3f8b2 100755
--- a/gr-filter/python/filter/qa_pfb_synthesizer.py
+++ b/gr-filter/python/filter/qa_pfb_synthesizer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2012,2013 Free Software Foundation, Inc.
+# Copyright 2012-2014 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -62,7 +62,14 @@ class test_pfb_synthesizer(gr_unittest.TestCase):
self.tb.connect(pfb, snk)
- self.tb.run()
+ self.tb.run()
+
+ # Adjusted phase rotations for data
+ p0 = 0
+ p1 = 2*math.pi*1.0/M
+ p2 = 2*math.pi*2.0/M
+ p3 = 2*math.pi*3.0/M
+ p4 = 2*math.pi*4.0/M
Ntest = 1000
L = len(snk.data())
@@ -73,20 +80,19 @@ class test_pfb_synthesizer(gr_unittest.TestCase):
freqs = [-2200, -1100, 0, 1100, 2200]
expected_data = len(t)*[0,]
for i in xrange(len(t)):
- expected_data[i] = math.cos(2.*math.pi*freqs[0]*t[i]) + \
- 1j*math.sin(2.*math.pi*freqs[0]*t[i]) + \
- math.cos(2.*math.pi*freqs[1]*t[i]) + \
- 1j*math.sin(2.*math.pi*freqs[1]*t[i]) + \
- math.cos(2.*math.pi*freqs[2]*t[i]) + \
- 1j*math.sin(2.*math.pi*freqs[2]*t[i]) + \
- math.cos(2.*math.pi*freqs[3]*t[i]) + \
- 1j*math.sin(2.*math.pi*freqs[3]*t[i]) + \
- math.cos(2.*math.pi*freqs[4]*t[i]) + \
- 1j*math.sin(2.*math.pi*freqs[4]*t[i])
+ expected_data[i] = math.cos(2.*math.pi*freqs[0]*t[i] + p3) + \
+ 1j*math.sin(2.*math.pi*freqs[0]*t[i] + p3) + \
+ math.cos(2.*math.pi*freqs[1]*t[i] + p4) + \
+ 1j*math.sin(2.*math.pi*freqs[1]*t[i] + p4) + \
+ math.cos(2.*math.pi*freqs[2]*t[i] + p0) + \
+ 1j*math.sin(2.*math.pi*freqs[2]*t[i] + p0) + \
+ math.cos(2.*math.pi*freqs[3]*t[i] + p1) + \
+ 1j*math.sin(2.*math.pi*freqs[3]*t[i] + p1) + \
+ math.cos(2.*math.pi*freqs[4]*t[i] + p2) + \
+ 1j*math.sin(2.*math.pi*freqs[4]*t[i] + p2)
dst_data = snk.data()
- offset = 25
-
self.assertComplexTuplesAlmostEqual(expected_data[2000-offset:2000-offset+Ntest],
+ self.assertComplexTuplesAlmostEqual(expected_data[2000:2000+Ntest],
dst_data[2000:2000+Ntest], 4)
if __name__ == '__main__':
- [Commit-gnuradio] [gnuradio] branch master updated (67882ee -> 103ca46), git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 01/06: blocks: allow subtract block to take a single input to invert the sign., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 06/06: Merge branch 'pfb_reconstruction', git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 02/06: blocks: allows null source/sink to output/input multiple streams., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 04/06: filter: use fft_filter inside pfb_decimator., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 05/06: filters: fixing up some minor issues with the analysis/synthesis filterbanks.,
git <=
- [Commit-gnuradio] [gnuradio] 03/06: filter: adds a ccf version of the fft filter., git, 2014/02/28