summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormormj <mormjb@gmail.com>2020-11-18 10:10:17 -0500
committermormj <34754695+mormj@users.noreply.github.com>2020-12-17 08:30:02 -0500
commit436e40867e05274f58cdff778da7d520cd100809 (patch)
tree17c512979d5c09682c97829b98c08971f83eb7a4
parentdf01f13a0cea8899a49b8f6edbd089741f1135c5 (diff)
filter: replace rational_resampler_base with rational_resampler
The bulk of the rational resampler code is named rational_resampler_base and only in Python is the automatic designing of filters if taps are not specified. This pushes that code into the C++ classes (which get binded) so rational_resampler.py can go away, removing a layer of wrapping
-rw-r--r--gr-filter/grc/CMakeLists.txt1
-rw-r--r--gr-filter/grc/filter.tree.yml1
-rw-r--r--gr-filter/grc/filter_rational_resampler_base_xxx.block.yml47
-rw-r--r--gr-filter/grc/filter_rational_resampler_xxx.block.yml50
-rw-r--r--gr-filter/include/gnuradio/filter/CMakeLists.txt2
-rw-r--r--gr-filter/include/gnuradio/filter/rational_resampler.h (renamed from gr-filter/include/gnuradio/filter/rational_resampler_base.h)32
-rw-r--r--gr-filter/lib/CMakeLists.txt2
-rw-r--r--gr-filter/lib/rational_resampler_base_impl.cc166
-rw-r--r--gr-filter/lib/rational_resampler_impl.cc263
-rw-r--r--gr-filter/lib/rational_resampler_impl.h (renamed from gr-filter/lib/rational_resampler_base_impl.h)24
-rw-r--r--gr-filter/python/filter/CMakeLists.txt1
-rw-r--r--gr-filter/python/filter/__init__.py1
-rw-r--r--gr-filter/python/filter/bindings/CMakeLists.txt2
-rw-r--r--gr-filter/python/filter/bindings/docstrings/rational_resampler_pydoc_template.h (renamed from gr-filter/python/filter/bindings/docstrings/rational_resampler_base_pydoc_template.h)0
-rw-r--r--gr-filter/python/filter/bindings/python_bindings.cc4
-rw-r--r--gr-filter/python/filter/bindings/rational_resampler_base_python.cc63
-rw-r--r--gr-filter/python/filter/bindings/rational_resampler_python.cc62
-rw-r--r--gr-filter/python/filter/qa_rational_resampler.py14
-rw-r--r--gr-filter/python/filter/rational_resampler.py145
19 files changed, 385 insertions, 495 deletions
diff --git a/gr-filter/grc/CMakeLists.txt b/gr-filter/grc/CMakeLists.txt
index 706a9b49c3..61ef4f11c4 100644
--- a/gr-filter/grc/CMakeLists.txt
+++ b/gr-filter/grc/CMakeLists.txt
@@ -29,7 +29,6 @@ install(FILES
filter_pfb_interpolator.block.yml
filter_pfb_synthesizer.block.yml
filter_rational_resampler_xxx.block.yml
- filter_rational_resampler_base_xxx.block.yml
filter_single_pole_iir_filter_xx.block.yml
filter_low_pass_filter.block.yml
filter_high_pass_filter.block.yml
diff --git a/gr-filter/grc/filter.tree.yml b/gr-filter/grc/filter.tree.yml
index 098e413d33..a297ba63f7 100644
--- a/gr-filter/grc/filter.tree.yml
+++ b/gr-filter/grc/filter.tree.yml
@@ -25,7 +25,6 @@
- mmse_interpolator_xx
- pfb_arb_resampler_xxx
- rational_resampler_xxx
- - rational_resampler_base_xxx
- ival_decimator
- Channelizers:
- freq_xlating_fft_filter_ccc
diff --git a/gr-filter/grc/filter_rational_resampler_base_xxx.block.yml b/gr-filter/grc/filter_rational_resampler_base_xxx.block.yml
deleted file mode 100644
index 9e81d59557..0000000000
--- a/gr-filter/grc/filter_rational_resampler_base_xxx.block.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-id: rational_resampler_base_xxx
-label: Rational Resampler Base
-flags: [ python ]
-
-parameters:
-- id: type
- label: Type
- dtype: enum
- options: [ccc, ccf, fcc, fff, fsf, scc]
- option_labels: [Complex->Complex (Complex Taps), Complex->Complex (Real Taps),
- Float->Complex (Complex Taps), Float->Float (Real Taps), Float->Short (Real
- Taps), Short->Complex (Complex Taps)]
- option_attributes:
- input: [complex, complex, float, float, float, short]
- output: [complex, complex, complex, float, short, complex]
- taps: [complex_vector, real_vector, complex_vector, real_vector, real_vector,
- complex_vector]
- hide: part
-- id: interp
- label: Interpolation
- dtype: int
- default: '1'
-- id: decim
- label: Decimation
- dtype: int
- default: '1'
-- id: taps
- label: Taps
- dtype: ${ type.taps }
-
-inputs:
-- domain: stream
- dtype: ${ type.input }
-
-outputs:
-- domain: stream
- dtype: ${ type.output }
-
-templates:
- imports: |-
- from gnuradio import filter
- from gnuradio.filter import firdes
- make: filter.rational_resampler_base_${type}(${interp}, ${decim}, ${taps})
- callbacks:
- - set_taps(${taps})
-
-file_format: 1
diff --git a/gr-filter/grc/filter_rational_resampler_xxx.block.yml b/gr-filter/grc/filter_rational_resampler_xxx.block.yml
index 1ac8238b74..10284d4cfd 100644
--- a/gr-filter/grc/filter_rational_resampler_xxx.block.yml
+++ b/gr-filter/grc/filter_rational_resampler_xxx.block.yml
@@ -25,6 +25,7 @@ parameters:
- id: taps
label: Taps
dtype: ${ type.taps }
+ default: '[]'
- id: fbw
label: Fractional BW
dtype: real
@@ -49,56 +50,45 @@ templates:
% if taps:
taps=${taps},
% else:
- taps=None,
+ taps=[],
% endif
% if float(fbw) != 0:
fractional_bw=${fbw})
% else:
- fractional_bw=None)
+ fractional_bw=-1.0)
% endif
callbacks:
- set_taps(${taps})
cpp_templates:
- includes: ['#include <gnuradio/filter/rational_resampler_base.h>']
- declarations: 'gr::filter::rational_resampler_base_${type}::sptr ${id};'
+ includes: ['#include <gnuradio/filter/rational_resampler.h>']
+ declarations: 'gr::filter::rational_resampler_${type}::sptr ${id};'
make: |-
<%
taps = self.context.get('taps')
try: taps
- except (NameError): taps = None
+ except: taps = None
taps = None if (len(taps) == 0) else taps
%>
% if taps == None or len(taps) == 0:
- <%
- # Leverage python module to generate default values for taps
- from gnuradio import filter
- %>
- <%
- fbw = self.context.get('fbw')
- fbw = float(fbw) if (len(fbw) > 0 and float(fbw) != 0) else None
- iotype = self.context.get('type')
- ftype = eval('filter.rational_resampler.rational_resampler_' + str(iotype))
- fltr = ftype(int(self.context.get('interp')), int(self.context.get('decim')), taps, fbw)
- taps = fltr.taps()
- # Format complex taps values for C++
- if iotype == 'fcc' or iotype == 'ccc':
- cmplx_taps = []
- for cmplx in taps:
- cmplx_taps.append({cmplx.real, cmplx.imag})
- taps = cmplx_taps
- %>
- % endif
-
- % if str(type.taps) == "complex_vector":
- std::vector<gr_complex> taps = {${str(taps)[1:-1]}};
+ % if str(type.taps) == "complex_vector":
+ std::vector<gr_complex> taps;
+ % else:
+ std::vector<float> taps;
+ % endif
% else:
- std::vector<float> taps = {${str(taps)[1:-1]}};
+ % if str(type.taps) == "complex_vector":
+ std::vector<gr_complex> taps = {${str(taps)[1:-1]}};
+ % else:
+ std::vector<float> taps = {${str(taps)[1:-1]}};
+ % endif
% endif
- this->${id} = gr::filter::rational_resampler_base_${type}::make(
+
+ this->${id} = gr::filter::rational_resampler_${type}::make(
${interp},
${decim},
- taps);
+ taps,
+ ${fbw});
link: ['gnuradio-filter']
callbacks:
- set_taps(${taps})
diff --git a/gr-filter/include/gnuradio/filter/CMakeLists.txt b/gr-filter/include/gnuradio/filter/CMakeLists.txt
index 4104aff1c9..5e24dbffa4 100644
--- a/gr-filter/include/gnuradio/filter/CMakeLists.txt
+++ b/gr-filter/include/gnuradio/filter/CMakeLists.txt
@@ -53,7 +53,7 @@ install(FILES
pfb_decimator_ccf.h
pfb_interpolator_ccf.h
pfb_synthesizer_ccf.h
- rational_resampler_base.h
+ rational_resampler.h
single_pole_iir_filter_cc.h
single_pole_iir_filter_ff.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/filter
diff --git a/gr-filter/include/gnuradio/filter/rational_resampler_base.h b/gr-filter/include/gnuradio/filter/rational_resampler.h
index 9b0af4b540..2ac18b0904 100644
--- a/gr-filter/include/gnuradio/filter/rational_resampler_base.h
+++ b/gr-filter/include/gnuradio/filter/rational_resampler.h
@@ -8,8 +8,8 @@
*
*/
-#ifndef RATIONAL_RESAMPLER_BASE_H
-#define RATIONAL_RESAMPLER_BASE_H
+#ifndef RATIONAL_RESAMPLER_H
+#define RATIONAL_RESAMPLER_H
#include <gnuradio/block.h>
#include <gnuradio/filter/api.h>
@@ -55,10 +55,10 @@ namespace filter {
* prefilter.
*/
template <class IN_T, class OUT_T, class TAP_T>
-class FILTER_API rational_resampler_base : virtual public block
+class FILTER_API rational_resampler : virtual public block
{
public:
- typedef std::shared_ptr<rational_resampler_base<IN_T, OUT_T, TAP_T>> sptr;
+ typedef std::shared_ptr<rational_resampler<IN_T, OUT_T, TAP_T>> sptr;
/*!
* Make a rational resampling FIR filter.
@@ -67,8 +67,10 @@ public:
* \param decimation The integer decimation rate of the filter
* \param taps The filter taps to control images and aliases
*/
- static sptr
- make(unsigned interpolation, unsigned decimation, const std::vector<TAP_T>& taps);
+ static sptr make(unsigned interpolation,
+ unsigned decimation,
+ const std::vector<TAP_T>& taps = std::vector<TAP_T>(),
+ float fractional_bw = 0.0);
virtual unsigned interpolation() const = 0;
virtual unsigned decimation() const = 0;
@@ -76,18 +78,14 @@ public:
virtual void set_taps(const std::vector<TAP_T>& taps) = 0;
virtual std::vector<TAP_T> taps() const = 0;
};
-typedef rational_resampler_base<gr_complex, gr_complex, gr_complex>
- rational_resampler_base_ccc;
-typedef rational_resampler_base<gr_complex, gr_complex, float>
- rational_resampler_base_ccf;
-typedef rational_resampler_base<float, gr_complex, gr_complex>
- rational_resampler_base_fcc;
-typedef rational_resampler_base<float, float, float> rational_resampler_base_fff;
-typedef rational_resampler_base<float, std::int16_t, float> rational_resampler_base_fsf;
-typedef rational_resampler_base<std::int16_t, gr_complex, gr_complex>
- rational_resampler_base_scc;
+typedef rational_resampler<gr_complex, gr_complex, gr_complex> rational_resampler_ccc;
+typedef rational_resampler<gr_complex, gr_complex, float> rational_resampler_ccf;
+typedef rational_resampler<float, gr_complex, gr_complex> rational_resampler_fcc;
+typedef rational_resampler<float, float, float> rational_resampler_fff;
+typedef rational_resampler<float, std::int16_t, float> rational_resampler_fsf;
+typedef rational_resampler<std::int16_t, gr_complex, gr_complex> rational_resampler_scc;
} /* namespace filter */
} /* namespace gr */
-#endif /* RATIONAL_RESAMPLER_BASE_H */
+#endif /* RATIONAL_RESAMPLER_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 69a56dd2c5..1e3189b7af 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -50,7 +50,7 @@ add_library(gnuradio-filter
pfb_decimator_ccf_impl.cc
pfb_interpolator_ccf_impl.cc
pfb_synthesizer_ccf_impl.cc
- rational_resampler_base_impl.cc
+ rational_resampler_impl.cc
single_pole_iir_filter_cc_impl.cc
single_pole_iir_filter_ff_impl.cc
)
diff --git a/gr-filter/lib/rational_resampler_base_impl.cc b/gr-filter/lib/rational_resampler_base_impl.cc
deleted file mode 100644
index 1ce199d1e4..0000000000
--- a/gr-filter/lib/rational_resampler_base_impl.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2010,2012,2018 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "rational_resampler_base_impl.h"
-#include <gnuradio/io_signature.h>
-#include <volk/volk.h>
-#include <stdexcept>
-
-namespace gr {
-namespace filter {
-
-template <class IN_T, class OUT_T, class TAP_T>
-typename rational_resampler_base<IN_T, OUT_T, TAP_T>::sptr
-rational_resampler_base<IN_T, OUT_T, TAP_T>::make(unsigned interpolation,
- unsigned decimation,
- const std::vector<TAP_T>& taps)
-{
- return gnuradio::make_block_sptr<rational_resampler_base_impl<IN_T, OUT_T, TAP_T>>(
- interpolation, decimation, taps);
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::rational_resampler_base_impl(
- unsigned interpolation, unsigned decimation, const std::vector<TAP_T>& taps)
- : block("rational_resampler_base<IN_T,OUT_T,TAP_T>",
- io_signature::make(1, 1, sizeof(IN_T)),
- io_signature::make(1, 1, sizeof(OUT_T))),
- d_history(1),
- d_decimation(decimation),
- d_ctr(0),
- d_updated(false)
-{
- if (interpolation == 0)
- throw std::out_of_range(
- "rational_resampler_base_impl<IN_T,OUT_T,TAP_T>: interpolation must be > 0");
- if (decimation == 0)
- throw std::out_of_range(
- "rational_resampler_base_impl<IN_T,OUT_T,TAP_T>: decimation must be > 0");
-
- this->set_relative_rate((uint64_t)interpolation, (uint64_t)decimation);
- this->set_output_multiple(1);
-
- d_firs.reserve(interpolation);
- for (unsigned i = 0; i < interpolation; i++) {
- d_firs.emplace_back(std::vector<TAP_T>());
- }
-
- set_taps(taps);
- install_taps(d_new_taps);
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-void rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::set_taps(
- const std::vector<TAP_T>& taps)
-{
- d_new_taps = taps;
- d_updated = true;
-
- // round up length to a multiple of the interpolation factor
- int n = taps.size() % this->interpolation();
- if (n > 0) {
- n = this->interpolation() - n;
- while (n-- > 0) {
- d_new_taps.insert(d_new_taps.end(), 0);
- }
- }
-
- assert(d_new_taps.size() % this->interpolation() == 0);
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-void rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::install_taps(
- const std::vector<TAP_T>& taps)
-{
- int nfilters = this->interpolation();
- int nt = taps.size() / nfilters;
-
- assert(nt * nfilters == (int)taps.size());
-
- std::vector<std::vector<TAP_T>> xtaps(nfilters);
-
- for (int n = 0; n < nfilters; n++)
- xtaps[n].resize(nt);
-
- for (int i = 0; i < (int)taps.size(); i++)
- xtaps[i % nfilters][i / nfilters] = taps[i];
-
- for (int n = 0; n < nfilters; n++)
- d_firs[n].set_taps(xtaps[n]);
-
- set_history(nt);
- d_updated = false;
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-std::vector<TAP_T> rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::taps() const
-{
- return d_new_taps;
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-void rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::forecast(
- int noutput_items, gr_vector_int& ninput_items_required)
-{
- int nreqd = std::max(
- (unsigned)1,
- (int)((double)(noutput_items + 1) * this->decimation() / this->interpolation()) +
- history() - 1);
- unsigned ninputs = ninput_items_required.size();
- for (unsigned i = 0; i < ninputs; i++)
- ninput_items_required[i] = nreqd;
-}
-
-template <class IN_T, class OUT_T, class TAP_T>
-int rational_resampler_base_impl<IN_T, OUT_T, TAP_T>::general_work(
- int noutput_items,
- gr_vector_int& ninput_items,
- gr_vector_const_void_star& input_items,
- gr_vector_void_star& output_items)
-{
- const IN_T* in = (const IN_T*)input_items[0];
- OUT_T* out = (OUT_T*)output_items[0];
-
- if (d_updated) {
- install_taps(d_new_taps);
- return 0; // history requirement may have increased.
- }
-
- unsigned int ctr = d_ctr;
- int count = 0;
-
- int i = 0;
- while ((i < noutput_items) && (count < ninput_items[0])) {
- out[i++] = d_firs[ctr].filter(in);
- ctr += this->decimation();
- while (ctr >= this->interpolation()) {
- ctr -= this->interpolation();
- in++;
- count++;
- }
- }
-
- d_ctr = ctr;
- this->consume_each(count);
- return i;
-}
-template class rational_resampler_base<gr_complex, gr_complex, gr_complex>;
-template class rational_resampler_base<gr_complex, gr_complex, float>;
-template class rational_resampler_base<float, gr_complex, gr_complex>;
-template class rational_resampler_base<float, float, float>;
-template class rational_resampler_base<float, std::int16_t, float>;
-template class rational_resampler_base<std::int16_t, gr_complex, gr_complex>;
-
-} /* namespace filter */
-} /* namespace gr */
diff --git a/gr-filter/lib/rational_resampler_impl.cc b/gr-filter/lib/rational_resampler_impl.cc
new file mode 100644
index 0000000000..32f253822f
--- /dev/null
+++ b/gr-filter/lib/rational_resampler_impl.cc
@@ -0,0 +1,263 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012,2018 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rational_resampler_impl.h"
+#include <gnuradio/filter/firdes.h>
+#include <gnuradio/integer_math.h>
+#include <gnuradio/io_signature.h>
+#include <volk/volk.h>
+#include <stdexcept>
+
+namespace gr {
+namespace filter {
+
+
+/**
+ * @brief Given the interpolation rate, decimation rate and a fractional bandwidth,
+ design a set of taps.
+ *
+ * Uses default parameters to build a low pass filter using a Kaiser Window
+ *
+ * @param interpolation interpolation factor (integer > 0)
+ * @param decimation decimation factor (integer > 0)
+ * @param fractional_bw fractional bandwidth in (0, 0.5) 0.4 works well. (float)
+ */
+template <typename TAP_T>
+std::vector<TAP_T> design_resampler_filter(const unsigned interpolation,
+ const unsigned decimation,
+ const float fractional_bw)
+{
+
+ if (fractional_bw >= 0.5 || fractional_bw <= 0) {
+ throw std::range_error("Invalid fractional_bandwidth, must be in (0, 0.5)");
+ }
+
+ // These are default values used to generate the filter when no taps are known
+ // Pulled from rational_resampler.py
+ float beta = 7.0;
+ float halfband = 0.5;
+ float rate = float(interpolation) / float(decimation);
+ float trans_width, mid_transition_band;
+
+ if (rate >= 1.0) {
+ trans_width = halfband - fractional_bw;
+ mid_transition_band = halfband - trans_width / 2.0;
+ } else {
+ trans_width = rate * (halfband - fractional_bw);
+ mid_transition_band = rate * halfband - trans_width / 2.0;
+ }
+
+ return firdes::low_pass(interpolation, /* gain */
+ interpolation, /* Fs */
+ mid_transition_band, /* trans mid point */
+ trans_width, /* transition width */
+ firdes::WIN_KAISER,
+ beta); /* beta*/
+}
+
+template <>
+std::vector<gr_complex> design_resampler_filter<gr_complex>(const unsigned interpolation,
+ const unsigned decimation,
+ const float fractional_bw)
+{
+ auto real_taps =
+ design_resampler_filter<float>(interpolation, decimation, fractional_bw);
+
+ std::vector<gr_complex> cplx_taps(real_taps.size());
+ for (size_t i = 0; i < real_taps.size(); i++) {
+ cplx_taps[i] = real_taps[i];
+ }
+
+ return cplx_taps;
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+typename rational_resampler<IN_T, OUT_T, TAP_T>::sptr
+rational_resampler<IN_T, OUT_T, TAP_T>::make(unsigned interpolation,
+ unsigned decimation,
+ const std::vector<TAP_T>& taps,
+ float fractional_bw)
+{
+ return gnuradio::make_block_sptr<rational_resampler_impl<IN_T, OUT_T, TAP_T>>(
+ interpolation, decimation, taps, fractional_bw);
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+rational_resampler_impl<IN_T, OUT_T, TAP_T>::rational_resampler_impl(
+ unsigned interpolation,
+ unsigned decimation,
+ const std::vector<TAP_T>& taps,
+ float fractional_bw)
+ : block("rational_resampler<IN_T,OUT_T,TAP_T>",
+ io_signature::make(1, 1, sizeof(IN_T)),
+ io_signature::make(1, 1, sizeof(OUT_T))),
+ d_history(1),
+ d_decimation(decimation)
+{
+ if (interpolation == 0) {
+ throw std::out_of_range(
+ "rational_resampler_impl<IN_T,OUT_T,TAP_T>: interpolation must be > 0");
+ }
+ if (decimation == 0) {
+ throw std::out_of_range(
+ "rational_resampler_impl<IN_T,OUT_T,TAP_T>: decimation must be > 0");
+ }
+
+ // If taps are not specified, we need to design them based on fractional_bw
+ if (taps.size() == 0 && fractional_bw <= 0) {
+ fractional_bw = 0.4;
+ }
+
+ auto d = GR_GCD(interpolation, decimation);
+
+ if (taps.size() && (d > 1)) {
+ GR_LOG_INFO(
+ d_logger,
+ boost::format(
+ "Rational resampler has user-provided taps but interpolation (%1%) and "
+ "decimation (%2%) have a GCD of %3%, which increases the complexity of "
+ "the filterbank. Consider reducing these values by the GCD.") %
+ interpolation % decimation % d);
+ }
+
+ std::vector<TAP_T> staps;
+ if (taps.size() == 0) {
+ if (fractional_bw <= 0) {
+ fractional_bw = 0.4;
+ }
+ // If we don't have user-provided taps, reduce the interp and
+ // decim values by the GCD (if there is one) and then define
+ // the taps from these new values.
+ interpolation /= d;
+ decimation /= d;
+ staps = design_resampler_filter<TAP_T>(interpolation, decimation, fractional_bw);
+ } else {
+ staps = taps;
+ }
+
+ this->set_relative_rate(uint64_t{ interpolation }, uint64_t{ decimation });
+ this->set_output_multiple(1);
+
+ d_firs.reserve(interpolation);
+ for (unsigned i = 0; i < interpolation; i++) {
+ d_firs.emplace_back(std::vector<TAP_T>());
+ }
+
+ set_taps(staps);
+ install_taps(d_new_taps);
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+void rational_resampler_impl<IN_T, OUT_T, TAP_T>::set_taps(const std::vector<TAP_T>& taps)
+{
+ d_new_taps = taps;
+ d_updated = true;
+
+ // round up length to a multiple of the interpolation factor
+ int n = taps.size() % this->interpolation();
+ if (n > 0) {
+ n = this->interpolation() - n;
+ while (n-- > 0) {
+ d_new_taps.insert(d_new_taps.end(), 0);
+ }
+ }
+
+ assert(d_new_taps.size() % this->interpolation() == 0);
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+void rational_resampler_impl<IN_T, OUT_T, TAP_T>::install_taps(
+ const std::vector<TAP_T>& taps)
+{
+ int nfilters = this->interpolation();
+ int nt = taps.size() / nfilters;
+
+ assert(nt * nfilters == (int)taps.size());
+
+ std::vector<std::vector<TAP_T>> xtaps(nfilters);
+
+ for (int n = 0; n < nfilters; n++)
+ xtaps[n].resize(nt);
+
+ for (int i = 0; i < (int)taps.size(); i++)
+ xtaps[i % nfilters][i / nfilters] = taps[i];
+
+ for (int n = 0; n < nfilters; n++)
+ d_firs[n].set_taps(xtaps[n]);
+
+ set_history(nt);
+ d_updated = false;
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+std::vector<TAP_T> rational_resampler_impl<IN_T, OUT_T, TAP_T>::taps() const
+{
+ return d_new_taps;
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+void rational_resampler_impl<IN_T, OUT_T, TAP_T>::forecast(
+ int noutput_items, gr_vector_int& ninput_items_required)
+{
+ int nreqd = std::max(
+ 1U,
+ (int)((double)(noutput_items + 1) * this->decimation() / this->interpolation()) +
+ history() - 1);
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned i = 0; i < ninputs; i++)
+ ninput_items_required[i] = nreqd;
+}
+
+template <class IN_T, class OUT_T, class TAP_T>
+int rational_resampler_impl<IN_T, OUT_T, TAP_T>::general_work(
+ int noutput_items,
+ gr_vector_int& ninput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ auto in = reinterpret_cast<const IN_T*>(input_items[0]);
+ auto out = reinterpret_cast<OUT_T*>(output_items[0]);
+
+ if (d_updated) {
+ install_taps(d_new_taps);
+ return 0; // history requirement may have increased.
+ }
+
+ unsigned int ctr = d_ctr;
+ int count = 0;
+
+ int i = 0;
+ while ((i < noutput_items) && (count < ninput_items[0])) {
+ out[i++] = d_firs[ctr].filter(in);
+ ctr += this->decimation();
+ while (ctr >= this->interpolation()) {
+ ctr -= this->interpolation();
+ in++;
+ count++;
+ }
+ }
+
+ d_ctr = ctr;
+ this->consume_each(count);
+ return i;
+}
+template class rational_resampler<gr_complex, gr_complex, gr_complex>;
+template class rational_resampler<gr_complex, gr_complex, float>;
+template class rational_resampler<float, gr_complex, gr_complex>;
+template class rational_resampler<float, float, float>;
+template class rational_resampler<float, std::int16_t, float>;
+template class rational_resampler<std::int16_t, gr_complex, gr_complex>;
+
+} /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/rational_resampler_base_impl.h b/gr-filter/lib/rational_resampler_impl.h
index 32d40f77bb..e9be526d30 100644
--- a/gr-filter/lib/rational_resampler_base_impl.h
+++ b/gr-filter/lib/rational_resampler_impl.h
@@ -8,33 +8,35 @@
*
*/
-#ifndef RATIONAL_RESAMPLER_IMPL_BASE_H
-#define RATIONAL_RESAMPLER_IMPL_BASE_H
+#ifndef RATIONAL_RESAMPLER_IMPL_H
+#define RATIONAL_RESAMPLER_IMPL_H
#include <gnuradio/filter/fir_filter.h>
-#include <gnuradio/filter/rational_resampler_base.h>
+#include <gnuradio/filter/rational_resampler.h>
namespace gr {
namespace filter {
template <class IN_T, class OUT_T, class TAP_T>
-class FILTER_API rational_resampler_base_impl
- : public rational_resampler_base<IN_T, OUT_T, TAP_T>
+class FILTER_API rational_resampler_impl : public rational_resampler<IN_T, OUT_T, TAP_T>
{
private:
unsigned d_history;
unsigned d_decimation;
- unsigned d_ctr;
+ unsigned d_ctr = 0;
std::vector<TAP_T> d_new_taps;
std::vector<kernel::fir_filter<IN_T, OUT_T, TAP_T>> d_firs;
- bool d_updated;
+ bool d_updated = false;
void install_taps(const std::vector<TAP_T>& taps);
+ gr::logger_ptr d_logger;
+
public:
- rational_resampler_base_impl(unsigned interpolation,
- unsigned decimation,
- const std::vector<TAP_T>& taps);
+ rational_resampler_impl(unsigned interpolation,
+ unsigned decimation,
+ const std::vector<TAP_T>& taps,
+ float fractional_bw);
unsigned history() const { return d_history; }
void set_history(unsigned history) { d_history = history; }
@@ -55,4 +57,4 @@ public:
} /* namespace filter */
} /* namespace gr */
-#endif /* RATIONAL_RESAMPLER_IMPL_BASE_H */
+#endif /* RATIONAL_RESAMPLER_IMPL_H */
diff --git a/gr-filter/python/filter/CMakeLists.txt b/gr-filter/python/filter/CMakeLists.txt
index 765af55868..1fb908fe68 100644
--- a/gr-filter/python/filter/CMakeLists.txt
+++ b/gr-filter/python/filter/CMakeLists.txt
@@ -15,7 +15,6 @@ GR_PYTHON_INSTALL(
freq_xlating_fft_filter.py
optfir.py
pfb.py
- rational_resampler.py
file_taps_loader.py
DESTINATION ${GR_PYTHON_DIR}/gnuradio/filter
)
diff --git a/gr-filter/python/filter/__init__.py b/gr-filter/python/filter/__init__.py
index 8e1fa48c68..e08457e6e0 100644
--- a/gr-filter/python/filter/__init__.py
+++ b/gr-filter/python/filter/__init__.py
@@ -23,7 +23,6 @@ except ImportError:
from .filterbank import *
from .freq_xlating_fft_filter import *
-from .rational_resampler import *
from . import pfb
from . import optfir
diff --git a/gr-filter/python/filter/bindings/CMakeLists.txt b/gr-filter/python/filter/bindings/CMakeLists.txt
index 47fa64cafe..1757159ba3 100644
--- a/gr-filter/python/filter/bindings/CMakeLists.txt
+++ b/gr-filter/python/filter/bindings/CMakeLists.txt
@@ -46,7 +46,7 @@ list(APPEND filter_python_files
pfb_synthesizer_ccf_python.cc
pm_remez_python.cc
polyphase_filterbank_python.cc
- rational_resampler_base_python.cc
+ rational_resampler_python.cc
single_pole_iir_python.cc
single_pole_iir_filter_cc_python.cc
single_pole_iir_filter_ff_python.cc
diff --git a/gr-filter/python/filter/bindings/docstrings/rational_resampler_base_pydoc_template.h b/gr-filter/python/filter/bindings/docstrings/rational_resampler_pydoc_template.h
index a187d6f1ef..a187d6f1ef 100644
--- a/gr-filter/python/filter/bindings/docstrings/rational_resampler_base_pydoc_template.h
+++ b/gr-filter/python/filter/bindings/docstrings/rational_resampler_pydoc_template.h
diff --git a/gr-filter/python/filter/bindings/python_bindings.cc b/gr-filter/python/filter/bindings/python_bindings.cc
index e7daa19c30..8147847e4a 100644
--- a/gr-filter/python/filter/bindings/python_bindings.cc
+++ b/gr-filter/python/filter/bindings/python_bindings.cc
@@ -58,7 +58,7 @@ void bind_pfb_interpolator_ccf(py::module&);
void bind_pfb_synthesizer_ccf(py::module&);
void bind_pm_remez(py::module&);
void bind_polyphase_filterbank(py::module&);
-void bind_rational_resampler_base(py::module&);
+void bind_rational_resampler(py::module&);
void bind_single_pole_iir(py::module&);
void bind_single_pole_iir_filter_cc(py::module&);
void bind_single_pole_iir_filter_ff(py::module&);
@@ -125,7 +125,7 @@ PYBIND11_MODULE(filter_python, m)
bind_pfb_synthesizer_ccf(m);
bind_pm_remez(m);
bind_polyphase_filterbank(m);
- bind_rational_resampler_base(m);
+ bind_rational_resampler(m);
bind_single_pole_iir(m);
bind_single_pole_iir_filter_cc(m);
bind_single_pole_iir_filter_ff(m);
diff --git a/gr-filter/python/filter/bindings/rational_resampler_base_python.cc b/gr-filter/python/filter/bindings/rational_resampler_base_python.cc
deleted file mode 100644
index 09083e798b..0000000000
--- a/gr-filter/python/filter/bindings/rational_resampler_base_python.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- */
-
-/***********************************************************************************/
-/* This file is automatically generated using bindtool and can be manually edited */
-/* The following lines can be configured to regenerate this file during cmake */
-/* If manual edits are made, the following tags should be modified accordingly. */
-/* BINDTOOL_GEN_AUTOMATIC(0) */
-/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(rational_resampler_base.h) */
-/* BINDTOOL_HEADER_FILE_HASH(8c16e10c6c05947272429eefa70c443e) */
-/***********************************************************************************/
-
-#include <pybind11/complex.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-
-namespace py = pybind11;
-
-#include <gnuradio/filter/rational_resampler_base.h>
-
-template <class IN_T, class OUT_T, class TAP_T>
-void bind_rational_resampler_base_template(py::module& m, const char* classname)
-{
- using rational_resampler_base =
- gr::filter::rational_resampler_base<IN_T, OUT_T, TAP_T>;
-
- py::class_<rational_resampler_base,
- gr::block,
- gr::basic_block,
- std::shared_ptr<rational_resampler_base>>(m, classname)
- .def(py::init(&gr::filter::rational_resampler_base<IN_T, OUT_T, TAP_T>::make),
- py::arg("interpolation"),
- py::arg("decimation"),
- py::arg("taps"))
-
- .def("set_taps", &rational_resampler_base::set_taps, py::arg("taps"))
- .def("taps", &rational_resampler_base::taps)
- .def("interpolation", &rational_resampler_base::interpolation)
- .def("decimation", &rational_resampler_base::decimation);
-}
-
-void bind_rational_resampler_base(py::module& m)
-{
- bind_rational_resampler_base_template<gr_complex, gr_complex, gr_complex>(
- m, "rational_resampler_base_ccc");
- bind_rational_resampler_base_template<gr_complex, gr_complex, float>(
- m, "rational_resampler_base_ccf");
- bind_rational_resampler_base_template<float, gr_complex, gr_complex>(
- m, "rational_resampler_base_fcc");
- bind_rational_resampler_base_template<float, float, float>(
- m, "rational_resampler_base_fff");
- bind_rational_resampler_base_template<float, std::int16_t, float>(
- m, "rational_resampler_base_fsf");
- bind_rational_resampler_base_template<std::int16_t, gr_complex, gr_complex>(
- m, "rational_resampler_base_scc");
-}
diff --git a/gr-filter/python/filter/bindings/rational_resampler_python.cc b/gr-filter/python/filter/bindings/rational_resampler_python.cc
new file mode 100644
index 0000000000..0f77b73415
--- /dev/null
+++ b/gr-filter/python/filter/bindings/rational_resampler_python.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+/***********************************************************************************/
+/* This file is automatically generated using bindtool and can be manually edited */
+/* The following lines can be configured to regenerate this file during cmake */
+/* If manual edits are made, the following tags should be modified accordingly. */
+/* BINDTOOL_GEN_AUTOMATIC(0) */
+/* BINDTOOL_USE_PYGCCXML(0) */
+/* BINDTOOL_HEADER_FILE(rational_resampler.h) */
+/* BINDTOOL_HEADER_FILE_HASH(79b3bf084bb620b66770a08c158f7ad9) */
+/***********************************************************************************/
+
+#include <pybind11/complex.h>
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+namespace py = pybind11;
+
+#include <gnuradio/filter/rational_resampler.h>
+
+template <class IN_T, class OUT_T, class TAP_T>
+void bind_rational_resampler_template(py::module& m, const char* classname)
+{
+ using rational_resampler = gr::filter::rational_resampler<IN_T, OUT_T, TAP_T>;
+
+ py::class_<rational_resampler,
+ gr::block,
+ gr::basic_block,
+ std::shared_ptr<rational_resampler>>(m, classname)
+ .def(py::init(&gr::filter::rational_resampler<IN_T, OUT_T, TAP_T>::make),
+ py::arg("interpolation"),
+ py::arg("decimation"),
+ py::arg("taps") = std::vector<TAP_T>(),
+ py::arg("fractional_bw") = 0.0)
+
+ .def("set_taps", &rational_resampler::set_taps, py::arg("taps"))
+ .def("taps", &rational_resampler::taps)
+ .def("interpolation", &rational_resampler::interpolation)
+ .def("decimation", &rational_resampler::decimation);
+}
+
+void bind_rational_resampler(py::module& m)
+{
+ bind_rational_resampler_template<gr_complex, gr_complex, gr_complex>(
+ m, "rational_resampler_ccc");
+ bind_rational_resampler_template<gr_complex, gr_complex, float>(
+ m, "rational_resampler_ccf");
+ bind_rational_resampler_template<float, gr_complex, gr_complex>(
+ m, "rational_resampler_fcc");
+ bind_rational_resampler_template<float, float, float>(m, "rational_resampler_fff");
+ bind_rational_resampler_template<float, std::int16_t, float>(
+ m, "rational_resampler_fsf");
+ bind_rational_resampler_template<std::int16_t, gr_complex, gr_complex>(
+ m, "rational_resampler_scc");
+}
diff --git a/gr-filter/python/filter/qa_rational_resampler.py b/gr-filter/python/filter/qa_rational_resampler.py
index bd4122d93d..4c67dc793b 100644
--- a/gr-filter/python/filter/qa_rational_resampler.py
+++ b/gr-filter/python/filter/qa_rational_resampler.py
@@ -76,7 +76,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(1, 1, taps)
+ op = filter.rational_resampler_fff(1, 1, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op)
tb.connect(op, dst)
@@ -99,7 +99,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(interpolation, 1, taps)
+ op = filter.rational_resampler_fff(interpolation, 1, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op)
tb.connect(op, dst)
@@ -117,7 +117,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(interpolation, 1, taps)
+ op = filter.rational_resampler_fff(interpolation, 1, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op)
tb.connect(op, dst)
@@ -137,7 +137,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(1, decimation, taps)
+ op = filter.rational_resampler_fff(1, decimation, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op)
tb.connect(op, dst)
@@ -168,7 +168,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(1, decim, taps)
+ op = filter.rational_resampler_fff(1, decim, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op, dst)
tb.run()
@@ -206,7 +206,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(interp, 1, taps)
+ op = filter.rational_resampler_fff(interp, 1, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op, dst)
tb.run()
@@ -238,7 +238,7 @@ class test_rational_resampler (gr_unittest.TestCase):
tb = gr.top_block()
src = blocks.vector_source_f(src_data)
- op = filter.rational_resampler_base_fff(interp, decimation, taps)
+ op = filter.rational_resampler_fff(interp, decimation, taps)
dst = blocks.vector_sink_f()
tb.connect(src, op)
tb.connect(op, dst)
diff --git a/gr-filter/python/filter/rational_resampler.py b/gr-filter/python/filter/rational_resampler.py
deleted file mode 100644
index 1af9698e2b..0000000000
--- a/gr-filter/python/filter/rational_resampler.py
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# Copyright 2005,2007 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-#
-
-
-import math
-from gnuradio import gr
-from . import filter_python as filter
-
-_plot = None
-
-
-def design_filter(interpolation, decimation, fractional_bw):
- """
- Given the interpolation rate, decimation rate and a fractional bandwidth,
- design a set of taps.
-
- Args:
- interpolation: interpolation factor (integer > 0)
- decimation: decimation factor (integer > 0)
- fractional_bw: fractional bandwidth in (0, 0.5) 0.4 works well. (float)
- Returns:
- : sequence of numbers
- """
-
- if fractional_bw >= 0.5 or fractional_bw <= 0:
- raise ValueError("Invalid fractional_bandwidth, must be in (0, 0.5)")
-
- beta = 7.0
- halfband = 0.5
- rate = float(interpolation) / float(decimation)
- if(rate >= 1.0):
- trans_width = halfband - fractional_bw
- mid_transition_band = halfband - trans_width / 2.0
- else:
- trans_width = rate*(halfband - fractional_bw)
- mid_transition_band = rate*halfband - trans_width / 2.0
-
- taps = filter.firdes.low_pass(interpolation, # gain
- interpolation, # Fs
- mid_transition_band, # trans mid point
- trans_width, # transition width
- filter.firdes.WIN_KAISER,
- beta) # beta
-
- return taps
-
-
-
-class _rational_resampler_base(gr.hier_block2):
- """
- base class for all rational resampler variants.
- """
- def __init__(self, resampler_base,
- interpolation, decimation, taps=None, fractional_bw=None):
- """
- Rational resampling polyphase FIR filter.
-
- Either taps or fractional_bw may be specified, but not both.
- If neither is specified, a reasonable default, 0.4, is used as
- the fractional_bw.
-
- Args:
- interpolation: interpolation factor (integer > 0)
- decimation: decimation factor (integer > 0)
- taps: optional filter coefficients (sequence)
- fractional_bw: fractional bandwidth in (0, 0.5), measured at final freq (use 0.4) (float)
- """
-
- if not isinstance(interpolation, int) or interpolation < 1:
- raise ValueError("interpolation must be an integer >= 1")
-
- if not isinstance(decimation, int) or decimation < 1:
- raise ValueError("decimation must be an integer >= 1")
-
- if taps is None and fractional_bw is None:
- fractional_bw = 0.4
-
- d = math.gcd(interpolation, decimation)
-
- # If we have user-provided taps and the interp and decim
- # values have a common divisor, we don't reduce these values
- # by the GCD but issue a warning to the user that this might
- # increase the complexity of the filter.
- if taps and (d > 1):
- gr.log.info("Rational resampler has user-provided taps but interpolation ({0}) and decimation ({1}) have a GCD of {2}, which increases the complexity of the filterbank. Consider reducing these values by the GCD.".format(interpolation, decimation, d))
-
- # If we don't have user-provided taps, reduce the interp and
- # decim values by the GCD (if there is one) and then define
- # the taps from these new values.
- if taps is None:
- interpolation = interpolation // d
- decimation = decimation // d
- taps = design_filter(interpolation, decimation, fractional_bw)
-
- self.resampler = resampler_base(interpolation, decimation, taps)
- gr.hier_block2.__init__(self, "rational_resampler",
- gr.io_signature(1, 1, self.resampler.input_signature().sizeof_stream_item(0)),
- gr.io_signature(1, 1, self.resampler.output_signature().sizeof_stream_item(0)))
-
- self.connect(self, self.resampler, self)
-
- def taps(self):
- return self.resampler.taps()
-
-class rational_resampler_fff(_rational_resampler_base):
- def __init__(self, interpolation, decimation, taps=None, fractional_bw=None):
- """
- Rational resampling polyphase FIR filter with
- float input, float output and float taps.
- """
- _rational_resampler_base.__init__(self, filter.rational_resampler_base_fff,
- interpolation, decimation, taps, fractional_bw)
-
-class rational_resampler_ccf(_rational_resampler_base):
- def __init__(self, interpolation, decimation, taps=None, fractional_bw=None):
- """
- Rational resampling polyphase FIR filter with
- complex input, complex output and float taps.
- """
- _rational_resampler_base.__init__(self, filter.rational_resampler_base_ccf,
- interpolation, decimation, taps, fractional_bw)
-
-class rational_resampler_ccc(_rational_resampler_base):
- def __init__(self, interpolation, decimation, taps=None, fractional_bw=None):
- """
- Rational resampling polyphase FIR filter with
- complex input, complex output and complex taps.
- """
- _rational_resampler_base.__init__(self, filter.rational_resampler_base_ccc,
- interpolation, decimation, taps, fractional_bw)
-
-class rational_resampler_fcc(_rational_resampler_base):
- def __init__(self, interpolation, decimation, taps=None, fractional_bw=None):
- """
- Rational resampling polyphase FIR filter with
- float input, complex output and complex taps.
- """
- _rational_resampler_base.__init__(self, filter.rational_resampler_base_fcc,
- interpolation, decimation, taps, fractional_bw)