基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

基于gnuradio的OOT模块,iirnotch,iir 陷波滤波器

  • To start
  • 一、修改iirNotch.h
  • 二、修改iirNotch_impl.h
  • 三、修改iirNotch_impl.cc
  • 四、修改notchFilter_iirNotch.block.yml
  • 五、安装OOT
  • 六、测试


To start

OOT模块的制作教程可以看上一篇内容:基于gnuradio的自适应陷波滤波器OOT模块,本篇主要就iirnotch的制作进行说明

iirnotch 的原理请参考这一篇:陷波滤波器的离散化设计

如上一篇所说,输入gr_modtool 相关指令,就能生成相关的模块代码,之后只用修改代码即可:
在这里插入图片描述


一、修改iirNotch.h

在类定义中,添加这两句:

virtual void set_wc(float wc)=0;
virtual void set_wb(float wb)=0;

分别作为回调函数(在模块执行完一次数据处理操作后自动调用),更新wc(中心频率)和wb(陷波宽度)。

另外给这两句话加上注释,那么整个文件就是:

/* -*- c++ -*- */
/*
 * Copyright 2022 mortarboard-H.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#ifndef INCLUDED_NOTCHFILTER_IIRNOTCH_H
#define INCLUDED_NOTCHFILTER_IIRNOTCH_H

#include 
#include 

namespace gr {
namespace notchFilter {

/*!
 * \brief <+description of block+>
 * \ingroup notchFilter
 *
 */
class NOTCHFILTER_API iirNotch : virtual public gr::sync_block {
public:
  typedef std::shared_ptr<iirNotch> sptr;

  /*!
   * \brief Return a shared_ptr to a new instance of notchFilter::iirNotch.
   *
   * To avoid accidental use of raw pointers, notchFilter::iirNotch's
   * constructor is in a private implementation
   * class. notchFilter::iirNotch::make is the public interface for
   * creating new instances.
   */
  static sptr make(double sampRate, double targetFreq, double width);

  /*!
   * \brief call back function to update centre frequency
   */
  virtual void set_wc(float wc)=0;

  /*!
   * \brief call back function to update band frequency
   */
  virtual void set_wb(float wb)=0;
};

} // namespace notchFilter
} // namespace gr

#endif /* INCLUDED_NOTCHFILTER_IIRNOTCH_H */

更新完头文件后,要注意重新绑定,在module所在的文件夹下打开terminal,然后输入:

gr_modtool bind iirNotch

运行效果如下:
基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)_第1张图片

二、修改iirNotch_impl.h

添加对父类中刚刚加入的两个纯虚函数的继承:

void set_wc(float wc) override;
void set_wb(float wb) override;

添加几个成员变量:

//coefficient of input sample
float a0,a1,a2;
//coefficient of delayed output sample
float b1,b2;
double wc;
double wb;
double sampleRate;

这几个成员变量是使用极零点配置法离散化传递函数后得到的,具体的计算和含义参考开头提到的博客。

那么整个文件看起来就像这样:

/* -*- c++ -*- */
/*
 * Copyright 2022 mortarboard-H.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#ifndef INCLUDED_NOTCHFILTER_IIRNOTCH_IMPL_H
#define INCLUDED_NOTCHFILTER_IIRNOTCH_IMPL_H

#include 

namespace gr {
namespace notchFilter {

class iirNotch_impl : public iirNotch {
private:
  //coefficient of input sample
  float a0,a1,a2;
  //coefficient of delayed output sample
  float b1,b2;
  double wc;
  double wb;
  double sampleRate;

public:
  iirNotch_impl(double sampRate, double targetFreq, double width);
  ~iirNotch_impl();

  // Where all the action really happens
  int work(int noutput_items, gr_vector_const_void_star &input_items,
           gr_vector_void_star &output_items);
  
  void set_wc(float wc) override;
  void set_wb(float wb) override;
};

} // namespace notchFilter
} // namespace gr

#endif /* INCLUDED_NOTCHFILTER_IIRNOTCH_IMPL_H */

#endif /* INCLUDED_NOTCHFILTER_IIRNOTCH_IMPL_H */

三、修改iirNotch_impl.cc

修改构造函数:

/*
 * The private constructor
 */
iirNotch_impl::iirNotch_impl(double sampRate, double targetFreq, double width)
    : gr::sync_block(
          "iirNotch",
          gr::io_signature::make(1 /* min inputs */, 1 /* max inputs */,
                                 sizeof(input_type)),
          gr::io_signature::make(1 /* min outputs */, 1 /*max outputs */,
                                 sizeof(output_type))) 
{
    wc=targetFreq*2*M_PI;
    wb=width*2*M_PI;
    sampleRate=sampRate;
    double alpha=-wb/2;
    double beta=sqrt(4*wc*wc-wb*wb)/2;
    double r=exp(alpha/sampRate);
    a0=(1.0- 2 * r * cos(beta /sampRate) + r*r)/(2 - 2 * cos(wc / sampRate));
    a1=-2*a0*cosf(wc/sampRate);
    a2=a0;
    b1=2*r*cos(beta/sampRate);
    b2=-r*r;
    
}

