As we all know, the Filter Designer in Matlab can directly generate the verilog code of the FIR filter, and can easily generate high-pass, low-pass, and band-pass filters with specified order and specified filter parameters, and the generated verilog code can also specify input and output signals type and bit width. However, the generated code is really not beautiful, and the reusability is also very poor. To realize the switching of different filtering characteristics, it is necessary to generate codes for multiple filters.
For the above considerations, I have designed and realized the general verilog code of the FIR filter, and its filter parameters are input through the interface, so that the corresponding filtering results can be obtained by inputting different parameters. The verilog code is as follows:
/*
* 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 example
When the order of the filter is high, how to give the filter parameters is undoubtedly a troublesome matter, so the matlab code is written, and the required .v file can be generated with one click to realize the configuration of the parameters:
%-----------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 and test results are as follows
`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 example
Using the above FIR filter code, many other filtering functions can also be realized, such as the commonly used 90-degree phase shift, which can be realized using the Hilbert transform. The matlab generated code for the Hilbert filter parameters is as follows
%-----------------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);
The simulation results are as follows