将gnuradio源码中的模块添加制作成自己的OOT模块

2024-01-20 23:50

本文主要是介绍将gnuradio源码中的模块添加制作成自己的OOT模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

将gnuradio源码中的模块添加制作成自己的OOT模块(安装了release版本无法进入源码中编译,但是又不想卸载后安装源码版本)

    • 1、写这篇文章的原因
    • 2、Gnuradio流图和相关参数如下:
    • 3、Bug复现
    • 4、通过OOT定义外部用户模块来实现修改源码的曲线救国方案
      • i. 命令行输入命令查看Gnuradio版本
      • ii. guihub上下载Gnuradio源码文件,并且指定为与自己版本相同
      • iii. 创建OOT模块
      • iv. 根据源文件对创建OOT文件进行修改
        • 1、cc文件的修改
        • 2、impl.h文件的修改
        • 3、h文件的修改
        • 4、yml文件的修改
      • v. 编译安装测试
        • 1、编译整体过程
        • 2、编译安装
      • vi. 修改内部函数并测试结果
    • 5、总结:
    • 6、参考资料:

1、写这篇文章的原因

  1. 笔者也是刚刚从2023年暑假接触Gnuradio和SDR,其根本原因是在对比FPGA和Gnuradio之后,想要实现通信原理中的调制解调,并且想通过电磁波发送出去,验证理论与实际。同时想与深度学习结合,验证传统算法和DL的高下。Gnuradio感觉集成度更高一点,软件定义无线电,通过写代码模拟嵌入式系统。当然更大一部分的原因是其宜人的价格。

  2. 奈何资料是真的少,大部分的时间都在寻找资料的路上。不过遇到的良师亦有不少,但是由于个人设备的原因,产生了如下的问题:

    a. 环境已经安装好,gnudaio是直接sudo apt install gnuradio的,也就是release版本,无法找到源码的文件,并且也已经安装好全部的硬件的依赖环境,一切都能正常运行,在不想重新配置环境(配不通)的情况下,想要更改源码内容实现功能的改进。

    b. 在bilibili上跟着 张老师学习SDR,在学习到OFDM图传的那一课时,张老师在里面说到了一个Gnuradio中的 Header/Payload Demux 模块的底层bug问题。(超过10帧的数据会出现丢帧的现象,所以在发送图片的时候基本是理想的信道,也会出现问题)
    1、 西电研究生探究问题所在,并且解决问题(点击跳转)
    2、张老师的这个视频从1:17:28开始讲OFDM图传,并且介绍bug,视频前面也有OOT模块的创建的教程(点击跳转)

2、Gnuradio流图和相关参数如下:

理想的图传流图,OFDM图传报告,详细描述每个块的作用和参数,想学习可以参考一下(点击跳转);
整体的流图如下图:
这是接收端的
这是发送端

3、Bug复现

就上面流图而言,是理想的信道,只有一点点的噪声,根据算法应该可以恢复得很漂亮才对,但是在传输图片的时候却出现了如下的不合理的情况:
发送端
接收端
理想信道下居然有如此严重的失真,显然是不合理的,是模块内部算法有问题。具体原因就是前面链接中文章的介绍。解决方法如果是源码安装的Gnuradio根据前面视频中张老师的方法就可以解决。
下面是介绍没有源码安装又想解决这个问题的情况。
其根本的原因是:Header/Payload Demux 模块的底层bug问题

4、通过OOT定义外部用户模块来实现修改源码的曲线救国方案

  1. 先学习如何OOT:自己定义OOT模块(点击跳转学习)
  2. 学习如何创建OOT后,我们并不需要编写源码,因为源码的文件我们是可以通过网上找到的,这里我用我自己认为是正确方法进行源码的查找:

i. 命令行输入命令查看Gnuradio版本

gnuradio-config-info -v

在这里插入图片描述

ii. guihub上下载Gnuradio源码文件,并且指定为与自己版本相同

(个人感觉直接用源码可能也可以,有道友尝试过可以回复我一下)

git clone https://github.com/gnuradio/gnuradio.git
cd gnuradio
git checkout maint-3.8

通过这两步之后,我们就得到了源码,而我们的Header/Payload Demux中的cch文件地址就在:

gnuradio/gr-digital/lib			#下的cc和h文件
gnuradio/grc						#下的ymal文件
gnuradio/include/gnuradio/digital      #x下的h文件

搜索到找到这四个文件复制保存备用
在这里插入图片描述

iii. 创建OOT模块

根据教程在命令行输入:

在这里插入图片描述
创建了Myoot的文件夹,并且添加了自己的模块名为:my_heade,使用的是cpp语言,不需要验证(这里看个人情况而定)
经过上面的操作之后,文件路径下会有一个gr-Myoot的文件,并且里面的内容如下:

在这里插入图片描述
在lib文件下就是我们要修改的cc和h文件,在grc文件夹就是我们需要修改的yml文件,在include/Myoot是其头文件,这四个都是需要修改的文件。

