[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 06/10: filter: added a ccc version of the p
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 06/10: filter: added a ccc version of the pfb_arb_resampler block. |
Date: |
Tue, 11 Feb 2014 21:11:22 +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 f80ed7a1ce2396e954d42a47e80a57d8975fcc3a
Author: Tom Rondeau <address@hidden>
Date: Tue Feb 11 14:08:26 2014 -0500
filter: added a ccc version of the pfb_arb_resampler block.
---
gr-filter/grc/filter_pfb_arb_resampler.xml | 7 +
gr-filter/include/gnuradio/filter/CMakeLists.txt | 3 +-
.../include/gnuradio/filter/pfb_arb_resampler.h | 126 +++++++++++
.../gnuradio/filter/pfb_arb_resampler_ccc.h | 132 ++++++++++++
gr-filter/lib/CMakeLists.txt | 11 +-
gr-filter/lib/pfb_arb_resampler.cc | 231 ++++++++++++++++++++-
gr-filter/lib/pfb_arb_resampler_ccc_impl.cc | 183 ++++++++++++++++
gr-filter/lib/pfb_arb_resampler_ccc_impl.h | 75 +++++++
gr-filter/python/filter/pfb.py | 83 ++++++--
gr-filter/python/filter/qa_pfb_arb_resampler.py | 80 ++++++-
gr-filter/swig/filter_swig.i | 3 +
11 files changed, 900 insertions(+), 34 deletions(-)
diff --git a/gr-filter/grc/filter_pfb_arb_resampler.xml
b/gr-filter/grc/filter_pfb_arb_resampler.xml
index e163874..7bceeac 100644
--- a/gr-filter/grc/filter_pfb_arb_resampler.xml
+++ b/gr-filter/grc/filter_pfb_arb_resampler.xml
@@ -38,6 +38,13 @@
<opt>output:float</opt>
<opt>taps:real_vector</opt>
</option>
+ <option>
+ <name>Complex->Complex (Complex Taps)</name>
+ <key>ccc</key>
+ <opt>input:complex</opt>
+ <opt>output:complex</opt>
+ <opt>taps:complex_vector</opt>
+ </option>
</param>
<param>
<name>Resampling Rate</name>
diff --git a/gr-filter/include/gnuradio/filter/CMakeLists.txt
b/gr-filter/include/gnuradio/filter/CMakeLists.txt
index 3135688..d039af9 100644
--- a/gr-filter/include/gnuradio/filter/CMakeLists.txt
+++ b/gr-filter/include/gnuradio/filter/CMakeLists.txt
@@ -47,7 +47,7 @@ macro(expand_h root)
string(REGEX REPLACE "X+" ${sig} name ${root})
list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
endforeach(sig)
-
+
#create a command to generate the files
add_custom_command(
OUTPUT ${expanded_files_h}
@@ -103,6 +103,7 @@ install(FILES
iir_filter_ffd.h
pfb_arb_resampler.h
pfb_arb_resampler_ccf.h
+ pfb_arb_resampler_ccc.h
pfb_arb_resampler_fff.h
pfb_channelizer_ccf.h
pfb_decimator_ccf.h
diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
index 47f55ad..9ced0b3 100644
--- a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
+++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
@@ -217,6 +217,132 @@ namespace gr {
/**************************************************************/
+ class FILTER_API pfb_arb_resampler_ccc
+ {
+ private:
+ std::vector<fir_filter_ccc*> d_filters;
+ std::vector<fir_filter_ccc*> d_diff_filters;
+ std::vector< std::vector<gr_complex> > d_taps;
+ std::vector< std::vector<gr_complex> > d_dtaps;
+ unsigned int d_int_rate; // the number of filters
(interpolation rate)
+ unsigned int d_dec_rate; // the stride through the filters
(decimation rate)
+ float d_flt_rate; // residual rate for the linear
interpolation
+ float d_acc; // accumulator; holds fractional
part of sample
+ unsigned int d_last_filter; // stores filter for re-entry
+ unsigned int d_taps_per_filter; // num taps for each arm of the
filterbank
+ int d_delay; // filter's group delay
+ float d_est_phase_change; // est. of phase change of a sine
wave through filt.
+
+ /*!
+ * Takes in the taps and convolves them with [-1,0,1], which
+ * creates a differential set of taps that are used in the
+ * difference filterbank.
+ * \param newtaps (vector of complex) The prototype filter.
+ * \param difftaps (vector of complex) (out) The differential filter
taps.
+ */
+ void create_diff_taps(const std::vector<gr_complex> &newtaps,
+ std::vector<gr_complex> &difftaps);
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param newtaps (vector of complex) The prototype filter to
populate the filterbank.
+ * The taps should be generated at the interpolated
sampling rate.
+ * \param ourtaps (vector of complex) Reference to our internal
member of holding the taps.
+ * \param ourfilter (vector of ccc filters) Reference to our internal
filter to set the taps for.
+ */
+ void create_taps(const std::vector<gr_complex> &newtaps,
+ std::vector< std::vector<gr_complex> > &ourtaps,
+ std::vector<kernel::fir_filter_ccc*> &ourfilter);
+
+ public:
+ /*!
+ * Creates a kernel to perform arbitrary resampling on a set of
samples.
+ * \param rate (float) Specifies the resampling rate to use
+ * \param taps (vector/list of complex) The prototype filter to
populate the filterbank. The taps * should be generated at
the filter_size sampling rate.
+ * \param filter_size (unsigned int) The number of filters in the
filter bank. This is directly
+ * related to quantization noise introduced during
the resampling.
+ * Defaults to 32 filters.
+ */
+ pfb_arb_resampler_ccc(float rate,
+ const std::vector<gr_complex> &taps,
+ unsigned int filter_size);
+
+ ~pfb_arb_resampler_ccc();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of complex) The prototype filter to
populate the filterbank.
+ */
+ void set_taps(const std::vector<gr_complex> &taps);
+
+ /*!
+ * Return a vector<vector<>> of the filterbank taps
+ */
+ std::vector<std::vector<gr_complex> > taps() const;
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+
+ /*!
+ * Sets the resampling rate of the block.
+ */
+ void set_rate(float rate);
+
+ /*!
+ * Sets the current phase offset in radians (0 to 2pi).
+ */
+ void set_phase(float ph);
+
+ /*!
+ * Gets the current phase of the resampler in radians (2 to 2pi).
+ */
+ float phase() const;
+
+ /*!
+ * Gets the number of taps per filter.
+ */
+ unsigned int taps_per_filter() const;
+
+ unsigned int interpolation_rate() const { return d_int_rate; }
+ unsigned int decimation_rate() const { return d_dec_rate; }
+ float fractional_rate() const { return d_flt_rate; }
+
+ /*!
+ * Get the group delay of the filter.
+ */
+ int group_delay() const { return d_delay; }
+
+ /*!
+ * Calculates the phase offset expected by a sine wave of
+ * frequency \p freq and sampling rate \p fs (assuming input
+ * sine wave has 0 degree phase).
+ */
+ float phase_offset(float freq, float fs);
+
+ /*!
+ * Performs the filter operation that resamples the signal.
+ *
+ * This block takes in a stream of samples and outputs a
+ * resampled and filtered stream. This block should be called
+ * such that the output has \p rate * \p n_to_read amount of
+ * space available in the \p output buffer.
+ *
+ * \param input An input vector of samples to be resampled
+ * \param output The output samples at the new sample rate.
+ * \param n_to_read Number of samples to read from \p input.
+ * \param n_read (out) Number of samples actually read from \p input.
+ * \return Number of samples put into \p output.
+ */
+ int filter(gr_complex *input, gr_complex *output,
+ int n_to_read, int &n_read);
+ };
+
+
+ /**************************************************************/
+
+
/*!
* \brief Polyphase filterbank arbitrary resampler with
* float input, float output and float taps
diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h
b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h
new file mode 100644
index 0000000..c473846
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h
@@ -0,0 +1,132 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDED_PFB_ARB_RESAMPLER_CCC_H
+#define INCLUDED_PFB_ARB_RESAMPLER_CCC_H
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \brief Polyphase filterbank arbitrary resampler with
+ * gr_complex input, gr_complex output and gr_complex taps
+ * \ingroup resamplers_blk
+ *
+ * \details
+
+ * This block takes in a signal stream and calls
+ * gr::filter::kernel::pfb_arb_resampler_ccc to perform
+ * arbitrary resampling on the stream.
+ *
+ * Output sampling rate is \p rate * input rate.
+ */
+ class FILTER_API pfb_arb_resampler_ccc : virtual public block
+ {
+ public:
+ // gr::filter::pfb_arb_resampler_ccc::sptr
+ typedef boost::shared_ptr<pfb_arb_resampler_ccc> sptr;
+
+ /*!
+ * Build the polyphase filterbank arbitray resampler.
+ * \param rate (float) Specifies the resampling rate to use
+ * \param taps (vector/list of complex) The prototype filter to
populate the filterbank. The taps
+ * should be generated at the filter_size sampling rate.
+ * \param filter_size (unsigned int) The number of filters in the filter
bank. This is directly
+ * related to quantization noise introduced during
the resampling.
+ * Defaults to 32 filters.
+ */
+ static sptr make(float rate,
+ const std::vector<gr_complex> &taps,
+ unsigned int filter_size=32);
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of complex) The prototype filter to
populate the filterbank.
+ */
+ virtual void set_taps(const std::vector<gr_complex> &taps) = 0;
+
+ /*!
+ * Return a vector<vector<>> of the filterbank taps
+ */
+ virtual std::vector<std::vector<gr_complex> > taps() const = 0;
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ virtual void print_taps() = 0;
+
+ /*!
+ * Sets the resampling rate of the block.
+ */
+ virtual void set_rate (float rate) = 0;
+
+ /*!
+ * Sets the current phase offset in radians (0 to 2pi).
+ */
+ virtual void set_phase(float ph) = 0;
+
+ /*!
+ * Gets the current phase of the resampler in radians (2 to 2pi).
+ */
+ virtual float phase() const = 0;
+
+ /*!
+ * Gets the number of taps per filter.
+ */
+ virtual unsigned int taps_per_filter() const = 0;
+
+ /*!
+ * Gets the interpolation rate of the filter.
+ */
+ virtual unsigned int interpolation_rate() const = 0;
+
+ /*!
+ * Gets the decimation rate of the filter.
+ */
+ virtual unsigned int decimation_rate() const =0;
+
+ /*!
+ * Gets the fractional rate of the filter.
+ */
+ virtual float fractional_rate() const = 0;
+
+ /*!
+ * Get the group delay of the filter.
+ */
+ virtual int group_delay() const = 0;
+
+ /*!
+ * Calculates the phase offset expected by a sine wave of
+ * frequency \p freq and sampling rate \p fs (assuming input
+ * sine wave has 0 degree phase).
+ */
+ virtual float phase_offset(float freq, float fs) = 0;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_PFB_ARB_RESAMPLER_CCC_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 58000bb..9f17092 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -48,7 +48,7 @@ macro(expand_cc root)
list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc)
list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
endforeach(sig)
-
+
#create a command to generate the source files
add_custom_command(
OUTPUT ${expanded_files_cc}
@@ -66,15 +66,15 @@ macro(expand_cc root)
${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
${root} ${root}.h.t ${ARGN}
)
-
+
#make source files depends on headers to force generation
set_source_files_properties(${expanded_files_cc}
PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
)
-
+
#install rules for the generated cc files
- list(APPEND generated_sources ${expanded_files_cc})
- list(APPEND generated_headers ${expanded_files_h})
+ list(APPEND generated_sources ${expanded_files_cc})
+ list(APPEND generated_headers ${expanded_files_h})
endmacro(expand_cc)
########################################################################
@@ -137,6 +137,7 @@ list(APPEND filter_sources
iir_filter_ffd_impl.cc
pfb_arb_resampler.cc
pfb_arb_resampler_ccf_impl.cc
+ pfb_arb_resampler_ccc_impl.cc
pfb_arb_resampler_fff_impl.cc
pfb_channelizer_ccf_impl.cc
pfb_decimator_ccf_impl.cc
diff --git a/gr-filter/lib/pfb_arb_resampler.cc
b/gr-filter/lib/pfb_arb_resampler.cc
index 541f1a9..0ebc788 100644
--- a/gr-filter/lib/pfb_arb_resampler.cc
+++ b/gr-filter/lib/pfb_arb_resampler.cc
@@ -33,7 +33,7 @@
namespace gr {
namespace filter {
namespace kernel {
-
+
pfb_arb_resampler_ccf::pfb_arb_resampler_ccf(float rate,
const std::vector<float>
&taps,
unsigned int filter_size)
@@ -53,7 +53,7 @@ namespace gr {
set_rate(rate);
d_last_filter = (taps.size()/2) % filter_size;
-
+
d_filters = std::vector<fir_filter_ccf*>(d_int_rate);
d_diff_filters = std::vector<fir_filter_ccf*>(d_int_rate);
@@ -153,7 +153,7 @@ namespace gr {
create_taps(taps, d_taps, d_filters);
create_taps(dtaps, d_dtaps, d_diff_filters);
}
-
+
std::vector<std::vector<float> >
pfb_arb_resampler_ccf::taps() const
{
@@ -186,7 +186,7 @@ namespace gr {
if((ph < 0) || (ph >= 2.0*M_PI)) {
throw std::runtime_error("pfb_arb_resampler_ccf: set_phase value out
of bounds [0, 2pi).\n");
}
-
+
float ph_diff = 2.0*M_PI / (float)d_filters.size();
d_last_filter = static_cast<int>(ph / ph_diff);
}
@@ -218,7 +218,7 @@ namespace gr {
int i_out = 0, i_in = 0;
unsigned int j = d_last_filter;;
gr_complex o0, o1;
-
+
while(i_in < n_to_read) {
// start j by wrapping around mod the number of channels
while(j < d_int_rate) {
@@ -242,7 +242,218 @@ namespace gr {
n_read = i_in; // return how much we've actually read
return i_out; // return how much we've produced
}
-
+
+ /****************************************************************/
+
+ pfb_arb_resampler_ccc::pfb_arb_resampler_ccc(float rate,
+ const
std::vector<gr_complex> &taps,
+ unsigned int filter_size)
+ {
+ d_acc = 0; // start accumulator at 0
+
+ /* The number of filters is specified by the user as the
+ filter size; this is also the interpolation rate of the
+ filter. We use it and the rate provided to determine the
+ decimation rate. This acts as a rational resampler. The
+ flt_rate is calculated as the residual between the integer
+ decimation rate and the real decimation rate and will be
+ used to determine to interpolation point of the resampling
+ process.
+ */
+ d_int_rate = filter_size;
+ set_rate(rate);
+
+ d_last_filter = (taps.size()/2) % filter_size;
+
+ d_filters = std::vector<fir_filter_ccc*>(d_int_rate);
+ d_diff_filters = std::vector<fir_filter_ccc*>(d_int_rate);
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<gr_complex> vtaps(0, d_int_rate);
+ for(unsigned int i = 0; i < d_int_rate; i++) {
+ d_filters[i] = new fir_filter_ccc(1, vtaps);
+ d_diff_filters[i] = new fir_filter_ccc(1, vtaps);
+ }
+
+ // Now, actually set the filters' taps
+ set_taps(taps);
+
+ // Delay is based on number of taps per filter arm. Round to
+ // the nearest integer.
+ float delay = -rate * (taps_per_filter() - 1.0) / 2.0;
+ d_delay = static_cast<int>(boost::math::iround(delay));
+
+ // This calculation finds the phase offset induced by the
+ // arbitrary resampling. It's based on which filter arm we are
+ // at the filter's group delay plus the fractional offset
+ // between the samples. Calculated here based on the rotation
+ // around nfilts starting at start_filter.
+ float accum = -d_delay * d_flt_rate;
+ int accum_int = static_cast<int>(accum);
+ float accum_frac = accum - accum_int;
+ int end_filter = static_cast<int>
+ (boost::math::iround(fmodf(d_last_filter - d_delay * d_dec_rate +
accum_int, \
+ static_cast<float>(d_int_rate))));
+
+ d_est_phase_change = d_last_filter - (end_filter + accum_frac);
+ }
+
+ pfb_arb_resampler_ccc::~pfb_arb_resampler_ccc()
+ {
+ for(unsigned int i = 0; i < d_int_rate; i++) {
+ delete d_filters[i];
+ delete d_diff_filters[i];
+ }
+ }
+
+ void
+ pfb_arb_resampler_ccc::create_taps(const std::vector<gr_complex>
&newtaps,
+ std::vector< std::vector<gr_complex>
> &ourtaps,
+ std::vector<fir_filter_ccc*>
&ourfilter)
+ {
+ unsigned int ntaps = newtaps.size();
+ d_taps_per_filter = (unsigned
int)ceil((double)ntaps/(double)d_int_rate);
+
+ // Create d_numchan vectors to store each channel's taps
+ ourtaps.resize(d_int_rate);
+
+ // 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<gr_complex> tmp_taps;
+ tmp_taps = newtaps;
+ while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ for(unsigned int i = 0; i < d_int_rate; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough
taps to fill out
+ ourtaps[i] = std::vector<gr_complex>(d_taps_per_filter, 0);
+ for(unsigned int j = 0; j < d_taps_per_filter; j++) {
+ ourtaps[i][j] = tmp_taps[i + j*d_int_rate];
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ ourfilter[i]->set_taps(ourtaps[i]);
+ }
+ }
+
+ void
+ pfb_arb_resampler_ccc::create_diff_taps(const std::vector<gr_complex>
&newtaps,
+ std::vector<gr_complex>
&difftaps)
+ {
+ // Calculate the differential taps using a derivative filter
+ std::vector<gr_complex> diff_filter(2);
+ diff_filter[0] = -1;
+ diff_filter[1] = 1;
+
+ for(unsigned int i = 0; i < newtaps.size()-1; i++) {
+ gr_complex tap = 0;
+ for(unsigned int j = 0; j < diff_filter.size(); j++) {
+ tap += diff_filter[j]*newtaps[i+j];
+ }
+ difftaps.push_back(tap);
+ }
+ difftaps.push_back(0);
+ }
+
+ void
+ pfb_arb_resampler_ccc::set_taps(const std::vector<gr_complex> &taps)
+ {
+ std::vector<gr_complex> dtaps;
+ create_diff_taps(taps, dtaps);
+ create_taps(taps, d_taps, d_filters);
+ create_taps(dtaps, d_dtaps, d_diff_filters);
+ }
+
+ std::vector<std::vector<gr_complex> >
+ pfb_arb_resampler_ccc::taps() const
+ {
+ return d_taps;
+ }
+
+ void
+ pfb_arb_resampler_ccc::print_taps()
+ {
+ unsigned int i, j;
+ for(i = 0; i < d_int_rate; i++) {
+ printf("filter[%d]: [", i);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ printf(" %.4e + j%.4e", d_taps[i][j].real(), d_taps[i][j].imag());
+ }
+ printf("]\n");
+ }
+ }
+
+ void
+ pfb_arb_resampler_ccc::set_rate(float rate)
+ {
+ d_dec_rate = (unsigned int)floor(d_int_rate/rate);
+ d_flt_rate = (d_int_rate/rate) - d_dec_rate;
+ }
+
+ void
+ pfb_arb_resampler_ccc::set_phase(float ph)
+ {
+ if((ph < 0) || (ph >= 2.0*M_PI)) {
+ throw std::runtime_error("pfb_arb_resampler_ccc: set_phase value out
of bounds [0, 2pi).\n");
+ }
+
+ float ph_diff = 2.0*M_PI / (float)d_filters.size();
+ d_last_filter = static_cast<int>(ph / ph_diff);
+ }
+
+ float
+ pfb_arb_resampler_ccc::phase() const
+ {
+ float ph_diff = 2.0*M_PI / static_cast<float>(d_filters.size());
+ return d_last_filter * ph_diff;
+ }
+
+ unsigned int
+ pfb_arb_resampler_ccc::taps_per_filter() const
+ {
+ return d_taps_per_filter;
+ }
+
+ float
+ pfb_arb_resampler_ccc::phase_offset(float freq, float fs)
+ {
+ float adj = (2.0*M_PI)*(freq/fs)/static_cast<float>(d_int_rate);
+ return -adj * d_est_phase_change;
+ }
+
+ int
+ pfb_arb_resampler_ccc::filter(gr_complex *output, gr_complex *input,
+ int n_to_read, int &n_read)
+ {
+ int i_out = 0, i_in = 0;
+ unsigned int j = d_last_filter;;
+ gr_complex o0, o1;
+
+ while(i_in < n_to_read) {
+ // start j by wrapping around mod the number of channels
+ while(j < d_int_rate) {
+ // Take the current filter and derivative filter output
+ o0 = d_filters[j]->filter(&input[i_in]);
+ o1 = d_diff_filters[j]->filter(&input[i_in]);
+
+ output[i_out] = o0 + o1*d_acc; // linearly interpolate between
samples
+ i_out++;
+
+ // Adjust accumulator and index into filterbank
+ d_acc += d_flt_rate;
+ j += d_dec_rate + (int)floor(d_acc);
+ d_acc = fmodf(d_acc, 1.0);
+ }
+ i_in += (int)(j / d_int_rate);
+ j = j % d_int_rate;
+ }
+ d_last_filter = j; // save last filter state for re-entry
+
+ n_read = i_in; // return how much we've actually read
+ return i_out; // return how much we've produced
+ }
+
/****************************************************************/
pfb_arb_resampler_fff::pfb_arb_resampler_fff(float rate,
@@ -264,7 +475,7 @@ namespace gr {
set_rate(rate);
d_last_filter = (taps.size()/2) % filter_size;
-
+
d_filters = std::vector<fir_filter_fff*>(d_int_rate);
d_diff_filters = std::vector<fir_filter_fff*>(d_int_rate);
@@ -364,7 +575,7 @@ namespace gr {
create_taps(taps, d_taps, d_filters);
create_taps(dtaps, d_dtaps, d_diff_filters);
}
-
+
std::vector<std::vector<float> >
pfb_arb_resampler_fff::taps() const
{
@@ -397,7 +608,7 @@ namespace gr {
if((ph < 0) || (ph >= 2.0*M_PI)) {
throw std::runtime_error("pfb_arb_resampler_fff: set_phase value out
of bounds [0, 2pi).\n");
}
-
+
float ph_diff = 2.0*M_PI / (float)d_filters.size();
d_last_filter = static_cast<int>(ph / ph_diff);
}
@@ -429,7 +640,7 @@ namespace gr {
int i_out = 0, i_in = 0;
unsigned int j = d_last_filter;;
float o0, o1;
-
+
while(i_in < n_to_read) {
// start j by wrapping around mod the number of channels
while(j < d_int_rate) {
diff --git a/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc
b/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc
new file mode 100644
index 0000000..3437524
--- /dev/null
+++ b/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc
@@ -0,0 +1,183 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pfb_arb_resampler_ccc_impl.h"
+#include <gnuradio/io_signature.h>
+#include <cstdio>
+
+namespace gr {
+ namespace filter {
+
+ pfb_arb_resampler_ccc::sptr
+ pfb_arb_resampler_ccc::make(float rate,
+ const std::vector<gr_complex> &taps,
+ unsigned int filter_size)
+ {
+ return gnuradio::get_initial_sptr
+ (new pfb_arb_resampler_ccc_impl(rate, taps, filter_size));
+ }
+
+
+ pfb_arb_resampler_ccc_impl::pfb_arb_resampler_ccc_impl(float rate,
+ const
std::vector<gr_complex> &taps,
+ unsigned int
filter_size)
+ : block("pfb_arb_resampler_ccc",
+ io_signature::make(1, 1, sizeof(gr_complex)),
+ io_signature::make(1, 1, sizeof(gr_complex)))
+ {
+ d_updated = false;
+
+ d_resamp = new kernel::pfb_arb_resampler_ccc(rate, taps, filter_size);
+ set_history(d_resamp->taps_per_filter());
+ set_relative_rate(rate);
+ }
+
+ pfb_arb_resampler_ccc_impl::~pfb_arb_resampler_ccc_impl()
+ {
+ delete d_resamp;
+ }
+
+ void
+ pfb_arb_resampler_ccc_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ unsigned ninputs = ninput_items_required.size();
+ if(noutput_items / relative_rate() < 1) {
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = relative_rate() + history() - 1;
+ }
+ else {
+ for(unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = noutput_items/relative_rate() + history()
- 1;
+ }
+ }
+
+ void
+ pfb_arb_resampler_ccc_impl::set_taps(const std::vector<gr_complex> &taps)
+ {
+ gr::thread::scoped_lock guard(d_mutex);
+
+ d_resamp->set_taps(taps);
+ set_history(d_resamp->taps_per_filter());
+ d_updated = true;
+ }
+
+ std::vector<std::vector<gr_complex> >
+ pfb_arb_resampler_ccc_impl::taps() const
+ {
+ return d_resamp->taps();
+ }
+
+ void
+ pfb_arb_resampler_ccc_impl::print_taps()
+ {
+ d_resamp->print_taps();
+ }
+
+ void
+ pfb_arb_resampler_ccc_impl::set_rate(float rate)
+ {
+ gr::thread::scoped_lock guard(d_mutex);
+
+ d_resamp->set_rate(rate);
+ set_relative_rate(rate);
+ }
+
+ void
+ pfb_arb_resampler_ccc_impl::set_phase(float ph)
+ {
+ gr::thread::scoped_lock guard(d_mutex);
+ d_resamp->set_phase(ph);
+ }
+
+ float
+ pfb_arb_resampler_ccc_impl::phase() const
+ {
+ return d_resamp->phase();
+ }
+
+ unsigned int
+ pfb_arb_resampler_ccc_impl::interpolation_rate() const
+ {
+ return d_resamp->interpolation_rate();
+ }
+
+ unsigned int
+ pfb_arb_resampler_ccc_impl::decimation_rate() const
+ {
+ return d_resamp->decimation_rate();
+ }
+
+ float
+ pfb_arb_resampler_ccc_impl::fractional_rate() const
+ {
+ return d_resamp->fractional_rate();
+ }
+
+ unsigned int
+ pfb_arb_resampler_ccc_impl::taps_per_filter() const
+ {
+ return d_resamp->taps_per_filter();
+ }
+
+ int
+ pfb_arb_resampler_ccc_impl::group_delay() const
+ {
+ return d_resamp->group_delay();
+ }
+
+ float
+ pfb_arb_resampler_ccc_impl::phase_offset(float freq, float fs)
+ {
+ return d_resamp->phase_offset(freq, fs);
+ }
+
+ int
+ pfb_arb_resampler_ccc_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_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];
+
+ if(d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ int nitems_read;
+ int nitems = floorf((float)noutput_items / relative_rate());
+ int processed = d_resamp->filter(out, in, nitems, nitems_read);
+
+ consume_each(nitems_read);
+ return processed;
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/pfb_arb_resampler_ccc_impl.h
b/gr-filter/lib/pfb_arb_resampler_ccc_impl.h
new file mode 100644
index 0000000..b4ad6dd
--- /dev/null
+++ b/gr-filter/lib/pfb_arb_resampler_ccc_impl.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H
+#define INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H
+
+#include <gnuradio/filter/pfb_arb_resampler_ccc.h>
+#include <gnuradio/filter/pfb_arb_resampler.h>
+#include <gnuradio/thread/thread.h>
+
+namespace gr {
+ namespace filter {
+
+ class FILTER_API pfb_arb_resampler_ccc_impl : public pfb_arb_resampler_ccc
+ {
+ private:
+ kernel::pfb_arb_resampler_ccc *d_resamp;
+ bool d_updated;
+ gr::thread::mutex d_mutex; // mutex to protect set/work access
+
+ public:
+ pfb_arb_resampler_ccc_impl(float rate,
+ const std::vector<gr_complex> &taps,
+ unsigned int filter_size);
+
+ ~pfb_arb_resampler_ccc_impl();
+
+ void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ void set_taps(const std::vector<gr_complex> &taps);
+ std::vector<std::vector<gr_complex> > taps() const;
+ void print_taps();
+
+ void set_rate(float rate);
+ void set_phase(float ph);
+ float phase() const;
+
+ unsigned int interpolation_rate() const;
+ unsigned int decimation_rate() const;
+ float fractional_rate() const;
+ unsigned int taps_per_filter() const;
+
+ int group_delay() const;
+ float phase_offset(float freq, float fs);
+
+ int general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H */
diff --git a/gr-filter/python/filter/pfb.py b/gr-filter/python/filter/pfb.py
index 2ddf659..7f7375c 100644
--- a/gr-filter/python/filter/pfb.py
+++ b/gr-filter/python/filter/pfb.py
@@ -37,9 +37,9 @@ class channelizer_ccf(gr.hier_block2):
It will then output a stream for each channel.
'''
def __init__(self, numchans, taps=None, oversample_rate=1, atten=100):
- gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
- gr.io_signature(1, 1, gr.sizeof_gr_complex),
- gr.io_signature(numchans, numchans,
gr.sizeof_gr_complex))
+ gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex),
+ gr.io_signature(numchans, numchans,
gr.sizeof_gr_complex))
self._nchans = numchans
self._oversample_rate = oversample_rate
@@ -89,9 +89,9 @@ class interpolator_ccf(gr.hier_block2):
other PFB block.
'''
def __init__(self, interp, taps=None, atten=100):
- gr.hier_block2.__init__(self, "pfb_interpolator_ccf",
- gr.io_signature(1, 1, gr.sizeof_gr_complex),
- gr.io_signature(1, 1, gr.sizeof_gr_complex))
+ gr.hier_block2.__init__(self, "pfb_interpolator_ccf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex))
self._interp = interp
self._taps = taps
@@ -131,9 +131,9 @@ class decimator_ccf(gr.hier_block2):
It will then output a stream that is the decimated output stream.
'''
def __init__(self, decim, taps=None, channel=0, atten=100):
- gr.hier_block2.__init__(self, "pfb_decimator_ccf",
- gr.io_signature(1, 1, gr.sizeof_gr_complex),
- gr.io_signature(1, 1, gr.sizeof_gr_complex))
+ gr.hier_block2.__init__(self, "pfb_decimator_ccf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex),
+ gr.io_signature(1, 1, gr.sizeof_gr_complex))
self._decim = decim
self._channel = channel
@@ -186,9 +186,9 @@ class arb_resampler_ccf(gr.hier_block2):
other PFB block.
'''
def __init__(self, rate, taps=None, flt_size=32, atten=100):
- gr.hier_block2.__init__(self, "pfb_arb_resampler_ccf",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), #
Input signature
- gr.io_signature(1, 1, gr.sizeof_gr_complex)) #
Output signature
+ gr.hier_block2.__init__(self, "pfb_arb_resampler_ccf",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), #
Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) #
Output signature
self._rate = rate
self._size = flt_size
@@ -239,9 +239,9 @@ class arb_resampler_fff(gr.hier_block2):
other PFB block.
'''
def __init__(self, rate, taps=None, flt_size=32, atten=100):
- gr.hier_block2.__init__(self, "pfb_arb_resampler_fff",
- gr.io_signature(1, 1, gr.sizeof_float), # Input
signature
- gr.io_signature(1, 1, gr.sizeof_float)) #
Output signature
+ gr.hier_block2.__init__(self, "pfb_arb_resampler_fff",
+ gr.io_signature(1, 1, gr.sizeof_float), #
Input signature
+ gr.io_signature(1, 1, gr.sizeof_float)) #
Output signature
self._rate = rate
self._size = flt_size
@@ -280,3 +280,56 @@ class arb_resampler_fff(gr.hier_block2):
def set_rate(self, rate):
self.pfb.set_rate(rate)
+
+
+class arb_resampler_ccc(gr.hier_block2):
+ '''
+ Convenience wrapper for the polyphase filterbank arbitrary resampler.
+
+ The block takes a single complex stream in and outputs a single complex
+ stream out. As such, it requires no extra glue to handle the input/output
+ streams. This block is provided to be consistent with the interface to the
+ other PFB block.
+ '''
+ def __init__(self, rate, taps=None, flt_size=32, atten=100):
+ gr.hier_block2.__init__(self, "pfb_arb_resampler_ccc",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), #
Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) #
Output signature
+
+ self._rate = rate
+ self._size = flt_size
+
+ if (taps is not None) and (len(taps) > 0):
+ self._taps = taps
+ else:
+ # Create a filter that covers the full bandwidth of the input
signal
+ bw = 0.4
+ tb = 0.2
+ ripple = 0.1
+ #self._taps = filter.firdes.low_pass_2(self._size, self._size, bw,
tb, atten)
+ made = False
+ while not made:
+ try:
+ self._taps = optfir.low_pass(self._size, self._size, bw,
bw+tb, ripple, atten)
+ made = True
+ except RuntimeError:
+ ripple += 0.01
+ made = False
+ print("Warning: set ripple to %.4f dB. If this is a
problem, adjust the attenuation or create your own filter taps." % (ripple))
+
+ # Build in an exit strategy; if we've come this far, it
ain't working.
+ if(ripple >= 1.0):
+ raise RuntimeError("optfir could not generate an
appropriate filter.")
+
+ self.pfb = filter.pfb_arb_resampler_ccc(self._rate, self._taps,
self._size)
+ #print "PFB has %d taps\n" % (len(self._taps),)
+
+ self.connect(self, self.pfb)
+ self.connect(self.pfb, self)
+
+ # Note -- set_taps not implemented in base class yet
+ def set_taps(self, taps):
+ self.pfb.set_taps(taps)
+
+ def set_rate(self, rate):
+ self.pfb.set_rate(rate)
diff --git a/gr-filter/python/filter/qa_pfb_arb_resampler.py
b/gr-filter/python/filter/qa_pfb_arb_resampler.py
index bdc54b3..9dbef7d 100755
--- a/gr-filter/python/filter/qa_pfb_arb_resampler.py
+++ b/gr-filter/python/filter/qa_pfb_arb_resampler.py
@@ -59,7 +59,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
snk = blocks.vector_sink_f()
self.tb.connect(signal, pfb, snk)
- self.tb.run()
+ self.tb.run()
Ntest = 50
L = len(snk.data())
@@ -67,7 +67,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
# Get group delay and estimate of phase offset from the filter itself.
delay = pfb.group_delay()
phase = pfb.phase_offset(freq, fs)
-
+
# Create a timeline offset by the filter's group delay
t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
@@ -93,7 +93,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
signal = blocks.vector_source_c(data)
pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts)
snk = blocks.vector_sink_c()
-
+
self.tb.connect(signal, pfb, snk)
self.tb.run()
@@ -152,5 +152,79 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:],
dst_data[-Ntest:], 2)
+ def test_ccc_000(self):
+ N = 5000 # number of samples to use
+ fs = 5000.0 # baseband sampling rate
+ rrate = 3.4321 # resampling rate
+
+ nfilts = 32
+ taps = filter.firdes.complex_band_pass_2(nfilts, nfilts*fs, 50, 400,
fs/10,
+ attenuation_dB=80,
+
window=filter.firdes.WIN_BLACKMAN_hARRIS)
+
+ freq = 211.123
+ data = sig_source_c(fs, freq, 1, N)
+ signal = blocks.vector_source_c(data)
+ pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts)
+ snk = blocks.vector_sink_c()
+
+ self.tb.connect(signal, pfb, snk)
+ self.tb.run()
+
+ Ntest = 50
+ L = len(snk.data())
+
+ # Get group delay and estimate of phase offset from the filter itself.
+ delay = pfb.group_delay()
+ phase = pfb.phase_offset(freq, fs)
+
+ # Create a timeline offset by the filter's group delay
+ t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
+
+ # Data of the sinusoid at frequency freq with the delay and phase
offset.
+ expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \
+ 1j*math.sin(2.*math.pi*freq*x+phase), t)
+
+ dst_data = snk.data()
+
+ self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:],
dst_data[-Ntest:], 2)
+
+ def test_ccc_001(self):
+ N = 50000 # number of samples to use
+ fs = 5000.0 # baseband sampling rate
+ rrate = 0.715 # resampling rate
+
+ nfilts = 32
+ taps = filter.firdes.complex_band_pass_2(nfilts, nfilts*fs, 50, 400,
fs/10,
+ attenuation_dB=80,
+
window=filter.firdes.WIN_BLACKMAN_hARRIS)
+
+ freq = 211.123
+ data = sig_source_c(fs, freq, 1, N)
+ signal = blocks.vector_source_c(data)
+ pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts)
+ snk = blocks.vector_sink_c()
+
+ self.tb.connect(signal, pfb, snk)
+ self.tb.run()
+
+ Ntest = 50
+ L = len(snk.data())
+
+ # Get group delay and estimate of phase offset from the filter itself.
+ delay = pfb.group_delay()
+ phase = pfb.phase_offset(freq, fs)
+
+ # Create a timeline offset by the filter's group delay
+ t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
+
+ # Data of the sinusoid at frequency freq with the delay and phase
offset.
+ expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \
+ 1j*math.sin(2.*math.pi*freq*x+phase), t)
+
+ dst_data = snk.data()
+
+ self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:],
dst_data[-Ntest:], 2)
+
if __name__ == '__main__':
gr_unittest.run(test_pfb_arb_resampler, "test_pfb_arb_resampler.xml")
diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i
index aad96e5..bc9f204 100644
--- a/gr-filter/swig/filter_swig.i
+++ b/gr-filter/swig/filter_swig.i
@@ -60,6 +60,7 @@
#include "gnuradio/filter/interp_fir_filter_fsf.h"
#include "gnuradio/filter/interp_fir_filter_scc.h"
#include "gnuradio/filter/pfb_arb_resampler_ccf.h"
+#include "gnuradio/filter/pfb_arb_resampler_ccc.h"
#include "gnuradio/filter/pfb_arb_resampler_fff.h"
#include "gnuradio/filter/pfb_channelizer_ccf.h"
#include "gnuradio/filter/pfb_decimator_ccf.h"
@@ -107,6 +108,7 @@
%include "gnuradio/filter/interp_fir_filter_fsf.h"
%include "gnuradio/filter/interp_fir_filter_scc.h"
%include "gnuradio/filter/pfb_arb_resampler_ccf.h"
+%include "gnuradio/filter/pfb_arb_resampler_ccc.h"
%include "gnuradio/filter/pfb_arb_resampler_fff.h"
%include "gnuradio/filter/pfb_channelizer_ccf.h"
%include "gnuradio/filter/pfb_decimator_ccf.h"
@@ -151,6 +153,7 @@ GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fff);
GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fsf);
GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_scc);
GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_ccf);
+GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_ccc);
GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_fff);
GR_SWIG_BLOCK_MAGIC2(filter, pfb_channelizer_ccf);
GR_SWIG_BLOCK_MAGIC2(filter, pfb_decimator_ccf);
- [Commit-gnuradio] [gnuradio] branch master updated (19d111e -> 295ba35), git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 03/10: Fixed other issues with app - changes to fft display - still missing 'tune on click', git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 06/10: filter: added a ccc version of the pfb_arb_resampler block.,
git <=
- [Commit-gnuradio] [gnuradio] 02/10: update README, git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 04/10: fixed click to tune, click mouse on fft display will tune to that frequency, git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 05/10: Merge remote-tracking branch 'cswiger/master' into hfx, git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 07/10: uhd: hf_explorer example: Added some more options for better handling of rates., git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 08/10: Merge branch 'maint', git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 10/10: filter: fixed use of volk_malloc in fft_filter kernel., git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 09/10: qtgui: in sink_c and sink_f, use volk_malloc/volk_free instead of new for buffers., git, 2014/02/11
- [Commit-gnuradio] [gnuradio] 01/10: fixing hfx.py for proper uhd support - tuning was negative of desired change, removed antenna tuner support, git, 2014/02/11