众所周知,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

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

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

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;

for i=1:size(s,2)-N-1

s_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']);

for i=1:size(B,1)

if(B(i)>=0)

hex=dec2hex(B(i),4);

else

hex=dec2hex(65536+B(i),4);

end

fprintf(fid,['assign\t','params[',...

num2str(i*16-1),':',num2str((i-1)*16),...

']\t= 16','''','h',hex,';\n']);

end

fprintf(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);

if mod(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']);

for i=1:size(B,1)

if(B(i)>=0)

hex=dec2hex(B(i),4);

else

hex=dec2hex(65536+B(i),4);

end

fprintf(fid,['assign\t','params[',...

num2str(i*16-1),':',num2str((i-1)*16),...

']\t= 16','''','h',hex,';\n']);

end

fprintf(fid,'\nendmodule\n');

fclose(fid);

  仿真结果如下

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。