You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GNU Radio自定义sync块运行报s<d_bufsize断言失败求解

问题背景

使用gr_modtool开发具备Kurtosis(峰度)计算能力的sync块,此前基于sink块实现过同类功能,本次改用sync块重构实现。代码可正常编译,但在GRC中运行流图时触发运行时错误,错误出现在返回已消耗数据项数量的环节。

报错日志
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_c" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_p" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_c" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_p" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_c" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_c.block.yml
WARNING:gnuradio.grc.core.platform.block_loader:Block with id "Kurtosis_Kurtosis_p" loaded from
  /usr/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml
overwritten by
  /usr/local/share/gnuradio/grc/blocks/Kurtosis_Kurtosis_p.block.yml

Generating: '/home/nomo/j.py'

Executing: /usr/bin/python3 -u /home/nomo/j.py

0
7
python3: ../gnuradio-runtime/lib/../include/gnuradio/buffer.h:193: unsigned int gr::buffer::index_add(unsigned int, unsigned int): Assertion `s < d_bufsize' failed. 
相关代码

实现源文件

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "Kurtosis_only_c_impl.h"

namespace gr {
  namespace Kurtosis_only {

    using input_type = gr_complex;
    using output_type = gr_complex;
    
    
    
    Kurtosis_only_c::sptr
    Kurtosis_only_c::make(int large_loop, int small_loop)
    {
      return gnuradio::get_initial_sptr
        (new Kurtosis_only_c_impl(large_loop, small_loop));
    }


    /*
     * The private constructor
     */
    Kurtosis_only_c_impl::Kurtosis_only_c_impl(int large_loop, int small_loop)
      : gr::sync_block("Kurtosis_only_c",
              gr::io_signature::make(1, 1, sizeof(input_type) * small_loop),
              gr::io_signature::make(2, 2, sizeof(output_type) * small_loop)),
              d_LL(large_loop), d_SL(small_loop)
    {
      
    }
    
    
    /*
     * Our virtual destructor.
     */
    Kurtosis_only_c_impl::~Kurtosis_only_c_impl()
    {
    }

    void Kurtosis_only_c_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
    {
      for (unsigned int i = 0; i < ninput_items_required.size(); ++i) 
        ninput_items_required[i] = d_SL;
    }

    int
    Kurtosis_only_c_impl::work(int noutput_items,
        gr_vector_const_void_star &input_items,
        gr_vector_void_star &output_items)
    {
    
      /*printf("sizeof(gr_compelx) = %ld", sizeof(gr_complex));
      printf("sizeof(gr_complex) * small_loop = %ld", sizeof(gr_complex) * d_SL);

       printf("in0 = %d, out0 = %d", input_items, output_items);
       
       printf("d_N = %d", d_SL);*/
        
      auto in0  = static_cast<const input_type*>(input_items[0]);
      auto out0 = static_cast<output_type*>(output_items[0]);
      auto out1 = static_cast<output_type*>(output_items[1]);
      
     
      
      gr_complex S1r[d_SL], S1i[d_SL], S2r[d_SL], S2i[d_SL], S3r[d_SL], S3i[d_SL], 
                 S4r[d_SL], S4i[d_SL];
                           
      gr_complex dcnt[d_SL];
      
      gr_complex Myu1r[d_SL], Myu1i[d_SL], Myu2r[d_SL], Myu2i[d_SL], Myu3r[d_SL], 
                 Myu3i[d_SL], Myu4r[d_SL], Myu4i[d_SL];
      
      gr_complex M1r[d_SL], M1i[d_SL], M2r[d_SL], M2i[d_SL], M3r[d_SL], M3i[d_SL], M4r[d_SL], 
                 M4i[d_SL];
                           
      gr_complex Kr[d_SL], Ki[d_SL];
      
     /*for (int k = 0; k < noutput_items; k += d_SL)
      {
        unsigned int datasize = noutput_items - k;
        unsigned int resid = d_SL - d_index;*/

        for(unsigned int j = 0; j < d_LL; ++j)
        {
          
          for(unsigned int i = 0; i < d_SL; ++i)
          {
            pwr =  in0[i].real();
            pwi =  in0[i].imag();
        
            S1r[i]  += pwr;
            S1i[i]  += pwi;
        
            S2r[i]  += pwr * pwr;
            S2i[i]  += pwi * pwi;
        
        S3r[i]  += pwr * pwr * pwr;
        S3i[i]  += pwi * pwi * pwi;
        
        S4r[i]  += pwr * pwr * pwr * pwr;
        S4i[i]  += pwi * pwi * pwi * pwi;
        
        dcnt[i] += 1;    
          }
        }   
      
        for(unsigned int i = 0; i < d_SL; ++i)
        {
          Myu1r[i] = S1r[i] / dcnt[i];
          Myu1i[i] = S1i[i] / dcnt[i];
      
          Myu2r[i] = S2r[i] / dcnt[i];
          Myu2i[i] = S2i[i] / dcnt[i];
      
          Myu3r[i] = S3r[i] / dcnt[i];
          Myu3i[i] = S3i[i] / dcnt[i];
      
          Myu4r[i] = S4r[i] / dcnt[i];
          Myu4i[i] = S4i[i] / dcnt[i];
        }


        gr_complex a = 4, b = 6, c = 3, d = 2;
        
        for(unsigned int i = 0; i < d_SL; ++i)
        {
          M1r[i] = a * Myu3r[i] * Myu1r[i];
          M1i[i] = a * Myu3i[i] * Myu1i[i];
          
          M2r[i] = b * Myu2r[i] * pow(Myu1r[i], d);
          M2i[i] = b * Myu2i[i] * pow(Myu1i[i], d);
          
          M3r[i] = c * pow(Myu1r[i], a);
          M3i[i] = c * pow(Myu1i[i], a);
          
          M4r[i] = Myu2r[i] - pow(Myu1r[i], d);
          M4i[i] = Myu2i[i] - pow(Myu1i[i], d);
        }
          
        for(unsigned int i = 0; i < d_SL; ++i)
        {     
          Kr[i] = (Myu4r[i] - M1r[i] + M2r[i] - M3r[i]) / pow(M4r[i], d);
      
          Ki[i] = (Myu4i[i] - M1i[i] + M2i[i] - M3i[i]) / pow(M4i[i], d);
        }
          
        for(unsigned int i = 0; i < d_SL; ++i)
        {
          out0[i] = Kr[i];
          out1[i] = Ki[i];
        }
        
      
        
      return 0;
    
    }
  } /* namespace Kurtosis_only */
} /* namespace gr */

头文件

#ifndef INCLUDED_KURTOSIS_ONLY_KURTOSIS_ONLY_C_IMPL_H
#define INCLUDED_KURTOSIS_ONLY_KURTOSIS_ONLY_C_IMPL_H

#include <Kurtosis_only/Kurtosis_only_c.h>

namespace gr {
  namespace Kurtosis_only {

    class Kurtosis_only_c_impl : public Kurtosis_only_c
    {
     private:
       gr_complex pwr;
       gr_complex pwi;
       
       int d_LL;
       int d_SL;
       
       int d_index = 0;
       
     public:
      Kurtosis_only_c_impl(int large_loop, int small_loop);
      ~Kurtosis_only_c_impl();
      
      void forecast(int nouput_items, gr_vector_int &ninput_items_required) override;
      
      // Where all the action really happens
      int work(
              int noutput_items,
              gr_vector_const_void_star &input_items,
              gr_vector_void_star &output_items
      );
      
      
    };

     
  } // namespace Kurtosis_only
} // namespace gr

#endif /* INCLUDED_KURTOSIS_ONLY_KURTOSIS_ONLY_C_IMPL_H */
GRC流图

GRC流图

问题根因与修复方案

触发gr::buffer::index_add断言的核心原因有两个,其余是附带的逻辑错误和警告:

  • work函数返回值错误:sync块的work函数约定是返回实际消耗的输入数据项个数,代码中直接return 0,等于告诉调度器本次调用一个输入项都没处理,调度器不会移动输入缓冲区读指针,会反复把同一段数据喂给块,最终读指针偏移超过缓冲区大小触发断言。
  • io_signature配置与forecast逻辑不匹配:构造函数中把单个输入输出项的大小设置为sizeof(gr_complex)*small_loop,也就是把small_loop个复数打包成1个数据项,但forecast中要求的输入项数是d_SL,相当于实际需要d_SL * d_SL个复数采样,和预期的处理粒度完全不符,进一步加剧缓冲区越界问题。

其余代码问题:

  • 栈上数组未初始化:work函数中定义的S1r、S1i、dcnt等所有局部数组没有赋初值,直接执行+=运算会读取栈上随机值,计算结果完全错误。
  • 累加逻辑失效:用于跨多帧累加的S1-S4、dcnt数组全部定义在work函数栈上,每次work调用都会重新创建,根本实现不了large_loop次的累加逻辑。
  • 块重复加载警告:系统中/usr/share/gnuradio/grc/blocks/和/usr/local/share/gnuradio/grc/blocks/两个路径下存在同名的Kurtosis块yml文件,前者是旧版本安装残留,加载时会被后者覆盖。

修复步骤:

  1. 修正io_signature配置,输入输出项大小统一设为单个复数大小:
Kurtosis_only_c_impl::Kurtosis_only_c_impl(int large_loop, int small_loop)
  : gr::sync_block("Kurtosis_only_c",
          gr::io_signature::make(1, 1, sizeof(input_type)),
          gr::io_signature::make(2, 2, sizeof(output_type))),
          d_LL(large_loop), d_SL(small_loop)
{
  // 累加数组和计数器移到成员变量后,在这里做初始化
  d_acc_cnt = 0;
  d_S1r.assign(d_SL, 0.0f);
  d_S1i.assign(d_SL, 0.0f);
  // S2r/S2i/S3r/S3i/S4r/S4i/dcnt数组按同样方式初始化
}
  1. 移除自定义的forecast函数,sync_block默认实现已经保证输入输出项数1:1匹配。如果需要攒够d_LL*d_SL个采样再计算,在work函数开头判断当前输入的noutput_items是否够一轮计算的长度,不够直接返回0,够了再执行计算。
  2. 修正work函数返回值:一轮计算实际消耗了多少个输入采样,就返回对应的数字,比如一次处理process_len = d_LL个采样就返回process_len,禁止无意义返回0。
  3. 把所有需要跨work调用保留值的累加数组、计数器全部定义为类的成员变量,不要放在work函数栈上。每完成一轮峰度计算、把结果写到输出缓冲区后,把所有累加变量清零,准备下一轮计算。
  4. 删除/usr/share/gnuradio/grc/blocks/路径下旧的Kurtosis_*.block.yml文件,消除块重复加载的警告。

内容的提问来源于stack exchange,提问作者yu_20

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:33:29