GNU Radio 学习使用 OOT 系列教程:

GNU Radio3.8创建OOT的详细过程(基础/C++)

GNU Radio3.8创建OOT的详细过程(进阶/C++)

GNU Radio3.8创建OOT的详细过程(python)

GNU Radio自定义模块:Embedded Python Block的使用

GNU Radio3.8:编辑yaml文件的方法

GNU Radio3.8:创建自定义的QPSK块(C++)

GNURadio 3.9 使用 OOT 自定义模块问题记录

GNURadio3.9.4创建OOT模块实例

----------------------------------------------------------------------------------------

目录

一、什么是Out of Tree(OOT)

二、工具软件的准备

1、gr_modtool

2、代码格式

3、CMake及Make等

三、创建一个OOT模块(module)的过程

1、创建module

2、为module添加block

3、编写block的测试代码(可选,不想写可略过直接到下一步)

4、编写block的C++代码

5、使用CMake编译并测试代码

6、使自定义的block在GRC中生效

7、最后一步:安装并加载

8、卸载已安装的block

9、module 创建流程总结

四、结语


文章虽长,但他也详细丫~只要认真学总会学会的哦~首先总结下所有设计的步骤流程以供参考:

  1. 创建module:gr_modtool newmod MODULENAME
  2. 为module添加block:gr_modtool add BLOCKNAME
  3. 创建build文件夹:mkdir build/
  4. 编译:cd build && cmake <OPTIONS> ../ && make
  5. 调用测试文件:make test 或 ctest or ctest -V for more verbosity(可选)
  6. 生成yaml文件,需要时手动修改:gr_modtool makeyaml BLOCKNAME
  7. 安装:sudo make install
  8. ubuntu环境下重新加载库文件:sudo ldconfig
  9. 卸载或删除block:sudo make uninstall 或 gr_modtool rm REGEX

一、什么是Out of Tree(OOT)

OOT模块是不存在于 GNU Radio 源代码树中的 GNU Radio 组件。如果想自定义一个全新的GR模块,那么创建一个OOT就是不二之选。可以使用C++或Python来建立OOT模块,下面将逐个介绍

二、工具软件的准备

1、gr_modtool

gr_modtool是在安装GR时自带的一个模块编辑脚本,可以帮助生成模板、自动生成makefile文件等,大大减轻了模块编辑前的工作量。另外gr_modtool对代码的格式做了很多限定,因此在自定义代码块的过程中,自定义的代码部分越多则gr_modtool所提供的帮助就越少,但gr_modtool仍是着手自定义一个模块的最好选择。

2、代码格式

GR源代码树中的代码遵循一个统一的编写格式,其中的主要定义的说明及编码范式可以参考这个链接,特别注意其中的命名规范。例如本例中使用的名为 square1_ff 的 block ,注意后缀 ff 的名规则,意味着输入是 float 类型的数据,输出也是 float 类型的数据。

3、CMake及Make等

众所周知,这两个工具是编译C++代码的必备技能,再次不再赘述了哈~

三、创建一个OOT模块(module)的过程

1、创建module

以创建一个名为 mymod 的模块(一个模块可以含有很多block)为例。在目标文件夹(我这里是建了一个空文件夹 temp,注意不要在GR源代码树文件夹中创建OOT)中打开终端输入命令gr_modtool newmod mymod,会出现以下结果:

wsx@wsx:~/temp$ gr_modtool newmod mymod
Creating out-of-tree module in ./gr-mymod...
Done.
Use 'gr_modtool add' to add a new block to this currently empty module.

这时 temp 文件夹中就会多了一个名为 gr-mymod 的文件夹,打开该文件夹可以看到里面的内容如下:

在这些子文件夹中,未来所有使用C++或者其他非Python语言所编写的代码将会放到 lib/ 文件夹中。对于C++文件来说,其头文件一般放入 include/(一般是创建module时就有的基础的底层头文件)或 lib/(一般是跟创建的block有关的头文件,例如 **_impl.h 文件,后面会看到)中 。

