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

阅读: 评论:0

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

将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 .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: _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是传输不过来的,但是修改之后,却可以完成传输的过程,过程我,这里好像放不了视频,我给放哔哩哔哩了,可以点击查看传输的过程。/?spm_id_from=333.999.0.0

5、总结:

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

6、参考资料:

参考资料
[1]:
[2]:
[3]:
[4]: /?vd_source=cc2ad6f27704707aaa7e22b40e6d8b75#reply189349046432
[5]:.html
[6]:/?spm_id_from=333.999.0.0,本实验最终过程

本文发布于:2024-01-28 08:20:05,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064012096068.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:自己的   模块   源码   gnuradio   OOT
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23