commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 09/16: digital: added tag propagation to bu


From: git
Subject: [Commit-gnuradio] [gnuradio] 09/16: digital: added tag propagation to burst_shaper blocks
Date: Sun, 26 Apr 2015 23:18:03 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 3b1b6d3fd6faa7bd1cbeb8b0ebfe42e6b9196bf7
Author: Sean Nowlan <address@hidden>
Date:   Sat Apr 25 19:38:33 2015 -0400

    digital: added tag propagation to burst_shaper blocks
---
 .../python/gnuradio/gr/qa_tag_utils.py             | 32 +++++++++
 gnuradio-runtime/python/gnuradio/gr/tag_utils.py   | 33 +++++++++
 .../include/gnuradio/digital/burst_shaper_XX.h.t   | 10 ++-
 gr-digital/lib/burst_shaper_XX_impl.cc.t           | 78 ++++++++++++++--------
 gr-digital/lib/burst_shaper_XX_impl.h.t            |  3 +-
 gr-digital/python/digital/qa_burst_shaper.py       | 71 ++++++++++++++++++--
 6 files changed, 193 insertions(+), 34 deletions(-)

diff --git a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py 
b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
index 1a08ac5..55b62a1 100755
--- a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
+++ b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
@@ -76,6 +76,38 @@ class test_tag_utils (gr_unittest.TestCase):
         self.assertTrue(pmt.equal(t_tuple.value, value))
         self.assertEqual(t_tuple.offset, offset)
 
+    def test_003(self):
+        offsets = (6, 3, 8)
+        key = pmt.string_to_symbol('key')
+        srcid = pmt.string_to_symbol('qa_tag_utils')
+        tags = []
+
+        for k in offsets:
+            t = gr.tag_t()
+            t.offset = k
+            t.key = key
+            t.value = pmt.from_long(k)
+            t.srcid = srcid
+            tags.append(t)
+
+        for k, t in zip(sorted(offsets),
+                        sorted(tags, key=gr.tag_t_offset_compare_key())):
+            self.assertEqual(t.offset, k)
+            self.assertTrue(pmt.equal(t.key, key))
+            self.assertTrue(pmt.equal(t.value, pmt.from_long(k)))
+            self.assertTrue(pmt.equal(t.srcid, srcid))
+
+        tmin = min(tags, key=gr.tag_t_offset_compare_key())
+        self.assertEqual(tmin.offset, min(offsets))
+        self.assertTrue(pmt.equal(tmin.key, key))
+        self.assertTrue(pmt.equal(tmin.value, pmt.from_long(min(offsets))))
+        self.assertTrue(pmt.equal(tmin.srcid, srcid))
+
+        tmax = max(tags, key=gr.tag_t_offset_compare_key())
+        self.assertEqual(tmax.offset, max(offsets))
+        self.assertTrue(pmt.equal(tmax.key, key))
+        self.assertTrue(pmt.equal(tmax.value, pmt.from_long(max(offsets))))
+        self.assertTrue(pmt.equal(tmax.srcid, srcid))
 
 
 if __name__ == '__main__':
diff --git a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py 
b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
index ba46e3f..872a5b0 100644
--- a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
+++ b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
@@ -108,3 +108,36 @@ def python_to_tag(tag_struct):
         return tag
     else:
         return None