python 相关的文件放在 python/ 文件夹中。

尽管有些GR块是使用C++编写,其仍可使用 python 进行调用并运行,在 GR3.8 中,这得益于 SWIG(simplified wrapper and interface generator) , 它会自动创建粘合代码来实现这一点。但是swig需要一些生成粘合代码的指引,这些文件都放在 swig/ 文件夹中,一般不需要进入 swig/ 目录进行编辑,gr_modtool 自动会为我们生成这些文件。

:从 GNU Radio 3.9 版本开始,python 与 c++ 的绑定不再使用swig,而是使用 pybind11 (version > 2.5.0)进行处理的,这与以前的版本有本质的不同。因此如果是使用 GR3.9 创建OOT,虽然仍然还默认生成 swig/ 文件夹,但是里面自始至终都没有文件,这时的一些粘和代码文件都放在了 python/bindings 中了。

另外,如果想让这些模块在 gnuradio-companion 中使用,则需要在 grc/ 文件夹中添加这些块的描述文件,在GR3.8版本之前是XML文件,但是在3.8及之后的版本需要YAML文件。

文档 docs/ 主要包含一些类似于readme的说明性文档。

apps/ 子目录包含与块(block)一起安装到系统的所有完整应用程序(包括 GRC 和独立可执行文件)。

目录 examples/ 可用于保存示例,这是一个很好的文档附录,因为其他开发人员可以直接查看代码以了解如何使用编写的块。

构建系统也带来了一些其他文件:CMakeLists.txt 文件(存在于每个子目录中)和 cmake/ 文件夹。cmake/ 文件夹主要为 CMake 提供有关如何查找 GNU Radio 库等的说明,需要编辑 CMakeLists.txt 文件以确保模块正确构建。

下面介绍往模块(module)中添加一个块(block)的过程及实例

该文件计算输入的一个float类型数据的平方并输出一个float型数据(根据命名规范,square1_ff代表输入是float数据输出也是float数据的块)。

我们将使这个块以及我们在本文中编写的其他块,最终出现在 mymod Python 模块中。这样我们就可以在 Python 中访问它,类似如下的操作:

import mymod
sqr = mymod.square_ff()

2、为module添加block

首先需要为这个块创建空文件,然后编辑 CMakeLists.txt 文件。可以注意到,前面使用gr_modtool创建一个新的module后terminal打印的log的最后一行的提示信息是:

Use 'gr_modtool add' to add a new block to this currently empty module.

因此,我们在 gr-mymod 文件夹中打开终端输入命令:gr_modtool add -t general -l cpp square1_ff来创建一个名为 square1_ff 的 block,结果如下:

wsx@wsx:~/temp/gr-mymod$ gr_modtool add -t general -l cpp square1_ff
GNU Radio module name identified: mymod
Language: C++
Block/code identifier: square1_ff
Please specify the copyright holder:
Enter valid argument list, including default arguments:
Add Python QA code? [Y/n] y
Add C++ QA code? [y/N] n
Adding file 'lib/square1_ff_impl.h'...
Adding file 'lib/square1_ff_impl.cc'...
Adding file 'include/mymod/square1_ff.h'...
Editing swig/mymod_swig.i...
Adding file 'python/qa_square1_ff.py'...
Editing python/CMakeLists.txt...
Adding file 'grc/mymod_square1_ff.block.yml'...
Editing grc/CMakeLists.txt...

命令中使用到的一些指令的含义如下(可通过命令 gr_modtool add --help 查看):

  • -t:block-type,即block的类型,可选类型有:[sink、source、sync、decimator、interpolator、general、tagged_stream、hier、noblock]
  • -l:language,即想使用什么语言编写该block的代码,可选类型有[cpp、python、c++]