接下来定义更新中心频率和陷波宽度的函数:

/*
 * Set targetfreq.
 */
void iirNotch_impl::set_wc(double targetFreq)
{
  wc=targetFreq*2*M_PI;
  double alpha=-wb/2;
  double beta=sqrt(4*wc*wc-wb*wb)/2;
  double r=exp(alpha/sampleRate);
  a0=(1.0- 2 * r * cos(beta /sampleRate) + r*r)/(2 - 2 * cos(wc / sampleRate));
  a1=-2*a0*cosf(wc/sampleRate);
  a2=a0;
  b1=2*r*cos(beta/sampleRate);
  b2=-r*r;
}

/*
 * Set bandwidth.
 */
void iirNotch_impl::set_wb(double bandwidth)
{
  wb=bandwidth*2*M_PI;
  double alpha=-wb/2;
  double beta=sqrt(4*wc*wc-wb*wb)/2;
  double r=exp(alpha/sampleRate);
  a0=(1.0- 2 * r * cos(beta /sampleRate) + r*r)/(2 - 2 * cos(wc / sampleRate));
  a1=-2*a0*cos(wc/sampleRate);
  a2=a0;
  b1=2*r*cos(beta/sampleRate);
  b2=-r*r;
}

最后修改work函数,work函数中有gr_modtool非常贴心地生成的提示:“Do <+signal processing+>”,意思是将信号处理的代码块写在这里,修改完的work函数看起来像这样:

int iirNotch_impl::work(int noutput_items,
                        gr_vector_const_void_star &input_items,
                        gr_vector_void_star &output_items) {
  auto in = static_cast<const input_type *>(input_items[0]);
  auto out = static_cast<output_type *>(output_items[0]);

#pragma message(                                                               \
    "Implement the signal processing in your block and remove this warning")
  // Do <+signal processing+>
  float inprepre=0,inpre=0,outprepre=0,outpre=0;
  for(int i=0;i<noutput_items;i++)
  {
    out[i]=a0*in[i]+a1*inpre+a2*inprepre+b1*outpre+b2*outprepre;
    inprepre=inpre;
    inpre=in[i];
    outprepre=outpre;
    outpre=out[i];
    //out[i]=a0;
  }
  // Tell runtime system how many output items we produced.
  return noutput_items;
}

最后整个文件是这样的:

/* -*- c++ -*- */
/*
 * Copyright 2022 mortarboard-H.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include "iirNotch_impl.h"
#include 

namespace gr {
namespace notchFilter {

#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;
iirNotch::sptr iirNotch::make(double sampRate, double targetFreq,
                              double depth) {
  return gnuradio::make_block_sptr<iirNotch_impl>(sampRate, targetFreq, depth);
}

/*
 * The private constructor
 */
iirNotch_impl::iirNotch_impl(double sampRate, double targetFreq, double width)
    : gr::sync_block(
          "iirNotch",
          gr::io_signature::make(1 /* min inputs */, 1 /* max inputs */,
                                 sizeof(input_type)),
          gr::io_signature::make(1 /* min outputs */, 1 /*max outputs */,
                                 sizeof(output_type))) 
{
    wc=targetFreq*2*M_PI;
    wb=width*2*M_PI;
    sampleRate=sampRate;
    double alpha=-wb/2;
    double beta=sqrt(4*wc*wc-wb*wb)/2;
    double r=exp(alpha/sampRate);
    a0=(1.0- 2 * r * cos(beta /sampRate) + r*r)/(2 - 2 * cos(wc / sampRate));
    a1=-2*a0*cosf(wc/sampRate);
    a2=a0;
    b1=2*r*cos(beta/sampRate);
    b2=-r*r;
    
}

/*
 * Our virtual destructor.
 */
iirNotch_impl::~iirNotch_impl() {}

/*
 * Set targetfreq.
 */
void iirNotch_impl::set_wc(double targetFreq)
{
  wc=targetFreq*2*M_PI;
  double alpha=-wb/2;
  double beta=sqrt(4*wc*wc-wb*wb)/2;
  double r=exp(alpha/sampleRate);
  a0=(1.0- 2 * r * cos(beta /sampleRate) + r*r)/(2 - 2 * cos(wc / sampleRate));
  a1=-2*a0*cosf(wc/sampleRate);
  a2=a0;
  b1=2*r*cos(beta/sampleRate);
  b2=-r*r;
}