iv. 根据源文件对创建OOT文件进行修改

1、cc文件的修改

查看cc文件,OOT模块和源文件的区别可以看到,头文件文件名是不一样的,为了修改文件的正确,选择最笨的方法进行修改,方法如下:(左边是自定义的cc文件,右边是源码文件)
在这里插入图片描述
修改后的如图
在这里插入图片描述
并且看到我们要找的函数正好对齐了在最下方。
这时我们继续根据源文件的内容,往创建的OOT文件中填入参数。比如make()中填入参数后如图所示:
在这里插入图片描述
同样填入参数和根据源文件修改函数内容后如图:
修改参数和函数
往后看到这两个函数

    my_heade_impl::~my_heade_impl(){}void my_heade_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required){/* <+forecast+> e.g. ninput_items_required[0] = noutput_items */}

my_heade_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
中用同样的方法修改后如图:

在这里插入图片描述
然后是函数在函数int my_heade_impl::general_work前后有自定义的函数,在如之前那样完成my_heade_impl::general_work函数的修改后,再进行自定义函数的修改。my_heade_impl::general_work函数是这个blk的启动函数,相当于是main()函数,很长内容很多,所以不贴图了。
注意一些自定义函数贴过来的时候要注意名字,要改成与自己文件名相同的名字。
general_work前有一个check_buffers_ready函数,修改名字后到我们的文件后如图:

在这里插入图片描述
将general_work函数同样的方法修改后,我们的文件后面就没有函数了,但是源文件上还有很多,这些都是一些自定义的函数,通过观察,发现都是header_payload_demux_impl类的函数,我们直接复制过来然后使用ctrl+f快捷键一键修改成我们设置的类my_heade_impl函数的名字即可:
替换后续函数
至此保存,cc文件修改完成。

2、impl.h文件的修改

注意有两个h文件,有impl的是和cc文件同一个文件夹的
同样的方式我们源文件和我们创建的h文件,同样修改文件,观察后发现需要修改的地方如下:
在这里插入图片描述
根据源文件填入后:
在这里插入图片描述

3、h文件的修改

通过观察,只有static sptr函数需要在static sptr make();填入参数即可:

      static sptr make(const int header_len,const int items_per_symbol = 1,const int guard_interval = 0,const std::string &length_tag_key = "frame_len",const std::string &trigger_tag_key = "",const bool output_symbols = false,const size_t itemsize = sizeof(gr_complex),const std::string &timing_tag_key = "",const double samp_rate = 1.0,const std::vector<std::string> &special_tags = std::vector<std::string>(),const size_t header_padding = 0);};
4、yml文件的修改

通过观察这两个文件,找到这个同样的东西:
在这里插入图片描述
将源码中parameter的东西,除了头,都复制过来,然后再修改上面图片中make: Myoot.my_heade()中的参数,都贴过来,然后删除多余的东西,file_format:1就是代码的最后一行了,后面我们需要继续修改里面的一些参数。
在这里插入图片描述
到这一步,需要修改cpp_templates的一些参数,网上找不到相关的资料,这里笔者也是瞎猫乱来的,在这里希望有高手兄可以指点一下我。先后找了很多资料,后来实在不知道如何,问了问AI:

这看起来是一个YAMLYAML Ain't Markup Language)配置文件的一部分,
用于定义和配置一个名为 `cpp_templates` 的组件,可能用于某种软件工程项目。
让我为您解释其中的各个部分:1. `cpp_templates`(组件名称): 
这是配置文件中的一个部分或部件,用于定义一些属性和操作。2. `includes`(包含语句): 这是一个包含了一个或多个C++头文件的列表。
在这种情况下,它包括了 `<gnuradio/digital/header_payload_demux.h>` 头文件,
表示在编译时需要包含这个头文件以使用其中的功能。3. `declarations`(声明): 这是一个C++代码片段,用于声明一个变量。
在这里,它声明了一个名为 `${id}` 的变量,其类型是 `digital::header_payload_demux::sptr``${id}` 看起来像是一个占位符,可能在稍后的配置文件中有具体的值。4. `make`(初始化): 这是一个C++代码块,用于初始化先前声明的变量 `${id}`。
它使用了一些参数,如 `${header_len}``${items_per_symbol}` 等等,这些参数可能也是占位符,
其具体值可能在其他地方定义或提供。5. `link`(链接库): 这是一个列表,指定了与该组件相关联的库。在这里,
它包括了 `'gnuradio-digital'`,
表示需要链接到 `gnuradio-digital` 这个库。6. `translations`(翻译): 这是一个键-值对的映射,用于定义将布尔值 `'True'``'False'` 
转化为相应的C++ 布尔值 `'true'``'false'`。这可能是因为不同的编程语言或库使用不同的布尔表示方式。这个配置片段的具体用途可能需要结合更多的上下文来理解。
通常情况下,这种配置文件用于配置和生成代码或定义特定的组件,以便在软件工程项目中使用。

