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

2023-05-16

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++)

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

有了前面的有关 GR 创建 OOT 的基础,接下来我们一起来写一个 QPSK 的解调模块。最终的测试流图长这个样子:

 1、编辑 block 执行代码 

首先,使用如下命令创建一个 module 并添加一个 block 。

gr_modtool newmod myqpsk
gr_modtool add my_qpsk_demod_cb

注意这里在添加块时没有指定 -t 与 -l 参数,可以在命令执行中进行选择。my_qpsk_demod_cb 的命名代表该 block 输入为 complex 型数据,输出为 byte 型数据。另外要注意一点的是,与之前所讲的 OOT 不同的是,这里还需要一个输入参数:bool gray_code ,需要在执行命令的过程中添加进去,该参数用于选择是否使用格雷码进行解码,后面会讲到。。

正常情况下的输出 log 如下:

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

wsx@wsx:~/temp$ cd gr-myqpsk/

wsx@wsx:~/temp/gr-myqpsk$ gr_modtool add my_qpsk_demod_cb
GNU Radio module name identified: myqpsk
('sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock')
Enter block type: general
Language (python/cpp): cpp
Language: C++
Block/code identifier: my_qpsk_demod_cb
Please specify the copyright holder: gnuradio.org
Enter valid argument list, including default arguments: 
bool gray_code
Add Python QA code? [Y/n] y
Add C++ QA code? [y/N] n
Adding file 'lib/my_qpsk_demod_cb_impl.h'...
Adding file 'lib/my_qpsk_demod_cb_impl.cc'...
Adding file 'include/myqpsk/my_qpsk_demod_cb.h'...
Editing swig/myqpsk_swig.i...
Adding file 'python/qa_my_qpsk_demod_cb.py'...
Editing python/CMakeLists.txt...
Adding file 'grc/myqpsk_my_qpsk_demod_cb.block.yml'...
Editing grc/CMakeLists.txt...

下面开始编写相关代码,首先是 lib/my_qpsk_demod_cb_impl.cc 的编写。

首先是构造函数的修改:

    my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
      : gr::block("my_qpsk_demod_cb",
              gr::io_signature::make(1, 1, sizeof(gr_complex)),
              gr::io_signature::make(1, 1, sizeof(char))),
        d_gray_code(gray_code)
    {}

代码中,my_qpsk_demod_cb_impl() 是 块 my_qpsk_demod 的构造函数。调用 gr::block() 来进行初始化。其中注意在后面要加上一个参数 d_gray_code 的初始化,并在 lib/my_qpsk_demod_cb_impl.h 头文件中声明这个私有属性。

     private:
      bool d_gray_code;

然后是 forecast() 函数的修改。如前面所说的,系统需要知道需要多少数据才能确保每个输入数组的有效性,forecast 函数向系统提供了这类信息。另外,在 general 类型的 block 中,必须要重写 forecast 函数来达到这个目的。

    void
    my_qpsk_demod_cb_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
    {
      unsigned ninputs = ninput_items_required.size();  // 获取输入端口的数量
      for (unsigned i = 0; i < ninputs; i++)
      {
        ninput_items_required[i] = noutput_items;  // 输入数据量等于输出数据量
      }
    }

可以从 forecast 函数的实现中看出端口的输入输出比均为 1:1 ,因此,根据之前教程的经验,在创建这个 block 时完全可以使用 sync 类型的 block ,这样可以简化代码。

接下来是主函数 general_work() 的修改。

    int
    my_qpsk_demod_cb_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 gr_complex *in = (const gr_complex *) input_items[0];
      unsigned char *out = (unsigned char *) output_items[0];
      // 声明初始化数据
      gr_complex origin = gr_complex(0, 0);

      // 在输入 IQ 数据中应用极大似然算法解调
      for (int i = 0; i < noutput_items; i++)
      {  
        out[i] = get_minimum_distances(in[i]);  // 极大似然解码,确定与所有星座点的最小距离
      }
      
      consume_each (noutput_items);

      // Tell runtime system how many output items we produced.
      return noutput_items;
    }