在上述命令及打印的log信息中可以看出,我们指定添加一个block块,块的名字叫square1_ff,它的类型是‘general’(因为我们还不知道这个块属于什么类型,所以这里就使用”通用“类型)。这个块是使用C++编写的。执行命令后,gr_modtool会询问块是否接受参数(此处没有,所以我们将其留空,直接回车进行下一步),下面是询问我们是否需要 Python 的 QA 代码(即测试文件),此处选择yes;后面是C++的QA,选择no(python版的就够了哈~)。最后可以看到,gr_modtool创建了很多文件,我们需要对这些文件进行编辑才能让我们的square_ff块起作用。

================================  BUG ==================================

可能有的小伙伴在执行上述操作时会遇到找不到clang-format文件的错误:

。。。。。。
Add Python QA code? [Y/n] y
Add C++ QA code? [y/N] n
Adding file 'lib/square1_ff_impl.h'...
Failed to run clang-format: %s [Errno 2] No such file or directory: 'clang-format'
Adding file 'lib/square1_ff_impl.cc'...
Failed to run clang-format: %s [Errno 2] No such file or directory: 'clang-format'
Adding file 'include/mymod/square1_ff.h'...
Failed to run clang-format: %s [Errno 2] No such file or directory: 'clang-format'
。。。。。。

这时只需输入以下命令安装 clang-format 即可:

sudo apt install clang-format

================================  END ==================================

强行剧透:为便于理解,就提前将前面创建的名为 mymod 的 module 以及名为 square1_ff 的 block 最终在GRC中的显示放出来,注意 module 与 block 之间的包含关系:

3、编写block的测试代码(可选,不想写可略过直接到下一步)

在开始编写C++程序之前,我们最好编写测试程序(非必要但却是一个比较好的习惯,而且过程很简单哦~)。针对块square1_ff就是输入一个单精度数据流,输出一个平方后的数据流,并判断结果是否正确。我们打开文件python/qa_square1_ff.py,可以像下面这样编写代码:

from gnuradio import gr, gr_unittest
from gnuradio import blocks
import mymod_swig as mymodclass qa_square1_ff(gr_unittest.TestCase):def setUp(self):self.tb = gr.top_block()def tearDown(self):self.tb = Nonedef test_001_square1_ff(self):src_data = (-3, 4, -5.5, 2, 3)  # 给出源数据expected_result = (9, 16, 30.25, 4, 9) # 正确的结果src = blocks.vector_source_f(src_data)  # 获取src_data的元素sqr = mymod.square1_ff()  # 需要进行测试的块  注意,这行代码在GR3.9中为 sqr =square1_ff(),因为3.9中的默认加载方式为 from mymod import square1dst = blocks.vector_sink_f()  # 用来获取mymodule.square_ff的输出self.tb.connect(src, sqr) # 依次连接上述src\sqr\dst三个模块,生成相应的流图self.tb.connect(sqr,dst)self.tb.run()result_data = dst.data()self.assertFloatTuplesAlmostEqual(expected_result, result_data, 6)  # 判断结果是否正确# check dataif __name__ == '__main__':gr_unittest.run(qa_square1_ff)  # 运行生成的图

其中,gr_unittest 是标准 Python 模块 unittest 的扩展。 gr_unittest 添加了对检查浮点数和复数元组的近似相等性的支持。详细的机制可以参考 Python unittest documentation。为了后面跟好的调试,最好先要弄懂代码的意思。

Unittest 使用了python的反射机制来查找所有以 test_ 开头的方法并运行它们。当我们运行这个测试文件时,gr_unittest.main 将按顺序调用  setUptest_001_square1_ff  和  tearDown 这三个函数。在代码的主体 test_001_square1_ff 函数中创建了一个包含三个节点的小型流图,在在代码中的体现就是 src、sqr、dst。run() 函数运行这个流图,之后对输出的结果进行验证。

另外,需要注意的是,这些测试一般是在模块进行安装之前运行的,即在 make 操作之后,sudo make install 之前。(如果还记得编译安装gnuradio时的操作,当时执行 make 命令之后执行的 make test 命令就是这个原理)

为了让后面使用CMake时系统知道测试文件的存在,gr_modtool 在生成测试文件的同时自动修改了python/CMakeLists.txt 文件,这个就不需要手动修改了。

4、编写block的C++代码

所有信号处理块都是由gr::block或其子类来进行驱动的。gr_modtool已经为我们提供了三个文件来定义块:lib/square_ff_impl.hlib/square1_ff_impl.cc 以及 include/mymod/square1_ff.h。我们要做的就是对这些文件进行修改以满足我们的需求。代码编写的结构可以参考 Blocks Coding Guide。

首先,对于头文件(include/)来说,由于此处实现的功能比较简单,一般不需要修改,因为在使用 gr_modtool 时就已经将需要的头文件包含的很全面了。

下面我们来看对lib/square1_ff_impl.cc的修改(哔哔一句,impl即implement,意思是实现,懂了吧^.^)。

对于GR3.8来说,gr_modtool 将需要修改代码的位置用 <+×××+> 提示出来,如下:

square1_ff_impl::square1_ff_impl(): gr::block("square1_ff",gr::io_signature::make(<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>)),gr::io_signature::make(<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>)))
{}

对于GR3.9版本来说,gr_modtool 将需要修改代码的位置用 预处理指令#pragma message 提示出来,但是最终的代码都是一样的。如下:

#pragma message("set the following appropriately and remove this warning")
using input_type = float;
#pragma message("set the following appropriately and remove this warning")
using output_type = float;
。。。省略部分代码。。。
#pragma message("Implement the signal processing in your block and remove this warning")// Do <+signal processing+>

square1_ff_impl.cc文件中,我们需要修改的函数为:

square1_ff_impl::square1_ff_impl()

square1_ff_impl::forecast()

square1_ff_impl::general_work()

修改方式以及各个函数的作用如下(注意看代码注释里的解释哦):

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif#include <gnuradio/io_signature.h>
#include "square1_ff_impl.h"namespace gr {namespace mymod {square1_ff::sptrsquare1_ff::make(){return gnuradio::get_initial_sptr(new square1_ff_impl());}/* 私有构造函数 所有信号处理块都是 gr::block 或其子类的派生类*/square1_ff_impl::square1_ff_impl(): gr::block("square1_ff",gr::io_signature::make(1, 1, sizeof (float)),gr::io_signature::make(1, 1, sizeof (float))){ }// 构造函数留空,因为该block不需要设置任何东西。 /*  虚拟析构函数 */square1_ff_impl::~square1_ff_impl(){}/* forecast函数作用为:告诉调度器有多少输入items被用来生成多少个输出items,这里他们是一样的 */voidsquare1_ff_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required){ninput_items_required[0] = noutput_items;// 索引0代表这是第一个输入端口,这里我们只有一个输入端口}// general_work()是定义在基类gr::block中的纯虚函数,因此在子类中必须进行重写// general_work()是执行实际信号处理任务的函数intsquare1_ff_impl::general_work (int noutput_items,gr_vector_int &ninput_items,gr_vector_const_void_star &input_items,gr_vector_void_star &output_items){const float *in = (const float *) input_items[0];float *out = (float *) output_items[0];for(int i = 0; i < noutput_items; i++) {out[i] = in[i] * in[i];}// Tell runtime system how many input items we consumed on// 每个输入数据流需要消耗多少items,由于ninput_items=noutput_items,这里填noutput_itemsconsume_each (noutput_items);// Tell runtime system how many output items we produced.return noutput_items;}} /* namespace mymod */
} /* namespace gr */

=========================== 相关函数具体解释 ============================

(参考自:GNU Radio Manual and C++ API Reference: gr::block Class Reference)

square1_ff_impl() 函数中第一个参数就是模块的名字,后两个函数参数依次用来定义输入和输出端口的属性,gr::io_signature::make 函数前两个参数分别代表该模块所允许的最少/最多的输入/输出端口数,第三个参数代表一个数据项(items)的字节数(这里注意一个数据项可以是一般的int、float、char 等数据类型,也可以是一个向量(如一个 OFDM sambol)等数据类型,一堆数据项组成一个数据流)。

这里解释下 consume_each() 函数。不过在这之前首先要介绍下 consume() 函数,该函数的原型如下:

void gr::block::consume   (int which_input,int how_many_items )       

作用是告诉调度器每生成一次输出数据,数据流“which_input”(即哪个输入端口)消耗了多少个输入数据项(how_many_items个)。该函数用来设置单个输入端口,并用在 general_work() 中调用,告诉调度程序处理的输入数据项(items)的数量。但是如果所有的输入端口的输入输出比是一样的话,就可以调用 consume_each() 函数进行统一设置。该函数的原型如下:

void gr::block::consume_each( int how_many_items )

然后是forecast() 函数。该函数原型如下:

virtual void gr::block::forecast(int noutput_items,gr_vector_int & ninput_items_required )    

参数 noutput_items 代表产生的输出数据项的数量,ninput_items_required 表示需要从输入端口中使用多少个数据项。在代码运行过程中,系统需要知道需要多少数据才能确保每个输入数组的有效性,forecast() 方法提供了此信息,因此必须在编写 gr::block 派生类的任何时候重写这个函数(对于 sync 类型的块,这是隐式的,文章结尾会提到这种 block)。函数的作用为评估生成 noutput_items 个输出,需要多少(ninput_items_required)个输入 items 。不过官方文档中特别说明了这个估计值不一定要准确,但应该接近。感觉系统可能会根据我们在代码中指定的输入输出的 items 的数量关系来设置一个具有盈余的存储空间吧,这样可以提升系统的鲁棒性。

general_work() 函数的返回值可以是输出数据项的数量也可以是 WORK_CALLED_PRODUCE 或者 WORK_DONE 。WORK_CALLED_PRODUCE 用于并非所有输出都产生相同数量的数据项的场合,WORK_DONE 表示这个块将不再产生数据。

=====================================================================

5、使用CMake编译并测试代码

在顶层文件夹gr-howto中依次输入以下命令(C++通用话术,懂得都懂—_—):

cd path-to-your-top-directory
mkdir build
cd build/
cmake ../
make
# sudo make install  莫慌莫慌,现在先不急着安装哈~

make 之后执行 make test 命令进行功能测试,如果不是测试文件本身编写有误,一般不会出现问题(如果是GR-v3.9,则可能会出现bug,解决方法见文末):

wsx@wsx:~/temp/gr-mymod/build$ make test
Running tests...
Test project /home/wsx/temp/gr-mymod/buildStart 1: qa_square1_ff
1/1 Test #1: qa_square1_ff ....................   Passed    0.48 sec100% tests passed, 0 tests failed out of 1Total Test time (real) =   0.48 sec

如果在 make test 的过程中遇到了测试失败的问题,可以通过指令 ctest -V (仍然在build文件夹中)来查询具体测试失败的原因。在这里可以使用 ctest -V -R square 来查看详细的错误信息,其中 “-V ”可以提供详细的输出信息,“-R” 后跟的是一个正则表达式,只运行那些匹配的测试,这里匹配的是square。

6、使自定义的block在GRC中生效

若想使得自定义的 block 像其他 GR 自带的 block 一样出现在 GRC 中使用,就需要编辑相应的 YAML文件,YAML文件在使用 gr_modtool add ××× 命令创建 block 时已经自动生成,但只是生成了框架,在该例中,yaml文件路径为:grc/mymod_square1_ff.block.yml

另外,在完成代码编译之后,可以在 gr_mymod 文件夹中使用 gr_modtool 工具辅助生成 YAML 文件来覆盖之前生成的框架文件。命令行操作如下:

