Implementación Verilog del filtro FIR general (con ejemplos de generación de parámetros Lowpass y Hilbert)

  Como todos sabemos, el Diseñador de filtros en Matlab puede generar directamente el código verilog del filtro FIR y puede generar fácilmente filtros de paso alto, paso bajo y paso de banda con un orden específico y parámetros de filtro específicos, y el verilog generado. El código también puede especificar el tipo de señales de entrada y salida y el ancho de bits. Sin embargo, el código generado no es realmente hermoso y la reutilización también es muy pobre. Para realizar el cambio de diferentes características de filtrado, es necesario generar códigos para múltiples filtros.

  Por las consideraciones anteriores, diseñé e implementé el código verilog general del filtro FIR, y sus parámetros de filtro se ingresan a través de la interfaz, de modo que los resultados de filtrado correspondientes se pueden obtener ingresando diferentes parámetros. El código verilog es el siguiente:

/* 
 * 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

Ejemplo de filtro de paso bajo

  Cuando el orden del filtro es alto, cómo proporcionar los parámetros del filtro es sin duda un asunto problemático, por lo que se escribe el código matlab y se puede generar el archivo .v requerido con un clic para realizar la configuración de los parámetros:

%-----------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);

  El banco de pruebas y los resultados de las pruebas son los siguientes.

`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

inserte la descripción de la imagen aquí

Ejemplo de Hilbert

  Usando el código de filtro FIR anterior, también se pueden implementar muchas otras funciones de filtrado, como el cambio de fase de 90 grados comúnmente usado, que se puede implementar usando la transformada de Hilbert. El código generado por Matlab para los parámetros del filtro de Hilbert es el siguiente

%-----------------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);

  Los resultados de la simulación son los siguientes.

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_43557686/article/details/132130857
Recomendado
Clasificación