general_work() 函数中调用了极大似然解调函数 get_minimum_distances(),该函数通过确定输入复数数据(星座图点)所在的象限对数据进行解调。实现如下:

    unsigned char my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &sample)
    {
      if(d_gray_code)  // 使用 格雷码 时的解码方式,此时四个象限依次代表:00/01/11/10
      {
        // 定义 QPSK 信号的两个位
        unsigned char bit0 = 0;  // 正交分量
        unsigned char bit1 = 0;  // 同相分量
        // 如果星座点在两个左象限(正交分量 < 0),将此位设置为 1
        if (sample.real() < 0)
        {
          bit0 = 0x01 << 1;
        }
        // 如果星座点在两个下象限(同相分量 < 0),将此位设置为 1
        if (sample.imag() < 0)
        {
          bit1 = 0x01 << 1;
        }
        return bit0 | bit1 ;  // 组合输出
      }
      else  // 非格雷编码,此时四个象限依次代表 00/01/10/11
      {
        if(sample.real() >= 0 and sample.imag() >= 0)
        { 
          return 0x00;  //第一象限
        }
        else if(sample.real() < 0 and sample.imag() >= 0)
        { 
          return 0x01;  // 第二象限
        }
        else if(sample.real() < 0 and sample.imag() < 0)
        { 
          return 0x02;  // 第三象限
        }
        else if(sample.real() >= 0 and sample.imag() < 0)
        { 
          return 0x03;  // 第四象限
        }
      }
    }

我们还需要在头文件 lib/my_qpsk_demod_cb_impl.h 中添加该函数的声明

unsigned char my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &sample);

理论上来说,get_minimum_distances 函数需要根据接收到的每一个 QPSK 信号到理想 QPSK 星座点的欧式距离中的最短的一个来进行解调,但是根据泰森多边形原理,两个坐标轴正好就是四个泰森区域的分界线,因此这里的代码实现就直接使用判断坐标系象限的方法来进行解调,其本质上等同于选择欧式距离中的最短一个。该函数最终将接受信号解调为位信息。

2、编写测试代码

编辑 python/qa_my_qpsk_demod_cb.py 

from gnuradio import gr, gr_unittest
from gnuradio import blocks
import myqpsk_swig as myqpsk
import numpy as np

class qa_my_qpsk_demod_cb(gr_unittest.TestCase):

    def setUp(self):
        self.tb = gr.top_block()

    def tearDown(self):
        self.tb = None

    def test_001_gray_code_enabled (self):
        # "Construct the Iphase and Qphase components"
        Iphase = np.array([ 1, -1, -1,  1])
        Qphase = np.array([ 1,  1, -1, -1])
        src_data = Iphase + 1j*Qphase;
        # 使用格雷码编码方式
        gray_code =  True;
        # 期望的正确结果
        expected_result = (0,1,3,2)
        # 创建复数源数据
        src = blocks.vector_source_c(src_data)
        # 初始化测试模块
        qpsk_demod = myqpsk.my_qpsk_demod_cb(gray_code)
        # "Instantiate the binary sink"
        dst = blocks.vector_sink_b();
        # 构建流图
        self.tb.connect(src,qpsk_demod)
        self.tb.connect(qpsk_demod,dst)
        # 运行流图
        self.tb.run ()
        # 检查结果
        result_data = dst.data()
        self.assertTupleEqual(expected_result, result_data)
        self.assertEqual(len(expected_result), len(result_data))

    def test_002_gray_code_disabled (self):
        # "Construct the Iphase and Qphase components"
        Iphase = np.array([ 1, -1, -1,  1])
        Qphase = np.array([ 1,  1, -1, -1])
        src_data = Iphase + 1j*Qphase;
        # 不使用格雷码
        gray_code =  False;
        # 期望的正确结果
        expected_result = (0,1,2,3)
        # 创建复数源数据
        src = blocks.vector_source_c(src_data)
        # 初始化测试模块
        qpsk_demod = myqpsk.my_qpsk_demod_cb(gray_code)
        # "Instantiate the binary sink"
        dst = blocks.vector_sink_b();
        # 构建流图
        self.tb.connect(src,qpsk_demod)
        self.tb.connect(qpsk_demod,dst)
        # 运行流图
        self.tb.run ()
        # 检查结果
        result_data = dst.data()
        self.assertTupleEqual(expected_result, result_data)
        self.assertEqual(len(expected_result), len(result_data))

if __name__ == '__main__':
    gr_unittest.run(qa_my_qpsk_demod_cb)

3、编辑 yaml 文件

.yml 文件提供了 GRC 中显示的 OOT 模块和源代码之间的用户界面。此外,YAML 文件定义了一个接口来传递特定于模块的参数,因此,要访问 GRC 内的模块,手动修改 .yml 文件很重要。yaml 文件的修改方法可以参考这里。修改后的yaml文件如下:

id: myqpsk_my_qpsk_demod_cb
label: My QPSK Demodulator
category: '[myqpsk]'

templates:
  imports: import myqpsk
  make: myqpsk.my_qpsk_demod_cb(${gray_code})

parameters:
- id: gray_code
  label: Gray Code
  dtype: bool
  default: 'True'

inputs:
- label: in
  dtype: complex
outputs:
- label: out
  dtype: byte

file_format: 1

相比之前教程中的例子,这里的 yaml 文件主要不同是使用了 parameter 关键字进行参数 gray_code 的设置。

4、编译安装测试

依次执行以下命令进行编译安装及测试,正常情况下会很顺利(亲测正常~)

mkdir build && cd build
cmake ../
make -j10
make test
sudo make install

在 GRC 中进行测试,结果如下:

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

 我在根据官网教程第一次构建流图运行的时候出现了以下错误:

    self.digital_chunks_to_symbols_xx_0 = digital.chunks_to_symbols_bc(1+1j,-1+1j,-1-1j,1-1j, 1)
TypeError: make() takes from 1 to 2 positional arguments but 5 were given

 主要就是:TypeError: make() takes from 1 to 2 positional arguments but 5 were given

主要原因就是在 Chunks to Symbols 块中设置的问题,我原来的设置为:

因为要转化为 python 代码,我们填入的 list 应该符合 python 的语法, 所以需要加上一对中括号:

[ 1+1j,-1+1j,-1-1j,1-1j ]

 正确的填写方式如下:

 问题顺利解决

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

参考:

Guided Tutorial GNU Radio in C++ - GNU Radio

https://dsp.stackexchange.com/questions/68004/chunks-to-symbols-in-gnuradio-3-8

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

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

  • 类的静态(static)成员

    有时候类需要它的一些成员与类本身直接相关 xff0c 而不是与类的各个对象保持关联 xff08 这意味着无论创建多少个类的对象 xff0c 静态成员都只有一个副本 xff09 我们通过在成员的声明前加上关键字static使得其与类关联在一起
  • Keil uvision5 介绍

    keil 5 Keil uvision5 安装过程Keil uvision5安装包1 Keil uvision5 介绍2 Keil uVision5 特点3 Keil uVision5 功能4 Keil uVision5 快捷键 Keil
  • px4仿真时,/mavros/state现实连接不上

    仿真时 xff0c 使用px4 xff0c 启动 PX4 Firmware launch文件中的launch文件 进入gazebo世界中 xff0c 通过 xff1a rostopic list 查看发布的话题 xff0c 并且打印 mav
  • 插值方法(一维插值、三次样条插值、二维插值的matlab自带函数,python实现/作图)

    数模比赛中 xff0c 常常需要根据已知的函数点进行数据 模型的处理和分析 xff0c 而有时候现有的数据是极少的 xff0c 不足以支撑分析的进行 xff0c 这时就需要使用一些数学的方法 xff0c 模拟产生 一些新的单又比较靠谱的值来
  • ROS中常用命令

    1 xff09 工作空间初始化 xff1a catkin init workspace 2 xff09 创建功能包 xff1a catkin create pkg pkg name reply 3 xff09 编译工作空间中的功能包 xff
  • 【DL】CNN的前向传播和反向传播(python手动实现)

    卷积层的前向传播和反向传播 说明 本文中 xff0c 只实现一层卷积层的正反向传播 xff08 带激活函数Relu xff09 xff0c 实现的是多通道输入 xff0c 多通道输出的 之前对深度学习的理解大多止于pytorch里面现成的A
  • Postman使用教程详解

    目录 1 Postman安装与接口请求基本操作1 1Postman安装1 2发起一个接口请求的小测试 2 接口测试实战2 1百度IP查询接口从抓包到测试实战2 2需要设置头域的请求实战2 3文件上传与json请求实战 3 Newman命令行
  • GNU Radio3.8创建OOT的详细过程(基础/C++)

    GNU Radio 学习使用 OOT 系列教程 xff1a GNU Radio3 8创建OOT的详细过程 基础 C 43 43 GNU Radio3 8创建OOT的详细过程 进阶 C 43 43 GNU Radio3 8创建OOT的详细过程
  • Johnson-Trotter(JT)算法生成排列

    对于生成 xff5b 1 xff0c xff0c n xff5d 的所有n xff01 个排列的问题 xff0c 我们可以利用减治法 xff0c 该问题的规模减一就是要生成所有 xff08 n 1 xff09 xff01 个排列 假设这个小
  • OSMWebWizard无法使用(Address family not supported by protocol)

    根据报错信息依次打开osmWebWizard py SimpleWebSocketServer py 查看对应行号的内容 xff0c 发现Simple py中有一个socket net6 可能是网络协议的问题 xff0c 查了一下 xff0
  • 粤嵌实训笔记二

    目录 20230227 20230303 xff08 第二周 xff09 main clcd clcd hbmp cbmp hgame cgame h 20230227 20230303 xff08 第二周 xff09 1 在Linux下
  • Arduino学习笔记:FreeRTOS——ESP32多任务处理

    Arduino学习笔记 xff1a FreeRTOS ESP32多任务处理 Demo span class token comment 创建任务一和任务二的句柄 xff0c 并初始化 span TaskHandle t TASK Handl
  • JAVA-信号量

    信号量 xff1a 信号量一般都有以下几个变量 xff1a count xff1a 记录可以使用的资源数wait list xff1a 等待信号量的队列 获取信号量需要判断count是否大于零 xff0c 即if count gt 0 若c
  • (程序猿专属)1024-我用代码写成浪漫情话表白你

    今天1024 xff0c 程序员节 xff01 不祝你们节日快乐了 xff0c 祝你们穿着拖鞋和裤衩去相亲吧 xff01 祝你们和甜蜜的爱情撞个满怀 xff01 一 我是你的什么啊 xff1f 你是我的bug啊 因为 xff0c 我每时每刻
  • C++中构造函数后的冒号

    C 43 43 中构造函数后的冒号 在C 43 43 中离不开类的定义 xff0c 而构造函数则是类的定义中很重要的一环 我们在构造函数中常常见到如下定义 xff1a span class token keyword class span
  • 论C语言没有输出的可能问题

    论C语言没有输出的可能问题 1 今天帮别人找bug xff0c 说是程序没有输出 题目如下 xff1a 错误代码如下 xff1a span class token macro property span class token direct
  • 【VS2019】报错:E0349没有与这些操作数匹配的运算符

    报错 xff1a E0349没有与这些操作数匹配的运算符 调试程序遇到该错误 xff0c 特此记录 span class token macro property span class token directive keyword inc
  • 基于docker技术搭建hadoop与mapreduce分布式环境

    基于docker技术搭建hadoop与mapreduce分布式环境 一 安装doker 1 宿主环境确认 如果没有的话 安装lsb relaease工具 apt install lsb release 检查版本 lsb release a
  • GNU Radio3.8创建OOT的详细过程(进阶/C++)

    GNU Radio 学习使用 OOT 系列教程 xff1a GNU Radio3 8创建OOT的详细过程 基础 C 43 43 GNU Radio3 8创建OOT的详细过程 进阶 C 43 43 GNU Radio3 8创建OOT的详细过程
  • 基于docker构建spark运行环境

    基于docker构建spark运行环境 一 安装docker与docker compose 参考之前的实验进行docker和docker compose的安装 二 系统构架图 xff1a 三 安装相关镜像 使用docker hub查找我们需

