[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gnuradio-commit
Subject:    [Commit-gnuradio] [gnuradio] 05/06: filters: fixing up some minor issues with the analysis/synthesis
From:       git () gnuradio ! org
Date:       2014-02-28 16:53:15
Message-ID: 20140228165315.E8E931A8D34 () hertz ! gnuradio ! org
[Download RAW message or body]

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 <tom@trondeau.com>
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 mailing list
Commit-gnuradio@gnu.org
https://lists.gnu.org/mailman/listinfo/commit-gnuradio


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic