关于 GNURadio-OFDM 运行时掉帧问题的解决

最近在运行 GNURadio 中的 OFDM 例程时发现了丢帧的问题。

2022.08.01更新:

1、突然又想起了这个问题,今年年初的时候与西电的一个师兄又重新讨论了这个问题,有了更深一步的理解,这里记录一下:其实这个掉帧的问题本质上还是前一步的 同步 没有做好导致的,源码里用的同步算法官网也就是同步算法不行,要想彻底解决这个问题可以换一个更鲁棒的同步算法试试。

2、下面的解释其实可以理解为:在同步效果不好的前提下掉帧的原理,以及这种情况下如何避免掉帧。这个方法虽然可以在一定程度上解决掉帧问题,但是在同步性能极差的情况下也是无能为力的。所以仅供参考哈~

使用的 gnuradio 是 3.8 版本的,Ubuntu为20.04,而且至少目前来说 gnuradio 3.9 也存在这个问题,下面是问题原因及解决方法。

当使用原始的例程(一次发送10帧960个字节的数据)进行测试时还没有丢帧现象出现,但当我们把要发送的数据换成图片数据进行发送时却无法进行正确的接收,即使是在仿真中将信道条件改为理想无噪无畸变信道时也仍然会在同一位置丢同样数量的数据帧。

在调试中发现,当定时信息的两个触发信号之间的间隔一般有 4 种情况,分别为958、959、960、961。但是只有当差为958(一个完整 OFDM 数据帧为960个 QPSK 数据)时才会出现丢帧现象,其他都没问题,而 958与正常的 960差了两个 QPSK 数据。另外,用于定时的触发信号的产生是正常的,问题应该就出在触发信号产生后使用该触发信号的模块中

在重新分析了例程中数据发送及解析的流程后,觉得可能是 Header/Payload Demux 模块源码中的问题,因此就看了下该模块的源码。

图 1

源码流程及问题所在:

总的来说,丢帧的原因就是相邻两个定时信号的间隔过短时,导致当前帧提取数据时将后一个帧数据的定时信号作为当前帧的数据一并读入,这样就丢失了下一帧数据的定时信号,因此就造成了丢帧的现象。这种现象是源码中固有的问题。具体分析如下:

图 2 中数据与触发信号是严格执行对应位置的并行传输关系,Header/Payload Demux 模块先读取 trigger 信号,当读到值为 1 时就被认为是一帧数据的开始,这时就从数据信号的相应位置开始往后提取 1919 个数据作为当前帧的数据进行输出。

图 2

根据源码的数据处理过程,源码中每次接收到定时信号后,都会提取紧跟着该定时信号后面的959个数据作为当前帧进行输出,因此这对定时信号的精确型提出了很高的要求,如果相邻两个定时信号的间隔出现了小于正常数据帧长度的偏差,比如正常间隔为 960,如果此时出现了间隔为 958 的间隔,如图 3,则在提取后续 959个数据的时候就会正好把下一帧的定时信号当作当前帧的数据一起读入,这样就丢失了下一帧数据的定时信号,因此就造成了丢帧的现象。

图 3

解决这个问题的方法就是在源码中进行修改,在保证相邻定时信号不想相互干扰的基础上再重新进行源码的编译安装。需要修改的源码部分为 gr-digital/lib/header_payload_demux_impl.cc 以及 gr-digital/lib/header_payload_demux_impl.h 。首先在 header_payload_demux_impl.h 中添加变量:

int d_next_trigger_offset;

 然后在 header_payload_demux_impl.cc 中更改 find_trigger_signal 函数如下:

......
    int trigger_nums = 0;
    if (max_rel_offset < skip_items) {
        return rel_offset;
    }
    if (in_trigger) {
        for (int i = skip_items; i < max_rel_offset; i++) {
            if (in_trigger[i]) {
                trigger_nums++;
                // record location of the first trigger
                if(trigger_nums == 1) {
                    rel_offset = i;
                }
                // If there is a second trigger signal,record offset of between the first and second trigger
                else if (trigger_nums == 2) {
                    d_next_trigger_offset = i - rel_offset;
                    break;
                }
            }
        }
    }
......

然后修改 general_work() 中的 case STATE_PAYLOAD 状态中的 consume 过程如下:

。。。。。。
            // Calculate whether the current frame consumes the trigger signal of the next frame data
            // If yes, then make corrections
            int consume_compensation = 0;
            int consume_nums = 0;
            // Calculate total consumption
            consume_nums = (d_curr_payload_len + d_header_len) * (d_items_per_symbol + d_gi) + 
                            d_header_padding_total_items + 
                            d_curr_payload_offset - 
                            items_padding ;
            // make a decision
            if(d_next_trigger_offset <= consume_nums) {
                consume_compensation = consume_nums - d_next_trigger_offset + 1;
            }
            else {
                consume_compensation = 0;
            }
            // add the corrections
            const int items_to_consume =
                d_curr_payload_len * (d_items_per_symbol + d_gi) - items_padding - consume_compensation;
。。。。。。

修改后从新对源码进行编译安装,问题解决~

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
OFDM(正交频分复用)是一种用于无线通信系统的调制技术,它将高速数据流分成多个低速子载波进行传输,以提高系统的传输效率和抗干扰能力。GNURadio是一个开源的软件无线电开发平台,可以用于设计和实现各种无线通信系统。 在GNURadio中实现OFDM系统,可以按照以下步骤进行: 1. 随机生成数据:首先,使用随机数生成器生成需要传输的数据。 2. 数据打包:将生成的数据按照一定的规则进行打包,例如每96个数据打包成一个packet。 3. 添加CRC校验:为了保证数据的完整性,可以使用CRC(循环冗余校验)算法为每个packet添加校验码。 4. 数据重组:将打包后的数据按照一定的规则进行重组,例如将8bit的数据拆分成2bit的数据,以便进行QPSK调制。 5. 星座映射:对重组后的数据进行星座映射,即将数据映射到复平面上的不同点,以便进行调制。 6. OFDM载波映射:将映射后的数据进行OFDM调制,即将数据分配到不同的子载波上。 7. IFFT变换:对每个子载波进行IFFT(逆快速傅里叶变换),将频域信号转换为时域信号。 8. 添加循环前缀:为了抵消多径传播引起的符号间干扰,可以在每个OFDM符号前添加循环前缀。 9. OFDM信号生成:将经过循环前缀处理的时域信号组合起来,生成最终的OFDM信号。 以上是一个标准的OFDM发射端的流程,其中包括数据生成、打包、校验、重组、映射、调制、IFFT变换和循环前缀处理等步骤。通过GNURadio可以方便地实现这些步骤,并生成OFDM信号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球被支点撬走啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值