GNU Radio中的消息传递机制(Message Passing)

2023-05-16

目录

0、首先看下 GR 中一些常用术语的官方解释

1、定义理解

2、消息传递端口API

3、消息处理函数

4、通过流程图连接消息

5、从外部源发布数据

6、使用消息传送命令

7、一个消息传输的例子


0、首先看下 GR 中一些常用术语的官方解释

直接吧官方的解释抄过来,直接看英文更容易理解:

BlockA functional processing unit with inputs and outputs
PortA single input or output of a block
SourceA producer of data
SinkA consumer of data
ConnectionA flow of data from output port to input port
Flow graphA collection of blocks and connections
ItemA unit of data. Ex: baseband sample, fft vector, matrix...
StreamA continuous flow of consecutive items
IO signatureA description of a blocks input and output ports

1、定义理解

GNU Radio中的消息(message)传递不同于数据流(streaming)的传递。其直观表现就是在流图中,消息端口(message port)之间的连线是虚线,而流数据端口(streaming port)之间的连线是实线。在 block 的代码层面,流数据一定是在 work 函数中进行处理的,而消息一般是在专用的消息处理函数中处理的。消息传递(Message Passing)机制 的出现给予以下两种原因:

  1. 在数据流传输过程中,它允许下游的block向上游的block进行通信
  2. 采用简单的方法实现外部应用与GNU Radio进行交互通信。

首先,stream 在 GR 中作为需要处理的数据,在数字信号中就是一个个采样点的信息,GR 对 stream 数据的处理就是一种无脑式处理,例如在一个滤波器模块中,模块才不会管你输入的是个啥数据,真实数据还是噪音,都会一视同仁当作有效数据进行滤波操作,这时就无法辨别 协议数据单元(PDU)与 信号数据,所以就需要 message 数据进行其他信息的传输。

message 还有这么一层功能:在 GR 中,一个数据流(stream)从产生到最终变成电磁波信号发射,其只能沿着这条从产生到发射的单向信号处理流程进行单向处理,但是有时我们需要一些文本信息或者其他数据类型(PMT类型)信息的反馈来了解数据的处理情况或者一些中间状态信息,这时就需要借助 message 来传递这样的消息了。

另外,消息传输接口的使用严重依赖于GR中的多态数据类型(PMTs),即我们传输的 message 都是 pmt 类型的。GNU Radio中消息传递与数据流传递的关系可以见下图,初次看可能不能理解那就先略过这幅图继续往下看叭~

2、消息传递端口API

消息传递接口定义在gr::basic_block中,该类是GR中所有blocks的父类。每个block都有一组消息队列来保存传入的消息,并且可以将消息发布到其他block的消息队列。并且一般来说每个block上都有输入输出端口,这些端口的C++定义如下:

 void message_port_register_in(pmt::pmt_t port_id)
 void message_port_register_out(pmt::pmt_t port_id)

上述两个API分别用来注册一个新的输入和输出端口。其参数是用以描述端口名称的PMT symbol 类型的数据。Python的调用方式如下:

 self.message_port_register_in(pmt.intern("port name"))
 self.message_port_register_out(pmt.intern("port name"))

这些新注册的端口可以通过定义的端口名来进行辨别。其他想要在输入端口上接收消息的block必须订阅(subscribe)它。当一个block想要发送消息时,其可以使用以下API来进行消息的发布(published):

 C++ API:     void message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg);
 python API:  self.message_port_pub(pmt.intern("port name"), <pmt message>)

订阅的过程通常通过连接消息端口的形式完成(流图中的连线)。当消息端口被连接后,gr::basic_block::message_port_sub方法就会被调用。

3、消息处理函数

订阅的block必须声明消息处理函数来对接受到的信息进行处理,在使用message_port_register_in方法声明一个订阅(输入)端口后,需要将此端口绑定到消息处理程序。

在C++中可以使用以下lambda函数的方式(从GR3.8开始使用C++11标准)

 set_msg_handler(pmt::pmt_t port_id, 
   [this](const pmt::pmt_t& msg) { message_handler_function(msg); });

Python的使用方式为:

 self.set_msg_handler(pmt.intern("port name"), <msg handler function>)

当新的消息进入接收队列后,就是用以上函数进行消息处理,'port_id'就是注册端口时定义的pmt类型的名字。msg handler function就是处理函数名,可以根据实际情况自定义该函数名。

4、通过流程图连接消息

在流程图层面,模块之间消息端口的连接实质上是通过gr::hier_block2::msg_connect方法进行的。假设块src有一个名为pdus的输出端口,块dbg有一个名为print的输入端口,则在流图中的消息连接如下(Python):

