0


通用FIR滤波器的verilog实现(内有Lowpass、Hilbert参数生成示例)

  众所周知,Matlab 中的 Filter Designer 可以直接生成 FIR 滤波器的 verilog 代码,可以方便地生成指定阶数、指定滤波器参数的高通、低通、带通滤波器,生成的 verilog 代码也可以指定输入输出信号的类型和位宽。然而其生成的代码实在算不上美观,复用性也很差,要实现不同滤波特性的切换就要生成多个滤波器的代码。

  出于以上考虑,自己设计实现了 FIR 滤波器的通用 verilog 代码,其滤波器参数通过接口输入,从而可以通过输入不同的参数获得相应的滤波结果。verilog 代码如下:

/* 
 * file         : FIR_filter.v
 * author       : 今朝无言
 * date            : 2023-07-03
 * version      : v1.0
 * description  : FIR 滤波器
 */
module FIR_filter(
input                            clk,
input                            rst_n,

input                [16*N-1:0]    filter_params,

input        signed    [15:0]        data_in,
output    reg    signed    [15:0]        data_out
);

parameter    N        = 32;    //滤波器参数个数
parameter    div_N    = 16;    //sum结果除 2^div_N,作为 filter 的输出

//FIR 滤波器参数
reg    signed    [15:0] b[0:N-1];

integer    m;
always @(*) begin
    for(m=0; m<N; m=m+1) begin
        b[m]    <= filter_params[(m << 4) +: 16];
    end
end

reg    signed    [15:0]    shift_reg[0:N-1];

integer    i;
always @(posedge clk) begin
    if(~rst_n) begin
        for(i=N-1; i>=0; i=i-1) begin
            shift_reg[i]    <= 16'd0;
        end
    end
    else begin
        for(i=N-1; i>0; i=i-1) begin
            shift_reg[i]    <= shift_reg[i-1];
        end
        shift_reg[0]        <= data_in;
    end
end

reg        signed    [31:0]    multi[0:N-1];

integer    j;
always @(*) begin
    for(j=0; j<N; j=j+1) begin
        multi[j]    <= shift_reg[j] * b[j];
        //这里可以考虑使用multiplier IP核,使用LUT搭建(而这里直接乘使用的是DSP资源,一般的FPGA芯片只有几百个)
    end
end

reg        signed    [47:0]    sum;

integer    k;
always @(*) begin
    sum        = 0;
    for(k=0; k<N; k=k+1) begin
        sum    = sum + multi[k];
    end
end

always @(posedge clk) begin
    data_out    <= sum[47-div_N : 32-div_N];
end

endmodule

Lowpass Filter示例

  当滤波器阶数较高时,滤波器参数如何给出无疑是个麻烦事,因此又编写了 matlab 代码,可以一键生成所需的 .v 文件以实现参数的配置:

%-----------FIR滤波器参数(生成.v)-----------------
clc,clear,close all

fs=1e6;

N=20;
Wn=0.1;
b =fir1(N, Wn);% 默认Hamming窗freqz(b,1,512)%% pramas
B=floor(b*65536);
B=B';%% test
t=0:1/fs:1e-3;
s=(mod(t,1e-4)<5e-5)*1.0;%s_filt=filter(B,1,s)/65536;fori=1:size(s,2)-N-1s_filt(i)=s(i:i+N)*double(B)/65536;end

