GNU Radio教程 6.在stream上添加标签

流标签

内容:

1   介绍

2   gr::block 的 API 扩展

3   流标签 API

3.1 将标签添加到流

3.2 从流中获取标签

4   标签传播

5   标签使用注意事项

6   示例流程图

6.1 向 QPSK 解调器添加标签

7   用例:FIR 滤波器

  • 简介:

GNU Radio 最初是一个没有其他机制在模块之间传递数据的流系统。(意思是,只能通过stream传输,不能向量传输)流数据是一种适用于样本、比特等的模型,但可能缺乏控制和元数据。

部分问题是使用现有的消息传递接口解决的,该接口允许模块订阅流程图中任何其他块发布的messages。消息传递系统的主要缺点是它异步工作,这意味着相对于数据流,无法保证消息何时到达。

流标签是与主数据流并行运行的同步数据流。流标签由块的工作函数生成,并从那里沿着特定样本向下游流动,直到它到达接收器或被另一个块强制停止传播。

流标签是为数据流中的特定item定义的,并形成key:value对。key标识value代表什么,而value保存tag包含的数据。Key和value都是多态类型 (PMT),其中键是 PMT 符号,而值是任何类型的 PMT,因此可以处理我们希望传递的任何数据。标签的另一个部分是srcid,它是一个 PMT 符号,用于标识创建标签的模块(通常是块的别名)。

二、gr::block 的 API 扩展

为了启用流标签,我们扩展了 gr::block 的 API 以理解absolute item numbers。在数据流模型中,每个模块的work函数在数据流中被赋予一个缓冲区,从 0 到 N-1 被引用。这是数据流的相对偏移量。绝对引用从流程图的开头开始,并随着每个item继续计数。每个输入流都与“number of items read”的概念相关联,每个输出流都有一个“number of items written”。这些可以在运行时使用两个 API检索的:

每个标签都与这个绝对时间尺度中的某个item相关联,该绝对时间尺度是使用这些函数计算的。

与数据流的其余部分一样,读取/写入的item数仅在调用工作期间更新一次。所以在一个工作函数中,nitems_read/written 将指的是工作函数开始时数据流的状态。因此,我们必须将数据流中的当前相对偏移量添加到该值。因此,如果我们在所有输出item上迭代i,我们会将流标记写入 nitems_written(0)+i 处的输出,用于第 0 个输出端口。

三、流标签API

   流标签 API 分为两部分:向流中添加标签和从流中获取标签。请注意,下面描述的函数仅用于在调用 general_work/work 时访问。虽然它们可以在其他时间点被模块调用,但如果不确切了解缓冲区中的iteam counts,则work之外的行为是未定义的。

3.1向流中添加标签

我们使用以下方法将标签添加到块的特定输出流:

    gr::block::add_item_tag:使用 gr::tag_t 数据类型或通过指定标签值将item标签添加到特定输出端口。

如果需要,我们可以将它们输出到多个输出流,但这样做意味着为每个端口调用一次此函数。这个函数可以提供一个 gr::tag_t 数据类型,或者可以显式地给出标签的每个值。

同样,标签定义为:

1.offset:数据流中标签的偏移量,以absolute item time计。

2.key:标识标签类型的 PMT 符号。

3.value:保存标签数据的 PMT。

4.srcid:(可选)标识创建标签的模块的 PMT 符号。

我们可以创建一个 gr::tag_t 结构来保存标签的所有上述信息,这可能是最简单/最好的方法。gr::tag_t 结构被定义为具有与上述列表中相同的成员。要将 gr::tag_t 标签添加到流中,请使用以下函数:

辅助 API 允许我们在函数调用中显式列出所有标签信息来创建标签

在 Python 中,我们可以使用以下方法之一向流中添加标签

请注意,key和value都是 PMT。要创建字符串类型 PMT,您可以使用 pmt.intern("example_key")。

以下面的流程图为例。我们将有一个嵌入式 python 模块以随机间隔插入流标签,并在 QT GUI Time sink 上查看这些标签。

将以下代码添加到嵌入式 python 块中。此代码输出与输入相同的信号,除了随机选择的输入样本上的标签:

四、从流中得到标签

要从特定输入流中获取标签,我们可以使用两个函数:

1.gr::block::get_tags_in_range:从特定输入端口获取特定范围item之间的所有标签(in absolute item time)。

2.gr::block::get_tags_in_window:从特定输入端口获取特定范围项目之间的所有标签(in relative item time within the work function)。

这两个函数之间的区别在于绝对item时间与相对item时间。这两个都传回 gr::tag_t 的向量,并且它们都允许指定特定的键(作为 PMT 符号)进行过滤(或者可以省略第五个参数以搜索所有键)。过滤某个键可以减少工作函数内部获取正确标签数据的工作量。

