Merge branch 'pfbsr'
authorTom Rondeau <trondeau@vt.edu>
Thu, 15 Apr 2010 04:35:35 +0000 (00:35 -0400)
committerTom Rondeau <trondeau@vt.edu>
Thu, 15 Apr 2010 04:35:35 +0000 (00:35 -0400)
gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py
gnuradio-examples/python/pfb/channelize.py

index 7e34551c8ed4ce8e62ed4f85f4d33ddb28dad349..5fda47880f5cea77a62c54806f6bdd1c0a654468 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
 #include <cstring>
 
 gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, 
-                                                        const std::vector<float> &taps)
+                                                        const std::vector<float> &taps,
+                                                        float oversample_rate)
 {
-  return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps));
+  return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps,
+                                                                 oversample_rate));
 }
 
 
 gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans, 
-                                     const std::vector<float> &taps)
-  : gr_sync_block ("pfb_channelizer_ccf",
-                  gr_make_io_signature (numchans, numchans, sizeof(gr_complex)),
-                  gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))),
-    d_updated (false)
+                                               const std::vector<float> &taps,
+                                               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))),
+    d_updated (false), d_numchans(numchans), d_oversample_rate(oversample_rate)
 {
-  d_numchans = numchans;
+  // The over sampling rate must be rationally related to the number of channels
+  // in that it must be N/i for i in [1,N], which gives an outputsample rate 
+  // of [fs/N, fs] where fs is the input sample rate.
+  // This tests the specified input sample rate to see if it conforms to this
+  // requirement within a few significant figures.
+  double intp = 0;
+  double x = (10000.0*rint(numchans / oversample_rate)) / 10000.0;
+  double fltp = modf(numchans / oversample_rate, &intp);
+  if(fltp != 0.0)
+    throw std::invalid_argument("gr_pfb_channelizer: oversample rate must be N/i for i in [1, N]"); 
+
   d_filters = std::vector<gr_fir_ccf*>(d_numchans);
 
   // Create an FIR filter for each channel and zero out the taps
@@ -60,10 +73,28 @@ gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans,
 
   // Create the FFT to handle the output de-spinning of the channels
   d_fft = new gri_fft_complex (d_numchans, false);
+
+  // 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.
+  d_rate_ratio = (int)rintf(d_numchans / d_oversample_rate);
+  d_idxlut = new int[d_numchans];
+  for(unsigned int i = 0; i < d_numchans; i++) {
+    d_idxlut[i] = d_numchans - ((i + d_rate_ratio) % d_numchans) - 1;
+  }
+
+  // Calculate the number of filtering rounds to do to evenly
+  // align the input vectors with the output channels
+  d_output_multiple = 1;
+  while((d_output_multiple * d_rate_ratio) % d_numchans != 0)
+    d_output_multiple++;
+  set_output_multiple(d_output_multiple);
 }
 
 gr_pfb_channelizer_ccf::~gr_pfb_channelizer_ccf ()
 {
+  delete [] d_idxlut; 
+  
   for(unsigned int i = 0; i < d_numchans; i++) {
     delete d_filters[i];
   }
@@ -101,7 +132,7 @@ gr_pfb_channelizer_ccf::set_taps (const std::vector<float> &taps)
   }
 
   // Set the history to ensure enough input items for each filter
-  set_history (d_taps_per_filter);
+  set_history (d_taps_per_filter+1);
 
   d_updated = true;
 }
@@ -121,9 +152,10 @@ gr_pfb_channelizer_ccf::print_taps()
 
 
 int
-gr_pfb_channelizer_ccf::work (int noutput_items,
-                             gr_vector_const_void_star &input_items,
-                             gr_vector_void_star &output_items)
+gr_pfb_channelizer_ccf::general_work (int noutput_items,
+                                     gr_vector_int &ninput_items,
+                                     gr_vector_const_void_star &input_items,
+                                     gr_vector_void_star &output_items)
 {
   gr_complex *in = (gr_complex *) input_items[0];
   gr_complex *out = (gr_complex *) output_items[0];
@@ -133,20 +165,35 @@ gr_pfb_channelizer_ccf::work (int noutput_items,
     return 0;               // history requirements may have changed.
   }
 
-  for(int i = 0; i < noutput_items; i++) {
-    // Move through filters from bottom to top
-    for(int j = d_numchans-1; j >= 0; j--) {
-      // Take in the items from the first input stream to d_numchans
-      in = (gr_complex*)input_items[d_numchans - 1 - j];
+  int n=1, i=-1, j=0, last;
+  int toconsume = (int)rintf(noutput_items/d_oversample_rate);
+  while(n <= toconsume) {
+    j = 0;
+    i = (i + d_rate_ratio) % d_numchans;
+    last = i;
+    while(i >= 0) {
+      in = (gr_complex*)input_items[j];
+      d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n]);
+      j++;
+      i--;
+    }
 
-      // Filter current input stream from bottom filter to top
-      d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]);
+    i = d_numchans-1;
+    while(i > last) {
+      in = (gr_complex*)input_items[j];
+      d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]);
+      j++;
+      i--;
     }
 