self.tb.msg_connect(src, "pdus", dbg, "print")

所有由src的pdus端口发出的信息都可以被dbg块的print端口接收,这里为了方便起见,端口名称可以直接使用string类型作为参数。

另外,还可以使用以下API来查询block的输入或者输出端口名:

pmt::pmt_t message_ports_in();
pmt::pmt_t message_ports_out();

上述两函数的返回值是pmt类型的vector,且内部元素为PMT symbols。

5、从外部源发布数据

GNU Radio可以接收外部数据源的数据。在一个block中,可以使用gr::basic_block::_post方法直接接收外部数据,因此任何一个拥有输入端口的block都可以接收外部数据。

假设已经创建了一个名为src的块作为PDU进行数据流传输,并有一个名为pdus的输入引脚,我们要向该block发送一个外部数据,该数据可以来自另外一个block或者流图,这里我们手动创建一个数据单元并出入给src块(python)。

 port = pmt.intern("pdus")
 msg = pmt.cons(pmt.PMT_NIL, pmt.make_u8vector(16, 0xFF))
 src.to_basic_block()._post(port, msg)

这里msg的有效数据部分为16个全为0xff的字节。为了发布msg数据,我们需要使用gr::basic_block::to_basic_block方法来访问src块的gr::basic_block类,然后调用gr::basic_block::_post方法来将数据传送到正确的端口上。

注:pmt.cons部分的介绍可以看这里,GNU Radio 中的 PDU(protocol data unit,协议数据单元)有一个特殊的 PMT 类型,它是一对字典(在 CAR 上)和一个统一向量类型。因此,没有元数据和 10 个零可以产生一个有效的 PDU作为流数据:

pdu = pmt.cons(pmt.make_dict(), pmt.make_u8vector(10, 0))

6、使用消息传送命令

消息的一个重要的使用方式就是将命令传送给block。这方面的例子包括:

  • gr::qtgui::freq_sink_c:可以通过消息更改频率轴的缩放比例
  • gr::uhd::usrp_source 和 gr::uhd::usrp_sink:许多与收发器相关的设置可以通过命令消息进行操作,例如频率、增益等。

虽然没有特殊的 PMT 类型来对命令进行编码,但是强烈建议使用以下格式之一:

  • pmt::cons(KEY, VALUE):这种格式只能提供一对键值对,对于采用单个值的命令很有用。将 KEY 和 VALUE 分别视为参数名称和值。例如如果修改 QT GUI Frequency Sink 的参数,KEY 将是“freq”,VALUE 将是新的中心频率(以 Hz 为单位)。
  • pmt::dict((KEY1: VALUE1), (KEY2: VALUE2), ...):这种方式可以提供多个键/值对。可以用于当单个命令采用多个无法分解为多个命令消息的参数的情况。

在这两种情况下,所有 KEY 都应该是 pmt::symbols(即字符串)。 VALUE 可以是块需要的任何值。

7、一个消息传输的例子

此处使用嵌入Python块(Embedded Python Block)进行举例,并将该块重命名为 Message Python Block。作用是将由 QT GUI Message Edit Box 中输入的字符串转换为字节流输出。如下图所示。图中的embedded Python block命名为"Message Passing Demo"。在File Sink中,File为输出字符的保存文件的路径,可根据实际情况自行设定。注意,图中的虚线连接的是消息端口(message ports),实线连接的是数据流端口(streaming ports)

Embedded Python Block的代码如下:

import numpy as np
from gnuradio import gr
import pmt
# 初始化
textboxValue = ""

class my_sync_block(gr.sync_block):
    """
    reads input from a message port
    outputs text
    """
    def __init__(self):
        gr.sync_block.__init__(self,
            name = "Message Passing Demo",
            in_sig = None,  # 设置 stream 数据输入端口
            out_sig = [np.byte])  # 设置 stream 数据输出端口
        self.message_port_register_in(pmt.intern('msg_in'))  # 设置消息输入端口
        self.message_port_register_out(pmt.intern('clear_input'))  # 设置消息输出端口
        self.set_msg_handler(pmt.intern('msg_in'), self.handle_msg)  # 为msg_in端口的输入数据绑定消息处理函数函数

    def handle_msg(self, msg):
        global textboxValue  # 声明全局变量
        textboxValue = pmt.symbol_to_string (msg)
    
    def work(self, input_items, output_items):
        global textboxValue  # 声明全局变量
        _len = len(textboxValue)  # 获取字符串的长度
        if (_len > 0):
            # 增加换行符
            textboxValue += "\n"
            _len += 1
            # 再输出数组中存储字符串
            for x in range(_len):
                output_items[0][x] = ord(textboxValue[x])
            textboxValue = ""
            self.message_port_pub(pmt.intern('clear_input'), pmt.intern(''))
            return (_len)
        else:
            return (0)

