[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")
- [Commit-gnuradio] [gnuradio] 04/16: grc: Add check for GTK initialization, (continued)
- [Commit-gnuradio] [gnuradio] 04/16: grc: Add check for GTK initialization, git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 13/16: Merge remote-tracking branch 'mmueller/pwr_squelch_add_tags', git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 12/16: Merge remote-tracking branch 'tom/ctrlport/fixes1', git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 06/16: controlport: use proper default return value from prefs get_bool., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 08/16: digital: fix skipped sample handling in burst_shaper, git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 05/16: qtgui: improved type checking for range block and simplifies python., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 02/16: controlport: fixed up performance monitor., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 03/16: qtgui: adds Type setting for Range widget., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 01/16: controlport: fixed controlport probes., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 07/16: analog: Power Squelch now emit tags on start/end of bursts, git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 09/16: digital: added tag propagation to burst_shaper blocks,
git <=
- [Commit-gnuradio] [gnuradio] 10/16: blocks: better implementation of peak_detector2. Address #783., git, 2015/04/26
- [Commit-gnuradio] [gnuradio] 11/16: blocks: more fixups to peak_detector2., git, 2015/04/26