随机推荐

  • HDFS基本操作

    HDFS基本操作 HDFS的基本命令格式 hdfs dfs cmd lt args gt 注意 xff1a 需要事先将HADOOP HOME bin目录配置进入环境变量 列出当前目录下的文件 hdfs dfs ls 在HDFS创建文件夹 h
  • 使用mllib完成mnist手写识别任务

    使用mllib完成mnist手写识别任务 小提示 xff0c 通过restart命令重启已经退出了的容器 sudo docker restart lt contain id gt 完成识别任务准备工作 从以下网站下载数据集 MNIST手写数
  • npm install 报错 Error: EPERM: operation not permitted, rename

    报错的解决方案 原因1 xff1a 权限不足原因2 xff1a 缓存出错方法1方法2 原因3 xff1a npm版本不够原因4 xff1a 网络不稳定方法1方法2 原因5 xff1a 杀毒软件问题方法1方法2 其他 xff1a 待补充 原因
  • 马原复习知识点背诵-《马克思主义基本原理概论》

    马概复习重点 绪论 1 什么是马克思主义 1 从创造者 继承者的角度讲 马克思主义是由马克思恩格 斯创立的 而由其后各个时代 各个民族的马克思主义者 不断丰富和发展的观点和学说的体系 2 从阶级属性讲 马克思主义是无产阶级争取自身解放和整
  • 深度学习 | 三个概念:Epoch, Batch, Iteration

    转自 xff1a https www jianshu com p 22c50ded4cf7 写在前面 xff1a 在训练神经网络的时候 xff0c 我们难免会看到Batch Epoch和Iteration这几个概念 曾对这几个概念感到模糊
  • OpenStack — Nova

    文章目录 NovaNova架构Nava组件nova apinova computenova conductornova schedulernova novncproxy 创建虚拟机流程 Nova Nova是OpenStack最核心的服务模块
  • 使用Object.key和delete来将对象中值为空的属性删除。

    有些时候 xff0c 我们在接口传值时 xff0c 不需要把值为空的属性传过去 xff0c 即可使用该方法来快速的删除属性 span class token comment 深拷贝对象 xff0c 避免影响页面显示 span span cl
  • docker启动关闭删除所有的容器命令

    1 启动所有容器 docker start docker ps a awk 39 print 1 39 tail n 43 2 2 关闭所有容器 docker stop docker ps a awk 39 print 1 39 tail
  • GNU Radio3.8创建OOT的详细过程(python)

    GNU Radio 学习使用 OOT 系列教程 xff1a GNU Radio3 8创建OOT的详细过程 基础 C 43 43 GNU Radio3 8创建OOT的详细过程 进阶 C 43 43 GNU Radio3 8创建OOT的详细过程
  • 面试必问:从输入URL到页面展示,这中间发生了什么?(详细易懂,条理好记)

    导航流程 xff1a 从输入URL到页面展示 xff0c 这中间发生了什么 xff1f 一 进程介绍 整个过程需要各个进程之间的配合 进程与线程是两个概念 xff0c 程序启动时 xff0c 操作系统为程序创建内存 xff0c 用以存放代码
  • MATLAB神经网络工具箱函数各种图的解释

    Neural Network 该部分展示了神经网络的结构 xff0c 从结构图中可以看出该网络有三个隐含层 xff0c 神经元个数分别为9个 8个 7个 Algorithms 该部分展示了该网络所使用的训练算法 xff0c 可以看出 Dat
  • gazebo加载world模型

    使用launch文件启动gazebo加载world模型 xff0c 或者说是将world模型加入gazebo仿真器中作为环境 first xff0c 我们应该告诉gazebo 要加载的world文件放在哪里 并通过arg标签 xff0c 设
  • px4无人机报avionics power low

    px4无人机报avionics power low xff0c 将无人机连接qgc中 xff0c 将CBRK SUPPLY参数设为最大值即可
  • QGC地面站PC桥接px4(QGC+wifi+机载计算机+px4)

    QGC地面站PC桥接px4 xff08 QGC 43 wifi 43 机载计算机 43 px4 xff09 1 在机载计算机上安装ubuntu2 安装ros3 机载计算机上安装mavros1安装mavros2 安装安装mavros相关的 g
  • 消除Gazebo模型抖动

    自己创建的模型导入到gazebo中往往会不停的跳动 xff0c 一般是由于转动惯量设置不正确导致的 xff0c 可以将转动惯量注释掉 如果注释点后还是有这种情况 xff0c 需要设置非零的min depth xff0c 模型通常会稳定 将其
  • px4报dangerously low battery! shutting system down.

    这两天用px4突然开始报dangerously low battery shutting system down xff0c 从px4 github项目上看到是因为telem接口中的tx和rx相连了 xff0c mavlink的消息从px4
  • realsense t265测试中的一些小问题

    realsense t265测试中出现的一些小问题 环境 xff1a Ubuntu18 04 内核 xff1a 5 4 官方教程 xff1a https github com IntelRealSense realsense ros 测试过
  • 查看T265配置信息及参数

    查看T265配置信息及参数 1 验证SDK安装成功 安装完sdk后 xff0c 终端里运行 realsense viewer 查看相机输出的图像和imu信息 xff0c 可以验证sdk是否安装成功 2 查看T265配置信息 rs enume
  • 修改vins-fusion中T265的相机模型文件

    修改vins fusion中T265的相机模型文件 在使用T265跑vins fusion的过程中 xff0c 首先需要设置相机相关的配置文件 xff0c 网上给出的相关测试教程都没有很明白的说明这一部分 xff0c 都将T265作为了ME
  • GNU Radio3.8:创建自定义的QPSK块(C++)

    GNU Radio 学习使用 OOT 系列教程 xff1a GNU Radio3 8创建OOT的详细过程 基础 C 43 43 GNU Radio3 8创建OOT的详细过程 进阶 C 43 43 GNU Radio3 8创建OOT的详细过程