最终修改成一下的样子

cpp_templates:includes: ['#include <gr-Myoot/my_heade.h']declarations: 'gr::Myoot::my_heade::sptr ${id};'make: |-this->${id} = gr::Myoot::my_heade::make(${header_len},${items_per_symbol},${guard_interval},${length_tag_key},${trigger_tag_key},${output_symbols},${type.cpp_itemsize},${timing_tag_key},${samp_rate},${special_tags},${header_padding});link: ['gnuradio-Myoot']translations:'True': 'true''False': 'false'

这个我也尝试了其它的名字,感觉都可以,不知道什么原因。保存,至此我们完成全部文件的修改,将修改好的文件替换没有修改的文件,接着我们开始在命令行编译。

v. 编译安装测试

1、编译整体过程

打开命令行,进入我们前面生成的文件夹中,我们这里是==(gr-Myoot文件夹)==
因为笔者已经安装过了,我再此修改一下yml中的文件的第二个参数,这个参数是模块的名字,我将其更改为:my_head/半盏生
主要步骤如下,前面的链接中的教程,也有详细的过程:

cd gr-Myoot
mkdir build
cd build
cmake ../
make
sudo make install
sudo ldconfig
2、编译安装

编译的过程如下,1、cmake
在这里插入图片描述
2、make
在这里插入图片描述
3、sudo make install
4、sudo ldconfig
在这里插入图片描述
打开Gnuradio,刷新之后,可以查找到我们添加的blk
在这里插入图片描述
将它替换原本的模块,完美的运行了,当然生成的也是失真的图片,因为到目前为止我们并没有进行header块内部函数的修改。根据前面张老师的方法,我们只需要修改一个参数。下面我们修改这个参数,以便解决这个问题。

vi. 修改内部函数并测试结果

打开cc文件,查找const int items_padding,然后修改方法如下:

 //const int items_padding = std::max(d_header_padding_total_items, 1);  //源文件的代码const int items_padding = std::max(d_header_padding_total_items, 3);//修改后的代码(将1改成3)

将后面的1改成3,当然张老师的视频有详细的讲解原理。大家有兴趣可以详细观看,肯定有所收获。

修改的代码块如下:

case STATE_PAYLOAD:// Assumptions:// - Input buffer is in the right spot to just start copyingif (check_buffers_ready(d_curr_payload_len,0,noutput_items,d_curr_payload_len * (d_items_per_symbol + d_gi),ninput_items,n_items_read)){// Write payloadcopy_n_symbols(in,out_payload,PORT_PAYLOAD,n_items_read_base + n_items_read,d_curr_payload_len);// Consume payload// We can't consume the full payload, because we need to hold off// at least the padding value. We'll use a minimum padding of 1// item here.//const int items_padding = std::max(d_header_padding_total_items, 1);  //源文件的代码const int items_padding = std::max(d_header_padding_total_items, 3);//修改后的代码(将1改成3)const int items_to_consume =d_curr_payload_len * (d_items_per_symbol + d_gi) - items_padding;CONSUME_ITEMS(items_to_consume);set_min_noutput_items(d_output_symbols ? 1 : (d_items_per_symbol + d_gi));d_state = STATE_FIND_TRIGGER;}break;

完成修改后,我们重复之前 v 中的步骤,步骤如下:

1、cd gr-Myoot/build
2、make
3、sudo make install
4、sudo ldconfig

之后连接流图如图,可以看到传输的图片是很漂亮的:

在这里插入图片描述
再传输了之前传输失败的一些图片,如此图:
在这里插入图片描述
用原来文件的header是传输不过来的,但是修改之后,却可以完成传输的过程,过程我,这里好像放不了视频,我给放哔哩哔哩了,可以点击查看传输的过程。https://www.bilibili.com/video/BV14841167QV/?spm_id_from=333.999.0.0

5、总结:

笔者仍在学习,后面打算搭建一个完整的通讯过程,加入深度学习的内容,奈何要学习的东西实在太多,很多东西都找不到突破口,希望能得到大家的指点,共同学习。

6、参考资料:

参考资料
[1]: https://blog.csdn.net/Flag_ing/article/details/121272591
[2]: https://blog.csdn.net/Flag_ing/article/details/120468143
[3]: https://blog.csdn.net/Flag_ing/article/details/118568932
[4]: https://www.bilibili.com/video/BV1yj41197ym/?vd_source=cc2ad6f27704707aaa7e22b40e6d8b75#reply189349046432
[5]:https://www.docin.com/p-4015404154.html
[6]:https://www.bilibili.com/video/BV14841167QV/?spm_id_from=333.999.0.0,本实验最终过程

这篇关于将gnuradio源码中的模块添加制作成自己的OOT模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627748

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除