diff options
-rw-r--r-- | gr-fft/include/gnuradio/fft/window.h | 4 | ||||
-rw-r--r-- | gr-fft/lib/window.cc | 23 | ||||
-rw-r--r-- | gr-fft/python/fft/bindings/window_python.cc | 5 | ||||
-rw-r--r-- | gr-fft/python/fft/qa_window.py | 37 |
4 files changed, 65 insertions, 4 deletions
diff --git a/gr-fft/include/gnuradio/fft/window.h b/gr-fft/include/gnuradio/fft/window.h index 0ab333e175..6739f9a0bd 100644 --- a/gr-fft/include/gnuradio/fft/window.h +++ b/gr-fft/include/gnuradio/fft/window.h @@ -331,8 +331,10 @@ public: * \param type a gr::fft::win_type index for the type of window. * \param ntaps Number of coefficients in the window. * \param beta Used only for building Kaiser windows. + * \param normalize If true, return a window with unit power */ - static std::vector<float> build(win_type type, int ntaps, double beta = 6.76); + static std::vector<float> + build(win_type type, int ntaps, double beta = 6.76, const bool normalize = false); }; } /* namespace fft */ diff --git a/gr-fft/lib/window.cc b/gr-fft/lib/window.cc index 430b435bd4..faebdd4f56 100644 --- a/gr-fft/lib/window.cc +++ b/gr-fft/lib/window.cc @@ -14,6 +14,8 @@ #include <gnuradio/fft/window.h> #include <gnuradio/math.h> +#include <algorithm> +#include <numeric> #include <stdexcept> namespace gr { @@ -355,8 +357,27 @@ std::vector<float> window::gaussian(int ntaps, float sigma) return taps; } -std::vector<float> window::build(win_type type, int ntaps, double beta) +std::vector<float> +window::build(win_type type, int ntaps, double beta, const bool normalize) { + // If we want a normalized window, we get a non-normalized one first, then + // normalize it here: + if (normalize) { + auto win = build(type, ntaps, beta, false); + const double pwr_acc = // sum(win**2) / len(win) + std::accumulate(win.cbegin(), + win.cend(), + 0.0, + [](const double a, const double b) { return a + b * b; }) / + win.size(); + const float norm_fac = static_cast<float>(std::sqrt(pwr_acc)); + std::transform(win.begin(), win.end(), win.begin(), [norm_fac](const float tap) { + return tap / norm_fac; + }); + return win; + } + + // Create non-normalized window: switch (type) { case WIN_RECTANGULAR: return rectangular(ntaps); diff --git a/gr-fft/python/fft/bindings/window_python.cc b/gr-fft/python/fft/bindings/window_python.cc index 51dd7200d1..e04a6c59df 100644 --- a/gr-fft/python/fft/bindings/window_python.cc +++ b/gr-fft/python/fft/bindings/window_python.cc @@ -13,8 +13,8 @@ /* If manual edits are made, the following tags should be modified accordingly. */ /* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_USE_PYGCCXML(0) */ -/* BINDTOOL_HEADER_FILE(window.h) */ -/* BINDTOOL_HEADER_FILE_HASH(b55c3b96105267729782fc5262efa28a) */ +/* BINDTOOL_HEADER_FILE(window.h) */ +/* BINDTOOL_HEADER_FILE_HASH(22de6d8875628eec777952b4902a09e9) */ /***********************************************************************************/ #include <pybind11/complex.h> @@ -176,6 +176,7 @@ void bind_window(py::module& m) py::arg("type"), py::arg("ntaps"), py::arg("beta") = 6.76, + py::arg("normalize") = false, D(window, build)) ; diff --git a/gr-fft/python/fft/qa_window.py b/gr-fft/python/fft/qa_window.py new file mode 100644 index 0000000000..f5afd2640d --- /dev/null +++ b/gr-fft/python/fft/qa_window.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# Copyright 2020 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" +Unit tests for fft.window +""" + +import numpy +from gnuradio import gr_unittest +from gnuradio import fft + +class test_window(gr_unittest.TestCase): + """ + Unit tests for fft.window + """ + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_normwin(self): + """ + Verify window normalization + """ + win = fft.window.build(fft.win_type.WIN_BLACKMAN_hARRIS, 21, normalize=True) + power = numpy.sum([x*x for x in win])/len(win) + self.assertAlmostEqual(power, 1.0) + +if __name__ == '__main__': + gr_unittest.run(test_window) |