FPGA数字信号处理(20)单级半带(HB)滤波器设计

本篇是FPGA数字信号处理的第20篇,前面介绍了多速率信号处理系统中用到的多速率FIR滤波器、CIC滤波器,本文将介绍另一种常用的半带滤波器(Half-Band Filter)的相关知识及设计方法。本文介绍的是单级半带滤波器,下一篇将介绍多级半带滤波器。

多速率信号处理的相关知识可以参考:“FPGA数字信号处理(十五)多速率FIR滤波器:https://blog.csdn.net/FPGADesigner/article/details/80875304 ”。


半带滤波器

半带滤波器是一种特殊的FIR滤波器,其阶数只能为偶数,长度为奇数。滤波器系数除了中间值为0.5外,其余偶数序号的系数都为0(因此也大大节省了滤波时的乘法和加法运算)。我们以一个具体的例子来观察半带滤波器的特性:
这里写图片描述
半带滤波器的频率响应具有对称的特点:通带与阻带对称。如果通带截止频率为ωc,则阻带截止频率为(π-ωc)。上图中通带为0~5MHz,阻带为20~25MHz,呈对称关系。该滤波器的系数为:

-0.0423,0,0.2903,0.5,0.2903,0,-0.0423

符合上面所叙述的半带滤波器的系数特点。由于半带滤波器比普通的FIR滤波器节省近一半的乘法运算,因此非常适合于2倍抽取(抽取后通带内不会有频谱混叠),通过半带滤波器的级联即可实现2^N倍抽取。

不过由半带滤波器的频率响应也可以看出:如果通带比较小,则过渡带范围会很大,无法满足设计要求。因此通常会在多级抽取滤波的最后一级加入一个一般的高性能FIR滤波器(由于抽取后采样频率已经降低,因此这个FIR的工作频率一般不高),使整体性能可以满足设计要求。


MATLAB设计

由于半带滤波器本质上也是一种FIR滤波器,因此其性能也与滤波器阶数、窗函数的选择等有关,可以通过提高阶数来增强滤波器的性能。MATLAB中半带滤波器的设计函数为firhalfband,本系列不着重讲述MATLAB程序设计,具体使用方法可参考help文档中的demo。

使用FDATOOL工具也可以进行半带滤波器的设计,如上文图中所示,可选择Halfband Lowpass或Halfband Hignpass(工程中用到的都是半带低通),设置采样频率、通带频率、通带容限等参数。使用FDATOOL工具的好处是可以直接生成Xilinx FIR IP核所需的coe文件。

一个半带滤波器进行2倍抽取滤波的示例如下:
这里写图片描述
可以看到信号频率没有改变,但数据速率降低了一半。


FPGA设计

半带滤波器本质上仍是FIR滤波器,可以用“并行FIR结构https://blog.csdn.net/fpgadesigner/article/details/80594627”或“串行FIR结构https://blog.csdn.net/fpgadesigner/article/details/80598992”实现,也可以使用Quartus或Vivado自带的FIR IP核实现。

本文使用Vivado的FIR Compiler IP核完成半带滤波器的设计。首先使用MATLAB的FDATOOL工具设计一个50MHz采样、10MHz截止、30阶的半带滤波器,生成存储半带滤波器系数的coe文件(16位定点量化)。IP核配置如下:
这里写图片描述
导入coe文件,左边是滤波器的频率响应。将滤波器类型设置为2倍抽取,输入数据位宽为10Bits,全精度输出26Bits(IP核相关内容已在本系列第5篇讲述,这里不再具体讨论)。

导入系数后可以在“Implementation”标签下将“Coefficient Structure”设置为Half Band,软件会根据半带滤波器的特点对FIR滤波器结构做性能优化(当设置为Inferred时软件也可以自动推测出该FIR为半带滤波器):
这里写图片描述
调用IP核完成半带滤波器2倍抽取,相关Verilog HDL代码如下:

`timescale 1ns / 1ps
//-------------------------------------------------------------
//  单级半带滤波器,完成2倍抽取
//-------------------------------------------------------------
module SingleHalfBand_liuqi
(
    input clk,
    input signed [9:0] Xin,    //待抽取数据
    output out_valid, 
    output signed [25:0] Yout  //半带滤波器2倍抽取后数据
);

wire signed [31:0] data;
HB_filter U0 (
  .aclk(clk),                               // input wire aclk
  .s_axis_data_tvalid(1'b1),                // input wire s_axis_data_tvalid
  .s_axis_data_tready(),                    // output wire s_axis_data_tready
  .s_axis_data_tdata({{6{Xin[9]}},Xin}),    // input wire [15 : 0] s_axis_data_tdata
  .m_axis_data_tvalid(out_valid),           // output wire m_axis_data_tvalid
  .m_axis_data_tdata(data)            // output wire [31 : 0] m_axis_data_tdata
);

assign Yout = data[25:0];

endmodule

仿真测试

使用MATLAB生成一个0.25MHz的单频信号,写入txt文件。编写testbench读取txt文件对信号抽取滤波,文件操作方法参考“Testbench编写指南(一)文件的读写操作https://blog.csdn.net/fpgadesigner/article/details/80470972 ”。

Vivado中仿真结果如下图所示:
这里写图片描述
可以看到输出数据速率为输入数据速率的1/2,每当有新数据输出时,out_valid信号会置高1个时钟周期。将信号设置为Analog显示方式:
这里写图片描述
可以看到经过抽取滤波后,数据速率降低,但信号频率没有改变。

猜你喜欢

转载自blog.csdn.net/fpgadesigner/article/details/80899230