wsx@wsx:~/temp/gr-mymod$ gr_modtool makeyaml square1_ff
GNU Radio module name identified: mymod
Warning: This is an experimental feature. Don't expect any magic.
Searching for matching files in lib/:
Making GRC bindings for lib/square1_ff_impl.cc...
Overwrite existing GRC file? [y/N] y

执行命令后,会自动生成新的名为 mymod_square1_ff.block.yml 的 yaml 文件并覆盖原来的文件。如下所示:

id: mymod_square1_ff
label: square1 ff
category: '[Mymod]'
templates:imports: import mymodmake: mymod.square1_ff()
inputs:
- label: indomain: streamdtype: float
outputs:
- label: outdomain: streamdtype: float
file_format: 1

对于该例来说,由于逻辑比较简单,所以生成的yaml文件不用修改即可使用。但是在 block 的功能比较复杂的情况下,这样生成的 yaml 文件并不能完成所有参数的配置,还需要手动进行额外的配置。至于如何进行进一步修改以及 yaml 文件中每个关键字的用法及含义可以参考这篇文章。

====================== 执行 makeyaml 时遇到的bug =====================

在执行 makeyaml 时遇到了问题:

wsx@wsx:~/temp/gr-mymod$ gr_modtool makeyaml square1_ff
GNU Radio module name identified: mymod
。。。。。。
Error: Can't parse input signature.
Error: Can't parse output signature.
。。。。。。

主要是说没法解析输入输出端口,这个问题其实有点奇怪。我第一次遇到这个问题竟然是因为在设置端口的那两句代码后面打了注释。。emmmm,就像下面这样:

square1_ff_impl::square1_ff_impl(): gr::block("square1_ff",gr::io_signature::make(1 , 1 , sizeof(input_type)),  // 这里是个注释gr::io_signature::make(1 , 1 , sizeof(output_type)))
{}

当我把注释去掉后,bug 就没了(别问我怎么知道这个问题的,问就是掐之一算猜出来的,泪),这可能是这个官方的 makeyaml 的脚本本身在解析代码时的小bug吧。

放个github链接

=================================================================

7、最后一步:安装并加载

在完成以上所有工作之后,回到 build/ 文件夹中,在终端中再次输入指令进行安装:

cd build/
sudo make install
sudo ldconfig  # 重新加载ubuntu库文件

至此,创建一个OOT module的工作就完成了,我们打开GRC,来看一下刚刚创建的block吧~

运行该流图,可以发现输出波的幅值(2.25)为输入(1.5)的平方,yep!

8、卸载已安装的block

1、如果是想卸载已经安装到系统中的 block,则 cd 到 build 文件夹中执行 sudo make uninstall 命令即可。

2、如果单单是想删除 module 中的 block 有关的文件(如果已安装,并不卸载安装,一般用于block的编辑阶段),则 cd 到 module 文件夹中,在命令行中执行 gr_modtool rm REGEX 命令即可,如下:

wsx@wsx:~/temp/gr-mymod$ gr_modtool rm square
GNU Radio module name identified: mymod
Searching for matching files in lib/:
Really delete lib/square1_ff_impl.cc? [Y/n/a/q]: y
Deleting lib/square1_ff_impl.cc.
Deleting occurrences of square1_ff_impl.cc from lib/CMakeLists.txt...
Really delete lib/square1_ff_impl.h? [Y/n/a/q]: y
Deleting lib/square1_ff_impl.h.
Deleting occurrences of square1_ff_impl.h from lib/CMakeLists.txt...
Searching for matching files in include/mymod/:
Really delete include/mymod/square1_ff.h? [Y/n/a/q]: y
Deleting include/mymod/square1_ff.h.
Deleting occurrences of square1_ff.h from include/mymod/CMakeLists.txt...
Searching for matching files in swig/:
None found.
Searching for matching files in python/:
Really delete python/qa_square1_ff.py? [Y/n/a/q]: y
Deleting python/qa_square1_ff.py.
Deleting occurrences of qa_square1_ff.py from python/CMakeLists.txt...
Searching for matching files in grc/:
Really delete grc/mymod_square1_ff.block.yml? [Y/n/a/q]: y
Deleting grc/mymod_square1_ff.block.yml.
Deleting occurrences of mymod_square1_ff.block.yml from grc/CMakeLists.txt...

9、module 创建流程总结

  1. 创建module:gr_modtool newmod MODULENAME
  2. 为module添加block:gr_modtool add BLOCKNAME
  3. 创建build文件夹:mkdir build/
  4. 编译:cd build && cmake <OPTIONS> ../ && make
  5. 调用测试文件:make test 或 ctest or ctest -V for more verbosity
  6. 生成yaml文件,需要时手动修改:gr_modtool makeyaml BLOCKNAME
  7. 安装:sudo make install
  8. ubuntu环境下重新加载库文件:sudo ldconfig
  9. 卸载或删除block:sudo make uninstall 或 gr_modtool rm REGEX

四、结语

大家还记得在本文这个例子中,我们创建的 block 为 general 类型的,这种类型的 block 在数据量的输入输出比的设置上(通过 forecast 和 consume 函数设置)具有很高的灵活性,这点体现出了其“通用”性所在。但是在一般的信号处理任务中,数据量的输入输出比往往是固定的,常用的是 1:1 、1:N 或 N:1这样的固定比例。所以现在就可以思考一个问题:如果一个 block 的输入数据量等于其输出数据,我们有必要再去将这个相同的数据量告诉 GR 两次吗?答案一定是否定的!因此在这种情况下我们就有理由去写一个相相对简化版的 block ,这就是 下篇文章 要说的 sync 类型的 block。

sync 类型的块派生自 gr::sync_block ,而 gr::sync_block 同时是这篇文章中 square1_ff 所继承的父类 gr::block 的子类,可以用来实现一个1:1输入输出的 block。本例中的有关继承关系可以查看 include/mymod/square1_ff.h 以及 lib/square1_ff_impl.h 。

另外还有一个事实必须要清楚,即所有信号处理块都是 gr::block 或其子类的派生类

另外,在使用GR-v3.9创建OOT的过程中可能会出现一些bug:

1、Unable to coerce endpoints when making a block in OOT module

解决方法可参考:

Unable to coerce endpoints when making a block in OOT module · Issue #4773 · gnuradio/gnuradio · GitHub

GNU Radio 3.9 OOT Module Porting Guide - GNU Radio

2、ImportError: generic_type: type "square_ff" referenced unknown base type "gr::block"

解决方法可参考:

ImportError: generic_type: type "square_ff" referenced unknown base type "gr::block" · Issue #4841 · gnuradio/gnuradio · GitHub

参考整理自:

OutOfTreeModules - GNU Radio

BlocksCodingGuide - GNU Radio

YAML GRC - GNU Radio

GNU Radio Manual and C++ API Reference: gr::block Class Reference

GNU Radio3.8创建OOT的详细过程(基础/C++)相关推荐

  1. GNU Radio3.8创建OOT的详细过程(python)

    GNU Radio 学习使用 OOT 系列教程: GNU Radio3.8创建OOT的详细过程(基础/C++) GNU Radio3.8创建OOT的详细过程(进阶/C++) GNU Radio3.8创 ...

  2. GNU Radio3.8创建OOT的详细过程(进阶/C++)

    GNU Radio 学习使用 OOT 系列教程: GNU Radio3.8创建OOT的详细过程(基础/C++) GNU Radio3.8创建OOT的详细过程(进阶/C++) GNU Radio3.8创 ...

  3. GNU Radio3.8:创建自定义的QPSK块(C++)

    GNU Radio 学习使用 OOT 系列教程: GNU Radio3.8创建OOT的详细过程(基础/C++) GNU Radio3.8创建OOT的详细过程(进阶/C++) GNU Radio3.8创 ...

  4. 最适合新手看的平衡二叉搜索树(BBST)的创建,包含详细过程,一看就会(C++版)

    写在前面:本人大二小白,本篇文章是我第一次写博客,用来记录我的学习过程,我想将我在学习中遇到的各种的问题和困难写下来,希望大家能够不要犯同样的错误.我会尽可能的详细的把每一个步骤都解释清楚,那么废话不 ...

  5. socket:内核初始化及创建流(文件)详细过程

    socket中文名称为套接字,属于传输协议及功能接口的封装.socket首先初始化注册(socket)文件系统,然后由使用它的模块传入具体的地址族(类型)family,如ipv4模块中的(void)s ...

  6. MySQL中关于临时表的创建到删除详细过程

    1.临时表的创建: CREATE TEMPORARY TABLE SalesSummary (product_name VARCHAR(50) NOT NULL, total_sales DECIMA ...

  7. Oracle 创建表空间详细过程

    此空间是用来进行数据存储的(表.function.存储过程等),所以是实际物理存储区域. 主要用途是在数据库进行排序运算[如创建索引.order by及group by.distinct.union/ ...

  8. Hive创建表的过程详细过程

    Hive创建表的过程详细过程 Demo 第一个demo CREATE TABLE db.testTable(id string COMMENT 'id',name string COMMENT '姓名 ...

  9. 菜鸟教程 | IDEA创建一个spring boot项目的详细过程

    目录 1.新建项目 2.选择项目所需依赖 3.手动导入部分依赖 创建spring项目的详细过程~ 1.新建项目 file --> new -->  project groupid 和 ar ...

最新文章

  1. Kubernetes安全之认证
  2. B+Tree索引为什么可以支持千万级别数据量的查找——讲讲mysql索引的底层数据结构
  3. 【Docker】容器镜像有哪些特性
  4. 适用于zTree 、EasyUI tree、EasyUI treegrid
  5. 操作系统(李治军) L9多进程图像-操作系统最重要的图像
  6. 解决关闭hbase时stop-hbase.sh报错stopping hbasecat: /tmp/hbase-xxxx-master.pid: No such file or directory
  7. 什么是冷区热区_墙角装个小柜子 冷区立马变热区 有颜值还实用!
  8. 数据库大作业——基于C#和SQL Server的简单日常记账系统
  9. C++内存汇编逆向安全全集
  10. 微信抢红包插件 English Version
  11. 计算机输入什么指令关机,电脑关机命令是什么 电脑关机命令详解
  12. AI落地的新范式,就“藏”在下一场软件基础设施的重大升级里
  13. 代理服务器使用全攻略(转)
  14. .so文件(so文件是什么)
  15. adobe illustrator 绘制平行四边形
  16. ply文件 java_ply之解析java文件,找出包名、类名、依赖类
  17. sql取每组最新数据
  18. DGA(域名生成算法)/DNS tunnel
  19. [Untiy]贪吃蛇大作战(四)——游戏主界面
  20. SV独立客户端无法登陆问题

热门文章

  1. “蔚来杯“2022牛客暑期多校训练营8 D题: Poker Game: Decision
  2. 妹子面试阿里,面试官竟问她有没有男朋友?面试真题「PDF分享
  3. 计算机组成指令系统的论文,计算机组成原理探讨论文
  4. 使用Xshell实现SSH隧道穿透
  5. 港科夜闻丨香港科大团队JACS:一锅法合成含氮阳离子的多功能聚电解质
  6. MS Visual Studio 2008 编译错误 microsoft visual studio 9.0\vc\include\new.h(60) : error C2065: '_In_opt_
  7. 上网方式不正确导致路由器无法连接外网
  8. Postgresql数据库介绍4——使用
  9. C程序设计语言读书笔记:入门C语言
  10. 通过SwitchyOmega插件实现Chrome的PAC模式代理网络连接