例如,此调用仅返回给定item范围之间的任何标签:

向该函数添加第五个参数允许我们过滤key。

在 Python 中,与 C++ 函数的主要区别在于,第一个参数不是存储标签的向量,Python 版本只返回标签列表。我们会这样使用它:

如果您想在输入端口 0 上获取当前正在由 work() 处理的样本上的所有标签,这是一个最小的示例:

五、标签传播

我们现在知道如何将标签添加到流中,以及如何读取它们。但是标签被读取后会发生什么?未使用的标签会怎样?毕竟,有很多块根本不关心标签。

答案是:这取决于块的标签传播策略,进入它的标签会发生什么。

有以下三种政策可供选择:

1.All-to-All:来自任何输入端口的所有标签都复制到所有输出端口

2.一对一:来自输入端口i的标签仅被复制到输出端口i(取决于 num 个输入 = num 个输出)。

3.Dont:不传播标签。标签要么在此处停止,要么工作功能以某种方式重新创建它们。

块的默认行为是“All-to-All”传播方法。

六、关于如何使用标签的注意事项

标签对应用程序非常有用,并且它们的使用正在推广。如果有任何变化,USRP 源会生成有关板的时间、采样率和频率的标签信息。我们有一个meta data file source/sink(请参阅Metadata_Information),它使用标签来存储有关数据流的信息。但是在模块中使用这些标签时需要考虑一些事情。

首先,当不使用标签时,对调度程序几乎没有影响。但是,当我们使用标签时,我们会通过从数据流中获取和提取标签来增加开销。我们还使用了传播标签的开销。对于每个标签,每个块必须将标签向量从一个块的输出端口复制到下一个块的输入端口。这些复制操作可以加起来。

关键是尽量减少标签的使用。仅在必要时使用它们,并通过从这些标签中获取信息来提供一些控制。一个很好的例子是生成时间标签的 USRP 源。如果它为每个样本生成一个标签,我们每秒将有数千个标签,这将增加大量开销。这是因为如果我们在时间 t0 以采样率 sr 开始,那么在 N 个样本之后,我们知道我们现在处于时间 t0 + N/sr。因此,不断生产新标签不会增加任何信息。

在上述情况下,我们需要处理的主要问题是确定何时从 USRP 接收的数据包不连续。由于我们无法在流程图中知道有多少样本可能丢失,因此我们丢失了时序信息。USRP 驱动程序识别数据包何时被丢弃,并使用这个时间点来排队另一个标签,这允许我们重新同步。同样,采样率或频率发生变化的任何点,都会产生一个新标签。

七、流程图示例

一个简单的例子如下:

    在这个流程图中,我们有两个源:一个正弦波和一个标签选通。标签选通是一个输出一个常量标签的模块,在本例中,在每第1000 个item添加标签(item的实际值始终为零)。这些源加起来。加法器后的信号与我们产生的正弦波相同,因为我们总是加item零。然而,标签仍然附着在与标签闪光灯发出时相同的位置!这意味着正弦曲线的每 1000 个样本现在都有一个标签。QT 示波器可以显示标签,甚至可以触发它们。

我们现在有一种机制可以将任何元数据随机附加到特定item。有几个使用标签的块。其中之一是 UHD Sink 块,用于与 USRP 设备进行传输的驱动程序。它将对带有某些key的tag做出反应,tag其中之一是tx_freq,可用于在streaming传输时设置 USRP 的传输频率。

7.1向 QPSK 解调器添加标签

    回到我们的 QPSK 解调示例,我们可能想要添加一个功能来告诉下游模块解调不顺利。请记住,我们模块的输出总是硬决策,我们必须输出一些东西。所以我们可以使用标签来通知输入格式不正确,QPSK输出不可靠。

    作为失败标准,我们讨论输入幅度太小,例如小于 0.01 的情况。当幅度低于该值时,我们输出一个标签。仅当幅度恢复并回落到阈值以下时才发送另一个标签。我们像这样扩展我们的工作函数:

在 Python 中,代码如下所示(assuming we have a member of our block class called d_low_ampl_state):

我们还可以创建一个标签数据类型tag_t并直接传递它:

这是一个使用标记的解调器的流程图。我们输入 20 个有效的 QPSK 符号,然后输入 10 个零。由于此块的输出始终为 0、1、2 或 3,因此我们通常无法查看输入是否不是这些值之一。

这是输出。您可以看到我们在那些值上带有标签,这些值不是来自有效的 QPSK 符号,而是来自不可靠的东西。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值