本文主要是介绍将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、写这篇文章的原因
-
笔者也是刚刚从2023年暑假接触Gnuradio和SDR,其根本原因是在对比FPGA和Gnuradio之后,想要实现通信原理中的调制解调,并且想通过电磁波发送出去,验证理论与实际。同时想与深度学习结合,验证传统算法和DL的高下。Gnuradio感觉集成度更高一点,软件定义无线电,通过写代码模拟嵌入式系统。当然更大一部分的原因是其宜人的价格。
-
奈何资料是真的少,大部分的时间都在寻找资料的路上。不过遇到的良师亦有不少,但是由于个人设备的原因,产生了如下的问题:
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定义外部用户模块来实现修改源码的曲线救国方案
- 先学习如何OOT:自己定义OOT模块(点击跳转学习)
- 学习如何创建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中的cc和h文件地址就在:
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:
这看起来是一个YAML(YAML 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模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!