+    n += (i+d_rate_ratio) >= (int)d_numchans;
+
     // despin through FFT
     d_fft->execute();
-    memcpy(&out[d_numchans*i], d_fft->get_outbuf(), d_numchans*sizeof(gr_complex));
+    memcpy(out, d_fft->get_outbuf(), d_numchans*sizeof(gr_complex));
+    out += d_numchans;
   }
-  
+
+  consume_each(toconsume);
   return noutput_items;
 }
index b2e67e8173a5558b16499698d4134d6da480c860..d56ccdbc6c3fca32b6cb86539b18cd82bb4f60fc 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
 #ifndef INCLUDED_GR_PFB_CHANNELIZER_CCF_H
 #define        INCLUDED_GR_PFB_CHANNELIZER_CCF_H
 
-#include <gr_sync_block.h>
+#include <gr_block.h>
 
 class gr_pfb_channelizer_ccf;
 typedef boost::shared_ptr<gr_pfb_channelizer_ccf> gr_pfb_channelizer_ccf_sptr;
 gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, 
-                                                        const std::vector<float> &taps);
+                                                        const std::vector<float> &taps,
+                                                        float oversample_rate=1);
 
 class gr_fir_ccf;
 class gri_fft_complex;
@@ -88,6 +89,19 @@ class gri_fft_complex;
  *      <B><EM>self._taps = gr.firdes.low_pass_2(1, fs, BW, TB, 
  *           attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
  *
+ * The filter output can also be overs ampled. The over sampling rate 
+ * is the ratio of the the actual output sampling rate to the normal 
+ * output sampling rate. It must be rationally related to the number 
+ * of channels as N/i for i in [1,N], which gives an outputsample rate
+ * of [fs/N, fs] where fs is the input sample rate and N is the number
+ * of channels.
+ *
+ * For example, for 6 channels with fs = 6000 Hz, the normal rate is 
+ * 6000/6 = 1000 Hz. Allowable oversampling rates are 6/6, 6/5, 6/4, 
+ * 6/3, 6/2, and 6/1 where the output sample rate of a 6/1 oversample
+ * ratio is 6000 Hz, or 6 times the normal 1000 Hz. A rate of 6/5 = 1.2,
+ * so the output rate would be 1200 Hz.
+ *
  * The theory behind this block can be found in Chapter 6 of 
  * the following book.
  *
@@ -96,23 +110,40 @@ class gri_fft_complex;
  *
  */
 
-class gr_pfb_channelizer_ccf : public gr_sync_block
+class gr_pfb_channelizer_ccf : public gr_block
 {
  private:
   /*!
    * Build the polyphase filterbank decimator.
    * \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM>
    * \param taps    (vector/list of floats) The prototype filter to populate the filterbank.
+   * \param oversample_rate (float)   The over sampling rate is the ratio of the the actual
+   *                                  output sampling rate to the normal output sampling rate.
+   *                                   It must be rationally related to the number of channels
+   *                                 as N/i for i in [1,N], which gives an outputsample rate 
+   *                                 of [fs/N, fs] where fs is the input sample rate and N is
+   *                                 the number of channels.
+   *                                 
+   *                                 For example, for 6 channels with fs = 6000 Hz, the normal
+   *                                 rate is 6000/6 = 1000 Hz. Allowable oversampling rates
+   *                                 are 6/6, 6/5, 6/4, 6/3, 6/2, and 6/1 where the output
+   *                                 sample rate of a 6/1 oversample ratio is 6000 Hz, or
+   *                                 6 times the normal 1000 Hz.
    */
   friend gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
-                                                                 const std::vector<float> &taps);
+                                                                 const std::vector<float> &taps,
+                                                                 float oversample_rate);
 