+
+def tag_t_offset_compare_key():
+    """
+    Convert a tag_t_offset_compare function into a key=function
+    This method is modeled after functools.cmp_to_key(_func_).
+    It can be used by functions that accept a key function, such as
+    sorted(), min(), max(), etc. to compare tags by their offsets,
+    e.g., sorted(tag_list, key=gr.tag_t_offset_compare_key()).
+    """
+    class K(object):
+        def __init__(self, obj, *args):
+            self.obj = obj
+        def __lt__(self, other):
+            # x.offset < y.offset
+            return gr.tag_t_offset_compare(self.obj, other.obj)
+        def __gt__(self, other):
+            # y.offset < x.offset
+            return gr.tag_t_offset_compare(other.obj, self.obj)
+        def __eq__(self, other):
+            # not (x.offset < y.offset) and not (y.offset < x.offset)
+            return not gr.tag_t_offset_compare(self.obj, other.obj) and \
+                   not gr.tag_t_offset_compare(other.obj, self.obj)
+        def __le__(self, other):
+            # not (y.offset < x.offset)
+            return not gr.tag_t_offset_compare(other.obj, self.obj)
+        def __ge__(self, other):
+            # not (x.offset < y.offset)
+            return not gr.tag_t_offset_compare(self.obj, other.obj)
+        def __ne__(self, other):
+            # (x.offset < y.offset) or (y.offset < x.offset)
+            return gr.tag_t_offset_compare(self.obj, other.obj) or \
+                   gr.tag_t_offset_compare(other.obj, self.obj)
+    return K
diff --git a/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t 
b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
index 43d422b..fd7b690 100644
--- a/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
+++ b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
@@ -49,7 +49,15 @@ namespace gr {
      * directly to the head and tail of each burst.
      *
      * Length tags will be updated to include the length of any added
-     * zero padding or phasing symbols.
+     * zero padding or phasing symbols and will be placed at the
+     * beginning of the modified tagged stream. Any other tags found at
+     * the same offset as a length tag will also be placed at the
+     * beginning of the modified tagged stream, since these tags are
+     * assumed to be associated with the burst rather than a specific
+     * sample. For example, if "tx_time" tags are used to control
+     * bursts, their offsets should be consistent with their associated
+     * burst's length tags. Tags at other offsets will be placed with
+     * the samples on which they were found.
      *
      * \li input: stream of @I_TYPE@
      * \li output: stream of @O_TYPE@
diff --git a/gr-digital/lib/burst_shaper_XX_impl.cc.t 
b/gr-digital/lib/burst_shaper_XX_impl.cc.t
index 398011a..85add49 100644
--- a/gr-digital/lib/burst_shaper_XX_impl.cc.t
+++ b/gr-digital/lib/burst_shaper_XX_impl.cc.t
@@ -68,6 +68,7 @@ namespace gr {
         d_ncopy(0),
         d_limit(0),
         d_index(0),
+        d_length_tag_offset(0),
         d_finished(false),
         d_state(STATE_WAIT)
     {
@@ -93,8 +94,8 @@ namespace gr {
 
     void
     @IMPL_NAME@::forecast(int noutput_items,
-                          gr_vector_int &ninput_items_required) {
-        //if(d_state == STATE_COPY
+                          gr_vector_int &ninput_items_required)
+    {
         ninput_items_required[0] = noutput_items;
     }
 
@@ -111,13 +112,11 @@ namespace gr {
         int nread = 0;
         int nspace = 0;
         int nskip = 0;
-        uint64_t curr_tag_index = nitems_read(0);
+        int curr_tag_index = 0;
 
-        std::vector<tag_t> length_tags, tags;
+        std::vector<tag_t> length_tags;
         get_tags_in_window(length_tags, 0, 0, ninput_items[0], 
d_length_tag_key);
-        get_tags_in_window(tags, 0, 0, ninput_items[0]);
         std::sort(length_tags.rbegin(), length_tags.rend(), 
tag_t::offset_compare);
-        std::sort(tags.begin(), tags.end(), tag_t::offset_compare);
 
         while((nwritten < noutput_items) && (nread < ninput_items[0])) {
             if(d_finished) {
@@ -128,11 +127,13 @@ namespace gr {
             switch(d_state) {
                 case(STATE_WAIT):
                     if(!length_tags.empty()) {
-                        curr_tag_index = length_tags.back().offset;
+                        d_length_tag_offset = length_tags.back().offset;
+                        curr_tag_index = (int)(d_length_tag_offset - 
nitems_read(0));
                         d_ncopy = pmt::to_long(length_tags.back().value);
                         length_tags.pop_back();
-                        nskip = (int)(curr_tag_index - nread - nitems_read(0));
+                        nskip = curr_tag_index - nread;
                         add_length_tag(nwritten);
+                        propagate_tags(curr_tag_index, nwritten, 1, false);
                         enter_prepad();
                     }
                     else {
@@ -188,19 +189,22 @@ namespace gr {
     }
 
     int
-    @IMPL_NAME@::prefix_length() const {
+    @IMPL_NAME@::prefix_length() const
+    {
         return (d_insert_phasing) ?
                d_nprepad + d_up_ramp.size() : d_nprepad;
     }
 
     int
-    @IMPL_NAME@::suffix_length() const {
+    @IMPL_NAME@::suffix_length() const
+    {
         return (d_insert_phasing) ?
                d_npostpad + d_down_ramp.size() : d_npostpad;
     }
 
     void
-    @IMPL_NAME@::write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace) {
+    @IMPL_NAME@::write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace)
+    {
         int nprocess = std::min(d_limit - d_index, nspace);
         std::memset(dst, 0x00, nprocess * sizeof(@O_TYPE@));
         dst += nprocess;
@@ -210,8 +214,10 @@ namespace gr {
 
     void
     @IMPL_NAME@::copy_items(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int 
&nwritten,
-                            int &nread, int nspace) {
+                            int &nread, int nspace)
+    {
         int nprocess = std::min(d_limit - d_index, nspace);
+        propagate_tags(nread, nwritten, nprocess);
         std::memcpy(dst, src, nprocess * sizeof(@O_TYPE@));
         dst += nprocess;
         nwritten += nprocess;
@@ -222,7 +228,8 @@ namespace gr {
 
     void
     @IMPL_NAME@::apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int 
&nwritten,
-                            int &nread, int nspace) {
+                            int &nread, int nspace)
+    {
         int nprocess = std::min(d_limit - d_index, nspace);
         @O_TYPE@ *phasing;
         const @O_TYPE@ *ramp;
@@ -239,6 +246,7 @@ namespace gr {
         if(d_insert_phasing)
             std::memcpy(dst, phasing, nprocess * sizeof(@O_TYPE@));
         else {
+            propagate_tags(nread, nwritten, nprocess);
             address@hidden@(dst, src, ramp, nprocess);
             src += nprocess;
             nread += nprocess;
@@ -259,33 +267,48 @@ namespace gr {
     }
 
     void
-    @IMPL_NAME@::propagate_tags(std::vector<tag_t> &tags, int offset)
+    @IMPL_NAME@::propagate_tags(int in_offset, int out_offset, int count, bool 
skip)
     {
-        // FIXME: need to handle offsets correctly
-        std::vector<tag_t>::iterator tag;
-        for(tag = tags.begin(); tag != tags.end(); tag++) {
-            tag_t new_tag = *tag;
-            new_tag.offset = nitems_written(0) + offset;
-            add_item_tag(0, new_tag);
+        uint64_t abs_start = nitems_read(0) + in_offset;
+        uint64_t abs_end = abs_start + count;
+        uint64_t abs_offset = nitems_written(0) + out_offset;
+        tag_t temp_tag;
+
+        std::vector<tag_t> tags;
+        std::vector<tag_t>::iterator it;
+
+        get_tags_in_range(tags, 0, abs_start, abs_end);
+
+        for(it = tags.begin(); it != tags.end(); it++) {
+            if(!pmt::equal(it->key, d_length_tag_key)) {
+                if(skip && (it->offset == d_length_tag_offset))
+                    continue;
+                temp_tag = *it;
+                temp_tag.offset = abs_offset + it->offset - abs_start;
+                add_item_tag(0, temp_tag);
+            }
         }
     }
 
     void
-    @IMPL_NAME@::enter_wait() {
+    @IMPL_NAME@::enter_wait()
+    {
         d_finished = true;
         d_index = 0;
         d_state = STATE_WAIT;
     }
 
     void
-    @IMPL_NAME@::enter_prepad() {
+    @IMPL_NAME@::enter_prepad()
+    {
         d_limit = d_nprepad;
         d_index = 0;
         d_state = STATE_PREPAD;
     }
 
     void
-    @IMPL_NAME@::enter_rampup() {
+    @IMPL_NAME@::enter_rampup()
+    {
         if(d_insert_phasing)
             d_limit = d_up_ramp.size();
         else
@@ -295,7 +318,8 @@ namespace gr {
     }
 
     void
-    @IMPL_NAME@::enter_copy() {
+    @IMPL_NAME@::enter_copy()
+    {
         if(d_insert_phasing)
             d_limit = d_ncopy;
         else
@@ -307,7 +331,8 @@ namespace gr {
     }
 
     void
-    @IMPL_NAME@::enter_rampdown() {
+    @IMPL_NAME@::enter_rampdown()
+    {
         if(d_insert_phasing)
             d_limit = d_down_ramp.size();
         else
@@ -317,7 +342,8 @@ namespace gr {
     }
 
     void
-    @IMPL_NAME@::enter_postpad() {
+    @IMPL_NAME@::enter_postpad()
+    {
         d_limit = d_npostpad;
         d_index = 0;
         d_state = STATE_POSTPAD;
diff --git a/gr-digital/lib/burst_shaper_XX_impl.h.t 
b/gr-digital/lib/burst_shaper_XX_impl.h.t
index 4fa1cad..99ad7fb 100644
--- a/gr-digital/lib/burst_shaper_XX_impl.h.t
+++ b/gr-digital/lib/burst_shaper_XX_impl.h.t
@@ -48,6 +48,7 @@ namespace gr {
       int d_ncopy;
       int d_limit;
       int d_index;
+      uint64_t d_length_tag_offset;
       bool d_finished;
       state_t d_state;
 
@@ -57,7 +58,7 @@ namespace gr {
       void apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten,
                       int &nread, int nspace);
       void add_length_tag(int offset);
-      void propagate_tags(std::vector<tag_t> &tags, int offset);
+      void propagate_tags(int in_offset, int out_offset, int count, bool 
skip=true);
       void enter_wait();
       void enter_prepad();
       void enter_rampup();
diff --git a/gr-digital/python/digital/qa_burst_shaper.py 
b/gr-digital/python/digital/qa_burst_shaper.py
index b5aecd4..f85b79c 100755
--- a/gr-digital/python/digital/qa_burst_shaper.py
+++ b/gr-digital/python/digital/qa_burst_shaper.py
@@ -25,6 +25,7 @@ from gnuradio import gr, gr_unittest
 from gnuradio import blocks, digital
 import pmt
 import numpy as np
+import sys
 
 def make_length_tag(offset, length):
     return gr.python_to_tag({'offset' : offset,
@@ -32,13 +33,15 @@ def make_length_tag(offset, length):
                              'value' : pmt.from_long(length),
                              'srcid' : pmt.intern('qa_burst_shaper')})
 
+def make_tag(offset, key, value):
+    return gr.python_to_tag({'offset' : offset,
+                             'key' : pmt.intern(key),
+                             'value' : value,
+                             'srcid' : pmt.intern('qa_burst_shaper')})
+
 def compare_tags(a, b):
-    a = gr.tag_to_python(a)
-    b = gr.tag_to_python(b)
-    return a.key == b.key and a.offset == b.offset and \
-           a.value == b.value
-    #return a.key == b.key and a.offset == b.offset and \
-    #       a.srcid == b.srcid and a.value == b.value
+    return a.offset == b.offset and pmt.equal(a.key, b.key) and \
+           pmt.equal(a.value, b.value)
 
 class qa_burst_shaper (gr_unittest.TestCase):
 
@@ -276,6 +279,62 @@ class qa_burst_shaper (gr_unittest.TestCase):
         for i in xrange(len(etags)):
             self.assertTrue(compare_tags(sink.tags()[i], etags[i]))
 
+    def test_tag_propagation (self):
+        prepad = 10
+        postpad = 10
+        length1 = 15
+        length2 = 25
+        gap_len = 5
+        lentag1_offset = 0
+        lentag2_offset = length1 + gap_len
+        tag1_offset = 0                     # accompanies first length tag
+        tag2_offset = length1 + gap_len     # accompanies second length tag
+        tag3_offset = 2                     # in ramp-up state
+        tag4_offset = length1 + 2           # in gap; tag will be dropped
+        tag5_offset = length1 + gap_len + 7 # in copy state
+
+        data = np.concatenate((np.ones(length1), np.zeros(gap_len),
+                               -1.0*np.ones(length2), np.zeros(10)))
+        window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5)))
+        tags = (make_length_tag(lentag1_offset, length1),
+                make_length_tag(lentag2_offset, length2),
+                make_tag(tag1_offset, 'head', pmt.intern('tag1')),
+                make_tag(tag2_offset, 'head', pmt.intern('tag2')),
+                make_tag(tag3_offset, 'body', pmt.intern('tag3')),
+                make_tag(tag4_offset, 'body', pmt.intern('tag4')),
+                make_tag(tag5_offset, 'body', pmt.intern('tag5')))
+        expected = np.concatenate((np.zeros(prepad), window[0:5],
+                                   np.ones(length1 - len(window)), 
window[5:10],
+                                   np.zeros(postpad + prepad), 
-1.0*window[0:5],
+                                   -1.0*np.ones(length2 - len(window)),
+                                   -1.0*window[5:10], np.zeros(postpad)))
+        elentag1_offset = 0
+        elentag2_offset = length1 + prepad + postpad
+        etag1_offset = 0
+        etag2_offset = elentag2_offset
+        etag3_offset = prepad + tag3_offset
+        etag5_offset = 2*prepad + postpad + tag5_offset - gap_len
+        etags = (make_length_tag(elentag1_offset, length1 + prepad + postpad),
+                 make_length_tag(elentag2_offset, length2 + prepad + postpad),
+                 make_tag(etag1_offset, 'head', pmt.intern('tag1')),
+                 make_tag(etag2_offset, 'head', pmt.intern('tag2')),
+                 make_tag(etag3_offset, 'body', pmt.intern('tag3')),
+                 make_tag(etag5_offset, 'body', pmt.intern('tag5')))
+
+        # flowgraph
+        source = blocks.vector_source_f(data, tags=tags)
+        shaper = digital.burst_shaper_ff(window, pre_padding=prepad,
+                                         post_padding=postpad)
+        sink = blocks.vector_sink_f()
+        self.tb.connect(source, shaper, sink)
+        self.tb.run ()
+
+        # checks
+        self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6)
+        for x, y in zip(sorted(sink.tags(), key=gr.tag_t_offset_compare_key()),
+                        sorted(etags, key=gr.tag_t_offset_compare_key())):
+            self.assertTrue(compare_tags(x, y))
+
 
 if __name__ == '__main__':
     gr_unittest.run(qa_burst_shaper, "qa_burst_shaper.xml")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]