观察流图可以发现,图中的Message Passing Demo输入是消息输出是数据流,事实上,只要消息的PMTs数据类型与数据流端口的数据类型相匹配,就可以在消息传递和流端口之间切换(在这个demo中,流端口的粉红色表示字节,而在Message Passing Demo中将message消息处理成ASCII码(字节)后输出,两者相匹配)。

另外,当一个message传送到一个block的端口后的处理方式取决于实际的block的设置,一般有以下两种方式:

  1. 调用消息处理函数,讲收到的数据传入该处理函数进行处理(例如本例中的 handle_msg 函数)
  2. 消息被写入FIFO缓存,block可以在任意需要的时候使用,通常在work函数中使用。

对于同时含有消息端口(message port)以及流端口(streaming port)的block来说可以根据实际的应用环境任选以上两种方式使用。但是强烈建议使用专门的消息处理函数处理消息,而不是在work函数中处理。这是由于如果在work函数中处理消息的话,同事还没有消息传来,work函数会一直等待(阻塞)消息传入才能继续运行,但work函数的运行是不能有阻塞的情况发生的!如果一个block的运行取决于消息,可以使用消息处理函数,然后在work函数被调用时通知block进行相应的操作。只有在特殊的、明确的场合,我们才应该在块中使用上面的方法2。

有了消息传递接口,我们就可以写出没有流端口的block,然后work函数就用不上了,因为work函数是一个旨在处理流式项目的函数事实上,没有流端口的块通常都没有work函数。

现在再看下面的图片是不是就清晰了很多~