+  bool                    d_updated;
+  unsigned int             d_numchans;
+  float                    d_oversample_rate;
   std::vector<gr_fir_ccf*> d_filters;
   std::vector< std::vector<float> > d_taps;
-  gri_fft_complex         *d_fft;
-  unsigned int             d_numchans;
   unsigned int             d_taps_per_filter;
-  bool                    d_updated;
+  gri_fft_complex         *d_fft;
+  int                     *d_idxlut;
+  int                      d_rate_ratio;
+  int                      d_output_multiple;
 
   /*!
    * Build the polyphase filterbank decimator.
@@ -120,7 +151,8 @@ class gr_pfb_channelizer_ccf : public gr_sync_block
    * \param taps    (vector/list of floats) The prototype filter to populate the filterbank.
    */
   gr_pfb_channelizer_ccf (unsigned int numchans, 
-                         const std::vector<float> &taps);
+                         const std::vector<float> &taps,
+                         float oversample_rate);
 
 public:
   ~gr_pfb_channelizer_ccf ();
@@ -136,9 +168,10 @@ public:
    */
   void print_taps();
   
-  int work (int noutput_items,
-           gr_vector_const_void_star &input_items,
-           gr_vector_void_star &output_items);
+  int general_work (int noutput_items,
+                   gr_vector_int &ninput_items,
+                   gr_vector_const_void_star &input_items,
+                   gr_vector_void_star &output_items);
 };
 
 #endif
index 4bef90e2222b2b0609489dbe3a0da4bcabd60324..63e3e0fe6a45544af7e17cc44b94dfea3bb295e5 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
 GR_SWIG_BLOCK_MAGIC(gr,pfb_channelizer_ccf);
 
 gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
-                                                        const std::vector<float> &taps);
+                                                        const std::vector<float> &taps,
+                                                        float oversample_rate=1);
 
-class gr_pfb_channelizer_ccf : public gr_sync_block
+class gr_pfb_channelizer_ccf : public gr_block
 {
  private:
   gr_pfb_channelizer_ccf (unsigned int numchans,
-                         const std::vector<float> &taps);
+                         const std::vector<float> &taps,
+                         float oversample_rate);
 
  public:
   ~gr_pfb_channelizer_ccf ();
index c45ae4d1a95ced054a04ebdc37d72ae9d1097d1f..a479ed48ea9a357800fccd03dde273fccc3b69d3 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2009 Free Software Foundation, Inc.
+# Copyright 2009,2010 Free Software Foundation, Inc.
 # 
 # This file is part of GNU Radio
 # 
@@ -29,16 +29,18 @@ class pfb_channelizer_ccf(gr.hier_block2):
     This simplifies the interface by allowing a single input stream to connect to this block.
     It will then output a stream for each channel.
     '''
-    def __init__(self, numchans, taps):
+    def __init__(self, numchans, taps, oversample_rate=1):
        gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
                                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._taps = taps
+        self._oversample_rate = oversample_rate
 
         self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans)
-        self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps)
+        self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps,
+                                          self._oversample_rate)
         self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans)
 
         self.connect(self, self.s2ss)
index bc83fae2739615b4603c41118566199477dadd55..27d87e558b4ee37d2351423b0f8a3391eafc01d6 100755 (executable)
@@ -101,7 +101,7 @@ def main():
         X,freq = mlab.psd(d, NFFT=fftlen, noverlap=fftlen/4, Fs=fs,
                           window = lambda d: d*winfunc(fftlen),
                           scale_by_freq=True)
-        X_in = 10.0*scipy.log10(abs(fftpack.fftshift(X)))
+        X_in = 10.0*scipy.log10(abs(X))
         f_in = scipy.arange(-fs/2.0, fs/2.0, fs/float(X_in.size))
         pin_f = spin_f.plot(f_in, X_in, "b")
         spin_f.set_xlim([min(f_in), max(f_in)+1]) 
@@ -144,7 +144,7 @@ def main():
             X,freq = mlab.psd(d, NFFT=fftlen, noverlap=fftlen/4, Fs=fs_o,
                               window = lambda d: d*winfunc(fftlen),
                               scale_by_freq=True)
-            X_o = 10.0*scipy.log10(abs(fftpack.fftshift(X)))
+            X_o = 10.0*scipy.log10(abs(X))
             f_o = scipy.arange(-fs_o/2.0, fs_o/2.0, fs_o/float(X_o.size))
             p2_f = sp1_f.plot(f_o, X_o, "b")
             sp1_f.set_xlim([min(f_o), max(f_o)+1])