summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-blocks/grc/blocks_moving_average_xx.xml11
-rw-r--r--gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t6
-rw-r--r--gr-blocks/lib/moving_average_XX_impl.cc.t61
-rw-r--r--gr-blocks/lib/moving_average_XX_impl.h.t11
-rw-r--r--gr-blocks/python/blocks/qa_moving_average.py47
5 files changed, 91 insertions, 45 deletions
diff --git a/gr-blocks/grc/blocks_moving_average_xx.xml b/gr-blocks/grc/blocks_moving_average_xx.xml
index e90903ad85..00c5e1d486 100644
--- a/gr-blocks/grc/blocks_moving_average_xx.xml
+++ b/gr-blocks/grc/blocks_moving_average_xx.xml
@@ -8,7 +8,7 @@
<name>Moving Average</name>
<key>blocks_moving_average_xx</key>
<import>from gnuradio import blocks</import>
- <make>blocks.moving_average_$(type.fcn)($length, $scale, $max_iter)</make>
+ <make>blocks.moving_average_$(type.fcn)($length, $scale, $max_iter, $vlen)</make>
<callback>set_length_and_scale($length, $scale)</callback>
<param>
<name>Type</name>
@@ -57,12 +57,21 @@
<value>4000</value>
<type>int</type>
</param>
+ <param>
+ <name>Length of Vectors</name>
+ <key>vlen</key>
+ <value>1</value>
+ <type>int</type>
+ </param>
+ <check>$vlen &gt; 0</check>
<sink>
<name>in</name>
<type>$type</type>
+ <vlen>$vlen</vlen>
</sink>
<source>
<name>out</name>
<type>$type</type>
+ <vlen>$vlen</vlen>
</source>
</block>
diff --git a/gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t b/gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t
index da5968240c..deabf31832 100644
--- a/gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t
+++ b/gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2013 Free Software Foundation, Inc.
+ * Copyright 2008,2013,2017 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -48,9 +48,11 @@ namespace gr {
* \param scale scale factor for the result.
* \param max_iter limits how long we go without flushing the accumulator
* This is necessary to avoid numerical instability for float and complex.
+ * \param vlen When > 1, do a per-vector-element moving average
*/
static sptr make(int length, @O_TYPE@ scale,
- int max_iter = 4096);
+ int max_iter = 4096,
+ unsigned int vlen = 1);
/*!
* Get the length used in the avaraging calculation.
diff --git a/gr-blocks/lib/moving_average_XX_impl.cc.t b/gr-blocks/lib/moving_average_XX_impl.cc.t
index 089166971f..2e70ab4cc0 100644
--- a/gr-blocks/lib/moving_average_XX_impl.cc.t
+++ b/gr-blocks/lib/moving_average_XX_impl.cc.t
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2010,2013 Free Software Foundation, Inc.
+ * Copyright 2008,2010,2013,2017 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -33,24 +33,30 @@ namespace gr {
namespace blocks {
@NAME@::sptr
- @NAME@::make(int length, @O_TYPE@ scale, int max_iter)
+ @NAME@::make(int length, @O_TYPE@ scale, int max_iter, unsigned int vlen)
{
return gnuradio::get_initial_sptr
- (new @NAME_IMPL@(length, scale, max_iter));
+ (new @NAME_IMPL@(length, scale, max_iter, vlen));
}
- @NAME_IMPL@::@NAME_IMPL@(int length, @O_TYPE@ scale, int max_iter)
+ @NAME_IMPL@::@NAME_IMPL@(int length, @O_TYPE@ scale, int max_iter, unsigned int vlen)
: sync_block("@NAME@",
- io_signature::make(1, 1, sizeof(@I_TYPE@)),
- io_signature::make(1, 1, sizeof(@O_TYPE@))),
+ io_signature::make(1, 1, sizeof(@I_TYPE@)*vlen),
+ io_signature::make(1, 1, sizeof(@O_TYPE@)*vlen)),
d_length(length),
d_scale(scale),
d_max_iter(max_iter),
+ d_vlen(vlen),
d_new_length(length),
d_new_scale(scale),
d_updated(false)
{
set_history(length);
+ //we don't have C++11's <array>, so initialize the stored vector instead
+ //we store this vector so that work() doesn't spend its time allocating and freeing vector storage
+ if(d_vlen > 1) {
+ d_sum = std::vector<@I_TYPE@>(d_vlen);
+ }
}
@NAME_IMPL@::~@NAME_IMPL@()
@@ -95,18 +101,39 @@ namespace gr {
const @I_TYPE@ *in = (const @I_TYPE@ *)input_items[0];
@O_TYPE@ *out = (@O_TYPE@ *)output_items[0];
- @I_TYPE@ sum = 0;
- int num_iter = (noutput_items>d_max_iter) ? d_max_iter : noutput_items;
- for(int i = 0; i < d_length-1; i++) {
- sum += in[i];
- }
-
- for(int i = 0; i < num_iter; i++) {
- sum += in[i+d_length-1];
- out[i] = sum * d_scale;
- sum -= in[i];
+ unsigned int num_iter = (unsigned int)((noutput_items>d_max_iter) ? d_max_iter : noutput_items);
+ if(d_vlen == 1) {
+ @I_TYPE@ sum = in[0];
+ for(unsigned int i = 1; i < d_length-1; i++) {
+ sum += in[i];
+ }
+
+ for(unsigned int i = 0; i < num_iter; i++) {
+ sum += in[i+d_length-1];
+ out[i] = sum * d_scale;
+ sum -= in[i];
+ }
+
+ } else { // d_vlen > 1
+ //gets automatically optimized well
+ for(unsigned int elem = 0; elem < d_vlen; elem++) {
+ d_sum[elem] = in[elem];
+ }
+
+ for(unsigned int i = 1; i < d_length - 1; i++) {
+ for(unsigned int elem = 0; elem < d_vlen; elem++) {
+ d_sum[elem] += in[i*d_vlen + elem];
+ }
+ }
+
+ for(unsigned int i = 0; i < num_iter; i++) {
+ for(unsigned int elem = 0; elem < d_vlen; elem++) {
+ d_sum[elem] += in[(i+d_length-1)*d_vlen + elem];
+ out[i*d_vlen + elem] = d_sum[elem] * d_scale;
+ d_sum[elem] -= in[i*d_vlen + elem];
+ }
+ }
}
-
return num_iter;
}
diff --git a/gr-blocks/lib/moving_average_XX_impl.h.t b/gr-blocks/lib/moving_average_XX_impl.h.t
index 17e8ef5da9..f90a666bbf 100644
--- a/gr-blocks/lib/moving_average_XX_impl.h.t
+++ b/gr-blocks/lib/moving_average_XX_impl.h.t
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008,2013 Free Software Foundation, Inc.
+ * Copyright 2008,2013,2017 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,6 +26,8 @@
#define @GUARD_NAME_IMPL@
#include <gnuradio/blocks/@NAME@.h>
+#include <vector>
+#include <algorithm>
namespace gr {
namespace blocks {
@@ -36,6 +38,9 @@ namespace gr {
int d_length;
@O_TYPE@ d_scale;
int d_max_iter;
+ unsigned int d_vlen;
+ std::vector<@I_TYPE@> d_sum;
+
int d_new_length;
@O_TYPE@ d_new_scale;
@@ -43,11 +48,13 @@ namespace gr {
public:
@NAME_IMPL@(int length, @O_TYPE@ scale,
- int max_iter = 4096);
+ int max_iter = 4096,
+ unsigned int vlen = 1);
~@NAME_IMPL@();
int length() const { return d_new_length; }
@O_TYPE@ scale() const { return d_new_scale; }
+ unsigned int vlen() const { return d_vlen; }
void set_length_and_scale(int length, @O_TYPE@ scale);
void set_length(int length);
diff --git a/gr-blocks/python/blocks/qa_moving_average.py b/gr-blocks/python/blocks/qa_moving_average.py
index 53b240fe7f..b76f81392d 100644
--- a/gr-blocks/python/blocks/qa_moving_average.py
+++ b/gr-blocks/python/blocks/qa_moving_average.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2013 Free Software Foundation, Inc.
+# Copyright 2013,2017 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -96,31 +96,33 @@ class test_moving_average(gr_unittest.TestCase):
def test_03(self):
tb = self.tb
- N = 10000 # number of samples
- history = 100 # num of samples to average
- data = make_random_float_tuple(N, 1) # generate random data
-
- # pythonic MA filter
- data_padded = (history-1)*[0.0]+list(data) # history
- expected_result = []
- moving_sum = sum(data_padded[:history-1])
- for i in range(N):
- moving_sum += data_padded[i+history-1]
- expected_result.append(moving_sum)
- moving_sum -= data_padded[i]
+ vlen = 5
+ N = 10*vlen
+ seed = 0
+ data = make_random_float_tuple(N, 2**10)
+ data = [int(d*1000) for d in data]
+ src = blocks.vector_source_i(data, False)
+ one_to_many = blocks.stream_to_streams(gr.sizeof_int, vlen)
+ one_to_vector = blocks.stream_to_vector(gr.sizeof_int, vlen)
+ many_to_vector = blocks.streams_to_vector(gr.sizeof_int, vlen)
+ isolated = [ blocks.moving_average_ii(100, 1) for i in range(vlen)]
+ dut = blocks.moving_average_ii(100, 1, vlen=vlen)
+ dut_dst = blocks.vector_sink_i(vlen=vlen)
+ ref_dst = blocks.vector_sink_i(vlen=vlen)
+
+ tb.connect(src, one_to_many)
+ tb.connect(src, one_to_vector, dut, dut_dst)
+ tb.connect(many_to_vector, ref_dst)
+ for idx, single in enumerate(isolated):
+ tb.connect((one_to_many,idx), single, (many_to_vector,idx))
- src = blocks.vector_source_f(data, False)
- op = blocks.moving_average_ff(history, 1)
- dst = blocks.vector_sink_f()
-
- tb.connect(src, op)
- tb.connect(op, dst)
tb.run()
-
- dst_data = dst.data()
+
+ dut_data = dut_dst.data()
+ ref_data = ref_dst.data()
# make sure result is close to zero
- self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4)
+ self.assertTupleEqual(dut_data, ref_data)
def test_04(self):
tb = self.tb
@@ -151,6 +153,5 @@ class test_moving_average(gr_unittest.TestCase):
# make sure result is close to zero
self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 4)
-
if __name__ == '__main__':
gr_unittest.run(test_moving_average, "test_moving_average.xml")