figure
subplot(2,1,1)plot(t,s)subplot(2,1,2)plot(t(1:end-N-1),s_filt)%% 生成.v
filename='FIR_params';
fid=fopen(['./v/',filename,'.v'],'w');fprintf(fid,['/* ','\n',...' * file\t\t\t: ',filename,'.v','\n',...' * author\t\t: 今朝无言','\n',...' * date\t\t\t: 2023-07-04','\n',...' * version\t\t: v1.0','\n',...' * description\t: FIR 滤波器','\n',...' */','\n']);fprintf(fid,['module ',filename,'(','\n',...'output\t[',num2str(size(B,1)*16-1),':0]\tparams\n',...');\n\n']);fori=1:size(B,1)if(B(i)>=0)
        hex=dec2hex(B(i),4);else
        hex=dec2hex(65536+B(i),4);endfprintf(fid,['assign\t','params[',...num2str(i*16-1),':',num2str((i-1)*16),...']\t= 16','''','h',hex,';\n']);endfprintf(fid,'\nendmodule\n');fclose(fid);

  testbench与测试结果如下

`timescale 1ns/100ps

module FIR_filter_tb();

reg        clk_100M    = 1'b1;
always #5 begin
    clk_100M    <= ~clk_100M;
end

localparam    N = 20;    //FIR滤波器阶数

wire    [16*(N+1)-1:0]    filter_params;
FIR_params_0d1 FIR_params_inst(
    .params        (filter_params)
);

reg                [15:0]    data_in;
wire    signed    [15:0]    data_out;

FIR_filter #(.N(N+1))
FIR_filter_inst2(
    .clk            (clk_100M),
    .filter_params    (filter_params),        //滤波器参数

    .data_in        (data_in),
    .data_out        (data_out)
);

reg        [7:0]    cnt        = 8'd0;

always @(posedge clk_100M) begin
    cnt        <= cnt + 1'b1;

    if(cnt<100)    begin
        data_in        <= -10000;
    end
    else if(cnt<200)    begin
        data_in        <= 10000;
    end
    else begin
        data_in        <= 0;
    end
end

initial begin
    #10000;
    $stop;
end

endmodule

在这里插入图片描述

Hilbert 示例

  使用以上 FIR 滤波器代码,还可以实现许多其他滤波功能,比如常用的 90 度相移,可以使用 Hilbert 变换实现,Hilbert 滤波器参数的 matlab 生成代码如下

%-----------------Hilbert----------------------
clc,clear,close all

%% Hilbert
N=200;% method 1        这种直接通过 h(n) 表达式生成的更为精确,推荐
n=(1:floor((N-1)/2));
b1=(1-(-1).^n)./(pi.*n);ifmod(N,2)==0
    b1=[0,b1,0,-b1(end:-1:1)]';else
    b1=[0,b1,-b1(end:-1:1)]';end% method 2        构造 Hilbert 的频域特性,经 IFFT 获得
H=[-1j*ones(1,floor((N+1)/2)),1j*ones(1,floor(N/2))];
b2=ifft(H);
b2=real(b2)';

b=b1;freqz(b,1,100)%% Filter
fs=1e3;
t=0:1/fs:1;
s=5*sin(2*pi*10*t);% f >= fs/N 时,可以由很好的90度移相

s2=filter(b,1,s);

figure
hold on
plot(t,s,'r-')plot(t,s2,'b--')
hold off

%% 量化
B=floor(b*32768);
s3=filter(B,1,s)/32768;

figure
hold on
plot(t,s,'r-')plot(t,s3,'b--')
hold off

%% 生成params.v
filename='Hilbert_params';
fid=fopen(['./v/',filename,'.v'],'w');fprintf(fid,['/* ','\n',...' * file\t\t\t: ',filename,'.v','\n',...' * author\t\t: 今朝无言','\n',...' * date\t\t\t: 2023-08-04','\n',...' * version\t\t: v1.0','\n',...' * description\t: FIR滤波器参数(Hilbert)',...'   N=',num2str(N),'\n',...' */','\n']);fprintf(fid,['module ',filename,'(','\n',...'output\t[',num2str(size(B,1)*16-1),':0]\tparams\n',...');\n\n']);fori=1:size(B,1)if(B(i)>=0)
        hex=dec2hex(B(i),4);else
        hex=dec2hex(65536+B(i),4);endfprintf(fid,['assign\t','params[',...num2str(i*16-1),':',num2str((i-1)*16),...']\t= 16','''','h',hex,';\n']);endfprintf(fid,'\nendmodule\n');fclose(fid);

  仿真结果如下

在这里插入图片描述

标签: fpga开发

本文转载自: https://blog.csdn.net/qq_43557686/article/details/132130857
版权归原作者 今朝无言 所有, 如有侵权,请联系我们删除。

“通用FIR滤波器的verilog实现(内有Lowpass、Hilbert参数生成示例)”的评论:

还没有评论