In my last post I talked about how data can be stored and read in MATLAB for analysis. The only downside is that these data files do not include any information about timing relative to other blocks. GNU Radio has a built-in functionality with stream tags to keep track of timing information. This can be useful for working with packetized data, but currently there isn’t any way to save those tags along with data to look at later. I’ve been working on a few blocks that might be able to help with this.
Bursty Data & Stream Tags
Originally GNU Radio was great for continuous streaming of samples, but lacked the ability to pass ancillary information like meta data, packet lengths, and the like that would help with decoding bursty data sent in packets. However, in recent years there has been quite a bit of work done to improve this.
One of the features that has helped extend the project’s functionality is Stream Tags. These stream tags operate as a separate data stream to pass information along to blocks downstream in the flow graph. These tags are associated with a certain sample in the data stream and that timing relation is preserved as the tags propagate through the remaining blocks. For instance, there are several blocks in GNU Radio that expect the first sample of a packet to have a tag containing the length of the packet. The block can then do its processing based on packet length.
Stream Tags are Polymorphic Types, a data type that can be used as a general container for data, be it vectors, strings, or any number of data formats such as ints and floats. Each tag has a specific format that contains several parts:
- Offset: The data stream sample that the tag is associated with
- Key: A PMT symbol that contains an identifier for the tag
- Value: A PMT representation of the data the tag is passing
- Source ID: A PMT symbol representing the block that created the tag (optional)
Saving Tags To File
In my last post I went through using file sinks to process data offline using software such as MATLAB. Currently, the file sinks don’t save tags along with that data. However, such information such as the timing and value of tags might be useful for debugging. For example, if you have a tag denoting the start of each packet you may wish to have that timing information available in MATLAB.
To do this I wrote a fairly simple block “Tag to Byte”. For a parameter it asks for the key associated with a given tag, which in this example is “packet_len”. It can be inserted anywhere into a stream, just change the IO Type parameter to match the input data type. The Tag to Byte block can be followed by a file sink.
Tag to Byte Block In A Flowgraph
The block searches the stream for a tag matching the key. When it finds one it outputs a ‘1’ for that sample only. For any samples that don’t have a tag it outputs a ‘0’. This way the timing between tags is preserved as it is written to file. The file length will be the same as a file containing the data from the same point in the flow graph and the tags will be at the correct offset. The extra timing information from the tags can be used in processing data offline.
Plotting Data and Tags in MATLAB
Adding Tags From A File
There also is some utility in being able to add tags anywhere in a data stream. GNU Radio has some functionality for this already. There is a stream to tagged stream block that will add tags at evenly spaced intervals. This can be useful for data that is evenly spaced. However if the tags need to correspond to data that is unevenly spaced, such as simulated irregular bursty transmissions we need another tool to do so.
A block I’ve written called “Add Tag at Offset” takes care of this. It can be inserted anywhere in a data stream and will insert tags into the stream. As parameters it will ask for the key to be associated with the tags and the value to insert. The last parameter is the offset for the tags, and this can be a vector of any length.
Using Add Tag at Offset In A Flow Graph
Every time the block reaches a sample with the same offset as is in its offset vector it will add a tag to that sample. All samples are passed through so the block does not interrupt the data flow.
This can be useful if we wish to take a block that uses tags in a complex flow graph and examine its performance by itself. We can load data from a file and add tags anywhere in the input stream. From the block’s perspective it seems as if it is still in the overall flow graph.
Both of these blocks and a few more that are useful for working with stream tags are available on GitHub.
There are a few obvious improvements to make to these tools that will be coming soon. It would be nice if the Add Tag at Offset block was able to add tags of different values instead of writing the same value each time. Its current operation might be okay if you were say passing the length of packets to the next block but less useful if you were using the tag to carry information that changes from packet to packet (an estimate of the packet’s carrier frequency offset, for example). A future improvement would be to have this block read the tag values from a vector as well.
It would also be nice if Tag to Byte would pass the value of the tags along to a file sink instead of just a ‘1’ to represent the presence of a tag. A new block with the working title “Tag Extractor” is being developed that will do just that. It will take some doing to cover all stream data types and tag data types, but I’m working on it. The first version of this (only for complex streams and complex-valued tags) is also available on GitHub.