diff options
Diffstat (limited to 'gr-blocks')
-rw-r--r-- | gr-blocks/examples/ctrlport/simple_copy.grc | 50 | ||||
-rw-r--r-- | gr-blocks/grc/blocks_moving_average_xx.xml | 11 | ||||
-rw-r--r-- | gr-blocks/include/gnuradio/blocks/moving_average_XX.h.t | 6 | ||||
-rw-r--r-- | gr-blocks/lib/moving_average_XX_impl.cc.t | 61 | ||||
-rw-r--r-- | gr-blocks/lib/moving_average_XX_impl.h.t | 11 | ||||
-rw-r--r-- | gr-blocks/python/blocks/qa_moving_average.py | 68 |
6 files changed, 135 insertions, 72 deletions
diff --git a/gr-blocks/examples/ctrlport/simple_copy.grc b/gr-blocks/examples/ctrlport/simple_copy.grc index a52c350ded..f61c6cd18a 100644 --- a/gr-blocks/examples/ctrlport/simple_copy.grc +++ b/gr-blocks/examples/ctrlport/simple_copy.grc @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='utf-8'?> -<?grc format='1' created='3.7.11'?> +<?grc format='1' created='3.7.12'?> <flow_graph> <timestamp>Sat Mar 16 22:03:14 2013</timestamp> <block> @@ -393,48 +393,6 @@ to enable/disablethis block</value> </param> </block> <block> - <key>epy_block</key> - <param> - <key>alias</key> - <value></value> - </param> - <param> - <key>_io_cache</key> - <value>('Null Msg Source', 'blk', [], [], [('fake_output', 'message', 1)], '', [])</value> - </param> - <param> - <key>_source_code</key> - <value># Block that doesn't do anything, just used to get a msg input port on another block exposed to ControlPort -from gnuradio import gr -import pmt -class blk(gr.basic_block): - def __init__(self): - gr.basic_block.__init__(self,name='Null Msg Source',in_sig=[],out_sig=[]) - self.message_port_register_out(pmt.intern("fake_output")) -</value> - </param> - <param> - <key>comment</key> - <value></value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>_coordinate</key> - <value>(357, 218)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - <param> - <key>id</key> - <value>epy_block_0</value> - </param> - </block> - <block> <key>note</key> <param> <key>alias</key> @@ -861,10 +819,4 @@ python simple_copy_controller.py 127.0.0.1 <PORT> true</value> <source_key>0</source_key> <sink_key>0</sink_key> </connection> - <connection> - <source_block_id>epy_block_0</source_block_id> - <sink_block_id>blocks_copy_0</sink_block_id> - <source_key>fake_output</source_key> - <sink_key>en</sink_key> - </connection> </flow_graph> 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 > 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..fe0a2bdebd 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(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(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 2c58805925..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 # @@ -45,6 +45,10 @@ class test_moving_average(gr_unittest.TestCase): def tearDown(self): self.tb = None + # These tests will always pass and are therefore useless. 100 random numbers [-1,1) are + # getting summed up and scaled with 0.001. Then, an assertion verifies a result near 0, + # which is the case even if the block is malfunctioning. + def test_01(self): tb = self.tb @@ -87,5 +91,67 @@ class test_moving_average(gr_unittest.TestCase): # make sure result is close to zero self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1) + # This tests implement own moving average to verify correct behaviour of the block + + def test_03(self): + tb = self.tb + + 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)) + + tb.run() + + dut_data = dut_dst.data() + ref_data = ref_dst.data() + + # make sure result is close to zero + self.assertTupleEqual(dut_data, ref_data) + + def test_04(self): + tb = self.tb + + N = 10000 # number of samples + history = 100 # num of samples to average + data = make_random_complex_tuple(N, 1) # generate random data + + # pythonic MA filter + data_padded = (history-1)*[0.0+1j*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] + + src = blocks.vector_source_c(data, False) + op = blocks.moving_average_cc(history, 1) + dst = blocks.vector_sink_c() + + tb.connect(src, op) + tb.connect(op, dst) + tb.run() + + dst_data = dst.data() + + # 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") |