(参考:https://wiki.gnuradio.org/index.php/Message_Passing)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GNU Radio中的消息传递机制(Message Passing) 的相关文章

  • Django 开发服务器消息 - 它们是什么意思?

    如果我运行 Django 开发服务器并在浏览器中查看我的应用程序 我会收到如下消息 08 一月 2011 18 12 45 获取 HTTP 1 1 200 2714 08 一月 2011 18 12 45 获取 static style c
  • 如何自动生成Makefile帮助命令

    我最近发现这篇文章在线 http marmelab com blog 2016 02 29 auto documented makefile html 这解释了如何设置make help目标将自动解析 Makefile 中的注释并显示格式良
  • 经过一段时间后,OpenEdge ABL 自动关闭是/否消息

    现在我有 消息 Hello World 查看为警报框警告按钮是 否更新 lVariable 如何在 14 秒后自动点击 否 如何以 另一种方式 做到这一点 DEFINE FRAME f message This is your messag
  • 来自 Process.MainWindowHandle 的 C# HwndSource

    我试图 挂钩 窗口的消息来检测最小化 最大化 我环顾四周 认为执行此操作的唯一 最佳解决方案是挂钩窗口的消息 并检查 WM WINDOWPOSCHANGED 消息 然后检查其状态 我遇到了问题 System Windows Interop
  • 如何在 Yii2 验证规则消息中添加换行符

    我需要打破 Yii2 验证规则中使用的长消息 我尝试这样 public function rules return username required message gt long message first line here br P
  • GNU Awk 4.2 中 FS = " " 的行为是什么?

    The first week of October Arnold Robbins announced Beta release of gawk 4 2 0 now available in the GNU announce bug gawk
  • BSD md5 与 GNU md5sum 输出格式?

    任何人都知道为什么 BSD md5 程序会产生这种格式的哈希输出 MD5 checksum md5 9eb7a54d24dbf6a2eb9f7ce7a1853cd0 而 GNU md5sum 会产生像这样更合理的格式 9eb7a54d24d
  • 通过 JavaMail 发送邮件时 Message-Id 被替换

    我试图找到一个解决方案 希望运气好 所以我决定将其发布在这里 问题是 当我使用 javaMail 发送消息时 它会自动生成一个消息 ID 我将其存储到数据库中 然后识别对此消息的回复 但当消息发送时 由于某种原因 smpt 服务器会更改该消
  • 在无锁设置中是否可以实现多生产者、单消费者?

    我有一堆线程相互之间进行大量通信 我希望这是无锁的 对于每个线程 我希望有一个邮箱 其他线程可以在其中向其发送消息 但只有所有者可以删除消息 这是多生产者单消费者的情况 我可以在无锁 高性能的情况下做到这一点吗 这是一个巨大模拟的内循环 无
  • 更改 withProgress() 生成的消息框的样式和位置

    The withProgress 函数可以生成一个消息框 指示闪亮的应用程序正在运行 但该消息位于浏览器的右上角 文字尺寸较小 这使得该消息不那么引人注目 所以我想知道有没有什么方法可以改变这个框的样式和位置 以便消息更具有表现力 这是我的
  • 调整控制台事件的大小

    所以我认为窗口调整大小事件将通过 winproc 进行 我可能是错误的 希望获得控制台调整大小事件的通知 我想在调整大小时最大化控制台缓冲区 一旦完成 基本上将其缩小回窗口大小 从而防止由于缓冲区小于窗口而导致溢出错误 不幸的是 答案是你无
  • 将 gcc libs .data 放在特定部分?

    我正在尝试为我们的嵌入式系统切换到 GNU GCC 编译器 但由于我们芯片的内存布局被分割 我在链接该项目时遇到了问题 RAM section 1 0x10000 0x12FFF RAM section 2 0x18000 0x1BFFF
  • 如何覆盖 Struts 2 消息?

    这是我的 struts xml 的一部分
  • Erlang 进程和消息传递架构

    我手头的任务是读取大文件的行 处理它们 并返回有序结果 我的算法是 从评估工作负载的主进程开始 写在文件的第一行 生成工作进程 每个工作进程将使用 pread 3 读取文件的一部分 处理这部分 并将结果发送给 master master接收
  • grep 正则表达式 空白行为

    我有一个文本文件 其中包含以下内容 12 34 EUR 5 67 EUR EUR 之前有一个空格 我忽略了 0 XX EUR 我试过 grep 1 9 0 9 0 9 2 sEUR gt didn t match grep 1 9 0 9
  • 向 Windows 窗体消息循环发送或发布消息

    我有一个线程从命名管道读取消息 它是阻塞读取 这就是它在自己的线程中的原因 当该线程读取消息时 我希望它通知主线程中运行的 Windows 窗体消息循环消息已准备就绪 我怎样才能做到这一点 在win32中我会做一个PostMessage 但
  • 链接器输入文件未使用的 c++ g++ make 文件

    我无法弄清楚是什么导致了我在制作项目时不断遇到的错误 i686 apple darwin11 llvm g 4 2 lncurses linker input file unused because linking not done 我的
  • 比较 timespec 值

    比较两个 timespec 值以查看哪个先发生的最佳方法是什么 下面这句话有什么问题吗 bool BThenA timespec a timespec b Returns true if b happened first b will be
  • Makefile 和通配符

    好吧 这是我当前的 makefile 设置 有一些文件名为public01 c public02 c等等 我正在尝试使用以下方法为每个人制作目标文件public o带有通配符的标签 public o public c hashtable h
  • 如何调用使用 Define 创建的 GNU make 宏?

    在我的 Makefile 中调用 GREP 的两种方式有什么区别吗 我有什么理由应该使用其中之一 两者似乎产生相同的结果 define GREP word 3 shell echo define FOO 0xfff00100 endef a

随机推荐

  • C++ 类和对象学习 —— 继承

    1 6 继承 利用继承技术 xff0c 可以减少重复代码 1 6 1 继承的基本语法 普通实现 span class token macro property span class token directive keyword inclu
  • 解决 VS 无法打开包括文件: “XXX.h”: No such file or directory问题

    每次封装管理 xff0c 当 Visual Studio 包含多个 h 文件和 c 文件 xff0c 运行时总会发生如下错误 错误 C1083 无法打开包括文件 XXX h No such file or directory test1 0
  • C++ 多态深入学习总结笔记

    多态和虚函数 1 通过案例理解多态 案例 xff1a 父类Animal xff0c 2个子类Dog和Cat xff0c 实现speak方法 未使用虚函数 virtual 声明 main h 文件 span class token keywo
  • LaTeX 报错! Missing $ inserted. <inserted text>$ l.44 问题解决

    学习LaTeX编辑器编辑数学公式时 xff0c 输入如下 xff1a 编译报错如下 xff1a 搜索方法 xff0c 并未得到有效解决 xff0c 机缘巧合把空行删除 xff0c 如下图所示 xff1a 再次编译未报错 xff0c 成功运行
  • 在 Microsoft Word 插入代码块(无需下载任何软件)

    Step 1 打开 CSDN Markdown 编辑器 xff0c 点击菜单栏上方代码块 xff0c 选择自己的代码语言 Step 2 插入代码如下图所示 xff0c 之后将代码复制 Step 3 打开 Microsoft Word xff
  • MATLAB 利用YALMIP+Gurobi 求解线性规划 -多无人机扫描覆盖

    使用要点 创建决策变量设置目标函数添加约束条件参数配置求解问题 问题描述 假设M个无人机的任务是尽快覆盖一组由 P 顶点表示的多边形凸区域 xff0c 假设每架无人机的最大飞行时间是有限的 xff0c 并且是预先知道的 每架无人机的都配备了
  • 毕业论文格式系列1 Word 图片交叉引用其题注

    图表论文自动编号 自动编号可以通过 Word 的 题注 功能实现 按论文格式要求 xff0c 第一章的图编号格式为 图1 X xff0c 具体做法如下 xff1a 将图插入文档中后 xff0c 选中新插入的图 xff0c 在 引用 菜单选
  • Visual Studio 2022 编译新版 Mission Planner 地面站

    下载安装VS 2022 安装时 xff0c 注意勾选 安装成功后 xff0c 从Visual Studio官方SDKs下载net461开发包 xff0c 网址 xff1a https dotnet microsoft com en us d
  • GNU Radio中的流标签(Stream Tags)

    目录 0 GR 中常用术语的官方解释 1 定义概述 2 在数据流中添加标签 3 添加标签的demo举例 4 从数据流中的获取标签 5 提取标签的demo举例 0 GR 中常用术语的官方解释 直接吧官方的解释抄过来 xff0c 直接看英文更容
  • 飞控学习随记

    常见指令 编译Arduplane程序 span class token builtin class name cd span ardupilot waf plane 进入 Tools autotest 文件夹中 xff0c 启动3D fli
  • 【无标题】

    apm飞控飞行模式详解 1 稳定模式Stabilize 稳定模式是使用得最多的飞行模式 xff0c 也是最基本的飞行模式 xff0c 起飞和降落都应该使用此模式 此模式下 xff0c 飞控会让飞行器保持稳定 xff0c 是初学者进行一般飞行
  • C# CustomMessageBox.Show() 输出多个变量调试

    Mission Planner 地面站调试中会遇到输出多个变量问题 xff0c 这里采用CustomMessageBox Show来输出调试多个变量 xff0c 用到string Format方法 span class token clas
  • MapReduce实验——学生总成绩报表,学生平均成绩

    学生总成绩报表 Map类 span class token keyword package span span class token class name StudentScore 06 span span class token pun
  • 【Docker操作必看,原来这才是正确打开Docker的新方式】

    前言 一 Docker操作镜像 首先镜像名称一般分为两个部分 xff1a repository tag xff0c 前者是镜像名 xff0c 后者是版本号 在没有指定tag的情况下 xff0c 默认是latest 代表的是最新版本 1 拉取
  • 第五章 FreeRTOS 任务基础知识

    5 1 什么是多任务系统 在使用 51 AVR STM32 单片机裸机 未使用系统 的时候一般都是在main 函数里面用 while 1 做一个大循环来完成所有的处理 xff0c 即应用程序是一个无限的循环 xff0c 循环中调用相应的函数
  • C语言for循环详解

    for 循环的使用更加灵活 xff0c 在日常的程序开发过程中我们会使用的更多一些 使用 while 循环来计算1加到100的值 xff0c 代码如下 xff1a include span class token generics func
  • Python批量下载sci-hub文献

    coding utf 8 import requests from bs4 import BeautifulSoup import os re path 61 34 Downloaded 34 if os path exists path
  • Ubuntu16.04 安装NS3.36.1及可视化模块

    如果不是必要 xff0c 尽量不要在Ubuntu 16 04上装3 36 1这个版本 xff0c 因为比较麻烦 NS3 36 1的新特性 安装依赖 一条一条执行 xff01 xff01 xff01 ns3 36需要用的python3 xff
  • ES6模块化及ES7新增特新性

    一 babel ES6代码转换为ES5的代码 1 初始化项目 npm init npm init y 不需要配置 xff0c 直接跳过 2 安装转码工具 cnpm install g babel cli cnpm install save
  • GNU Radio中的消息传递机制(Message Passing)

    目录 0 首先看下 GR 中一些常用术语的官方解释 1 定义理解 2 消息传递端口API 3 消息处理函数 4 通过流程图连接消息 5 从外部源发布数据 6 使用消息传送命令 7 一个消息传输的例子 0 首先看下 GR 中一些常用术语的官方