提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
OOT模块的制作教程可以看上一篇内容:基于gnuradio的自适应陷波滤波器OOT模块,本篇主要就iirnotch的制作进行说明
iirnotch 的原理请参考这一篇:陷波滤波器的离散化设计
如上一篇所说,输入gr_modtool 相关指令,就能生成相关的模块代码,之后只用修改代码即可:
在类定义中,添加这两句:
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
添加对父类中刚刚加入的两个纯虚函数的继承:
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 */
修改构造函数:
/*
* 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 */
这个文件在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
进入gr-notchfilter下的build文件夹,打开terminal,然后:
camke ..
make
sudo make install
sudo ldconfig
全部完成后就能在gnuradio-companion中看到这个新增的block了:
创建这样的一个流图:
左边是两个sin信号和一个noise信号,加起来之后通过一个throttle,这个throttle是官方提供的流图运行同步和速度控制模块
后面接一个数据类型转换block,用于将副信号转为实信号,转出的信号接本次制作的一个iirnotch block,一个上次做的adaptiveNotch,以及用于显示信号的time sink和frequency sink,分别用于显示时间域和频率域。iirnotch后面也接了一个frequency sink,用于比较。
运行流图:
第一张图是2kHz与1KHz信号叠加在一起的图,第二是用iirnotch滤除1KHz的图,第三张是用adaptivenotch滤除1kHz的图。
分别调整两个notchfilter的滤除频率到990Hz,此时二者对1KHz的滤除效果如下:
iirnotch对1KHz仍有衰减作用,而adaptiveNotch的滤除效果差,这是由于两者的原理不同造成的。