/*
 * Set bandwidth.
 */
void iirNotch_impl::set_wb(double bandwidth)
{
  wb=bandwidth*2*M_PI;
  double alpha=-wb/2;
  double beta=sqrt(4*wc*wc-wb*wb)/2;
  double r=exp(alpha/sampleRate);
  a0=(1.0- 2 * r * cos(beta /sampleRate) + r*r)/(2 - 2 * cos(wc / sampleRate));
  a1=-2*a0*cos(wc/sampleRate);
  a2=a0;
  b1=2*r*cos(beta/sampleRate);
  b2=-r*r;
}


int iirNotch_impl::work(int noutput_items,
                        gr_vector_const_void_star &input_items,
                        gr_vector_void_star &output_items) {
  auto in = static_cast<const input_type *>(input_items[0]);
  auto out = static_cast<output_type *>(output_items[0]);

#pragma message(                                                               \
    "Implement the signal processing in your block and remove this warning")
  // Do <+signal processing+>
  float inprepre=0,inpre=0,outprepre=0,outpre=0;
  for(int i=0;i<noutput_items;i++)
  {
    out[i]=a0*in[i]+a1*inpre+a2*inprepre+b1*outpre+b2*outprepre;
    inprepre=inpre;
    inpre=in[i];
    outprepre=outpre;
    outpre=out[i];
    //out[i]=a0;
  }
  // Tell runtime system how many output items we produced.
  return noutput_items;
}

} /* namespace notchFilter */
} /* namespace gr */

四、修改notchFilter_iirNotch.block.yml

这个文件在grc文件夹下面,如果这个文件配置不正确,那么在gnuradio的图形化操作界面里面是找不到这个模块的。
主要需要修改的是template里面的make,然后要添加回调函数,然后要修改paremeters和inputs以及outputs:
最后文件内容如下:

id: notchFilter_iirNotch
label: iirNotch
category: '[notchFilter]'

templates:
  imports: import notchFilter
  make: |-
    notchFilter.iirNotch(${sampRate}, ${targetFreq}, ${band})
  callbacks:
    - self.${id}.set_wc(${targetFreq})
    - self.${id}.set_wb(${band})

#  Make one 'parameters' list entry for every parameter you want settable from the GUI.
#     Keys include:
#     * id (makes the value accessible as keyname, e.g. in the make entry)
#     * label (label shown in the GUI)
#     * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#     * default
parameters:
- id: sampRate
  label: sample rate
  dtype: real
  default: samp_rate

- id: targetFreq
  label: wc
  dtype: real
  default: 0

- id: band
  label: wb
  dtype: real
  default: 0
#- id: ...
#  label: ...
#  dtype: ...

#  Make one 'inputs' list entry per input and one 'outputs' list entry per output.
#  Keys include:
#      * label (an identifier for the GUI)
#      * domain (optional - stream or message. Default is stream)
#      * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
#      * vlen (optional - data stream vector length. Default is 1)
#      * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: in0
  domain: stream
  dtype: float
#- label: ...
#  domain: ...
#  dtype: ...
#  vlen: ...
#  optional: ...

outputs:
- label: out0
  domain: stream
  dtype: float

#  'file_format' specifies the version of the GRC yml format used in the file
#  and should usually not be changed.
file_format: 1

五、安装OOT

进入gr-notchfilter下的build文件夹,打开terminal,然后:

camke ..
make 
sudo make install
sudo ldconfig

全部完成后就能在gnuradio-companion中看到这个新增的block了:
基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)_第2张图片

六、测试

创建这样的一个流图:
基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)_第3张图片
左边是两个sin信号和一个noise信号,加起来之后通过一个throttle,这个throttle是官方提供的流图运行同步和速度控制模块
后面接一个数据类型转换block,用于将副信号转为实信号,转出的信号接本次制作的一个iirnotch block,一个上次做的adaptiveNotch,以及用于显示信号的time sink和frequency sink,分别用于显示时间域和频率域。iirnotch后面也接了一个frequency sink,用于比较。
运行流图:
基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)_第4张图片
第一张图是2kHz与1KHz信号叠加在一起的图,第二是用iirnotch滤除1KHz的图,第三张是用adaptivenotch滤除1kHz的图。
分别调整两个notchfilter的滤除频率到990Hz,此时二者对1KHz的滤除效果如下:
基于gnuradio的OOT模块,iirnotch(iir 陷波滤波器)_第5张图片
iirnotch对1KHz仍有衰减作用,而adaptiveNotch的滤除效果差,这是由于两者的原理不同造成的。

你可能感兴趣的:(gnurado,模块编程,基带工程,射频工程)