• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

MATLAB设计FIR滤波器,FPGA实现FIR滤波器

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
  • 滤波器说明:设计一个采样率Fs=1024,Fpass=200,Fstop=400,通过最小二乘实现,15阶,并对滤波器参数进行量化。流水线型fir滤波器

1.1 使用matlab进行滤波

 %滤波器信息:采样频率1024 fpass=200 fstop=400  15阶
 %0-2000hz信号保留,200-400hz为过度带 ,400-500hz,滤除
Fs=1024; %采样频率 
dt=1.0/Fs;
T=1;N=T/dt;t=[0:N-1]/N
x0=sin(2*pi*150*t)+sin(2*pi*450*t);     %产生一个不同频率的信号
subplot(2,2,1); %图片为2行两列的第一个
x1=round(x0*2^11)
plot(x1);
axis([0,100,-10000,10000])
title(\'输入信号时域图\')

P=fft(x1,N);           %对信号进行傅里叶变换
Pyy=2*sqrt(P.*conj(P))/N;             
f=linspace(0,Fs/2,N/2);       
subplot(2,2,2);
plot(f,Pyy(1:N/2)); %画出信号频谱图
title(\'输入信号频谱图\')
xlabel(\'频率/HZ\')

y=filter(fir,x1); %调用filter Designer产生的滤波器。
%产生滤波器具体步骤:filter designer窗口 ->文件 ->生成MATLAB代码 ->滤波器设计函数
% fir为保存的滤波器.m文件的文件名
subplot(2,2,3)
plot(y);
axis([0,100,-3,3])
title(\'输出信号时域图\')

绘制的图像如下:

1.2 matlab产生coe波形文件

Fs=1024; %采样频率  fpass=200 fstop=400 
dt=1.0/Fs;
T=1;N=T/dt;t=[0:N-1]/N
x1=sin(2*pi*150*t)+sin(2*pi*450*t);     %产生一个不同频率的信号
b=round(x1*2^11);
fid=fopen(\'wave.coe\',\'w\');
fprintf(fid,\'MEMORY_INITIALIZATION_RADIX=10;\n\');
fprintf(fid,\'MEMORY_INITIALIZATION_VECTOR=\n\');
for i=1:1:Fs
    fprintf(fid,\'%d\',b(i));
    if i==Fs
        fprintf(fid,\';\');
    else
        fprintf(fid,\',\');
    end
    if mod(i,15)==0
        fprintf(fid,\'\n\');
    end
end
fclose(fid)

1.3 FIR滤波器流水线型

//fir ————15阶流水线型滤波器
//滤波器系数量化为16位   通带2000  阻带4000  带宽10000

//两个部分组成、一个是接受数据移位保存
//输入数据为14位
//输出取32位防止输出溢出

module fir_flow_15(
input clk,                      //系统时钟
input rst_n,                    //系统复位
input [13:0] data_in,           //数据输入
input vld_en,                   //流水线控制使能,

output reg  [23:0] data_out     //数据输出

);

assign vld =vld_en;        //将输入数据赋值给vld


//因为输入数据有符号,滤波器系数也有符号所以,定义有符号的寄存器来保存数据

reg signed  [13:0]   x0  ;
reg signed  [13:0]   x1  ;
reg signed  [13:0]   x2  ;
reg signed  [13:0]   x3  ;
reg signed  [13:0]   x4  ;
reg signed  [13:0]   x5  ;
reg signed  [13:0]   x6  ;
reg signed  [13:0]   x7  ;
reg signed  [13:0]   x8  ;
reg signed  [13:0]   x9  ;
reg signed  [13:0]   x10 ;
reg signed  [13:0]   x11 ;
reg signed  [13:0]   x12 ;
reg signed  [13:0]   x13 ;
reg signed  [13:0]   x14 ;
reg signed  [13:0]   x15 ;

reg signed [14:0]   m0 ;
reg signed [14:0]   m1 ;
reg signed [14:0]   m2 ;
reg signed [14:0]   m3 ;
reg signed [14:0]   m4 ;
reg signed [14:0]   m5 ;
reg signed [14:0]   m6 ;
reg signed [14:0]   m7 ;

reg signed [31:0]  n0 ;
reg signed [31:0]  n1 ;
reg signed [31:0]  n2 ;
reg signed [31:0]  n3 ;
reg signed [31:0]  n4 ;
reg signed [31:0]  n5 ;
reg signed [31:0]  n6 ;
reg signed [31:0]  n7 ;

reg signed [31:0]  p0 ;
reg signed [31:0]  p1 ;
reg signed [31:0]  p2 ;
reg signed [31:0]  p3 ;
reg signed [31:0]  q0 ;
reg signed [31:0]  q1 ;
reg signed [31:0]  y  ;

//四级流水线控制寄存器
reg vld_ff0  ;
reg vld_ff1  ;
reg vld_ff2  ;
reg vld_ff3  ;
reg y_vld 	 ;

//保存滤波器系数,定义为常量会导致无法进行有符号乘法,所以定义为寄存器类型
reg signed [15:0] h0   ;
reg signed [15:0] h1   ;
reg signed [15:0] h2   ;
reg signed [15:0] h3   ;
reg signed [15:0] h4   ;
reg signed [15:0] h5   ;
reg signed [15:0] h6   ;
reg signed [15:0] h7   ;

//滤波器系数
always @( posedge clk)
begin
        h0 <=16\'h00a3;
        h1 <=16\'hff3d  ;
        h2 <=16\'hfe36;
        h3 <=16\'h043f;
        h4 <=16\'h015d ;
        h5 <=16\'hf2a2;
        h6 <=16\'h094a;
        h7 <=16\'h4072;
end

//将输入数据移位寄存,总共保存16个数据
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		x0 <=  14\'b0;
	    x1 <=  14\'b0;
	    x2 <=  14\'b0;
	    x3 <=  14\'b0;
	    x4 <=  14\'b0;
	    x5 <=  14\'b0;
	    x6 <=  14\'b0;
	    x7 <=  14\'b0;
	    x8 <=  14\'b0;
	    x9 <=  14\'b0;
	    x10 <= 14\'b0;
	    x11 <= 14\'b0;
	    x12 <= 14\'b0;
	    x13 <= 14\'b0;
	    x14 <= 14\'b0;
	    x15 <= 14\'b0;
		
	end
	else begin
		x0 <= 	data_in;
		x1 <= 	x0;
		x2 <= 	x1;
		x3 <= 	x2;
		x4 <= 	x3;
		x5 <= 	x4;
		x6 <= 	x5;
		x7 <= 	x6;
		x8 <= 	x7;
		x9 <= 	x8;
		x10 <=  x9;
		x11 <=  x10;
		x12 <=  x11;
		x13 <=  x12;
		x14 <=  x13;
		x15 <=  x14;
	end
end

//滤波器系数是对称的,所以可以将输入数据先加,再与滤波器系数相乘
//以减少运算量
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		m0 <=  15\'b0;
		m1 <=  15\'b0;
		m2 <=  15\'b0;
		m3 <=  15\'b0;
		m4 <=  15\'b0;
		m5 <=  15\'b0;
		m6 <=  15\'b0;
		m7 <=  15\'b0;
		
	end
	else if(vld)begin
		m0 <= x0 + x15;
		m1 <= x1 + x14;
		m2 <= x2 + x13;
		m3 <= x3 + x12;
		m4 <= x4 + x11;
		m5 <= x5 + x10;
		m6 <= x6 + x9;
		m7 <= x7 + x8;
	end
end

//滤波器系数与输入数据相乘,直接用*号进行乘,系统自动调用dsp乘法单元
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		n0 <=  32\'b0;
	    n1 <=  32\'b0;
	    n2 <=  32\'b0;
	    n3 <=  32\'b0;
	    n4 <=  32\'b0;
	    n5 <=  32\'b0;
	    n6 <=  32\'b0;
	    n7 <=  32\'b0;
	end
	else if(vld_ff0)begin
		n0 <= m0*h7;
		n1 <= m1*h6;
		n2 <= m2*h5;
		n3 <= m3*h4;
		n4 <= m4*h3;
		n5 <= m5*h2;
		n6 <= m6*h1;
		n7 <= m7*h0;
	end
end

//流水线,将多个加法拆分为几块,从而提高加法速度,提高系统工作频率
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		p0 <=  32\'b0;
	    p1 <=  32\'b0;
	    p2 <=  32\'b0;
	    p3 <=  32\'b0;
	
	end
	else if(vld_ff1)begin
		p0 <= n0+n1;
		p1 <= n2+n3;
		p2 <= n4+n5;
		p3 <= n6+n7;
	end
end

//流水线
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		q0 <= 32\'b0;
		q1 <= 32\'b0;
	end
	else if(vld_ff2)begin
		q0 <= p0+p1;
		q1 <= p2+p3;
	end
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		y <= 32\'b0;
	end
	else if(vld_ff3)begin
		y <=q0+q1;
	end
end

//流水线控制使能,使每一级同步
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		vld_ff0 <= 1\'b0;
	    vld_ff1 <= 1\'b0;
	    vld_ff2 <= 1\'b0;
	    vld_ff3 <= 1\'b0;
	    y_vld 	<= 1\'b0;
	end
	else begin
		vld_ff0 <= vld;
		vld_ff1 <= vld_ff0;
		vld_ff2 <= vld_ff1;
		vld_ff3 <= vld_ff2;
		y_vld 	<= vld_ff3;
	end
end

//将滤波结果输出到输出端口
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)begin
		data_out <=24\'b0;
	end
	else if(y_vld) begin
		data_out <= y>>8; //右移8位牺牲精度,使io端口资源减少
	end
	else 
	    data_out <=data_out;
end

endmodule	



1.4测试文件

module FIR_15_tb();

//调用被测试模块
fir_flow_15   fir_flow_15_u(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.vld_en(vld_en),
.data_out(data_out)
);




reg [15:0] cnt_t;         //计数器,用来产生地址
wire [13:0] data;       //数据连接线
reg clk;
reg rst_n;
reg vld_en;
wire  [13:0] data_in;

//将matlab生成的波形保存为coe文件,通过调用rom ip核实现读取波形数据文件
//波形是频率为150hz  和450hz的正弦波的混叠。位宽为14,深度为1024
blk_mem_gen_0 your_instance_name (
  .clka(clk),    // input wire clka
  .addra(cnt_t),  // input wire [9 : 0] addra
  .douta(data)  // output wire [14 : 0] douta
);

//产生激励时钟
always #10 clk=~clk;
 
//将rom ip核读取到的波形数据赋值给fir滤波模块
assign  data_in =data;

//进行计数,,该计数器是为了产生读取波形所需的地址
 always @(posedge clk or rst_n)
 begin
      if(!rst_n)
        begin
        cnt_t<=1\'b0;
        end
      else if (cnt_t==16\'d1024)
        cnt_t<=1\'b0;
      else
        cnt_t<=cnt_t+1\'b1;
  end

//经过16个时钟周期,移位寄存器数据填满,开始进行滤波
always @(posedge clk or rst_n)
begin
    if(!rst_n)
        vld_en <=1\'b0;
    else if(cnt_t==12\'d15)
        vld_en<=1\'b1;
end

//先进行系统复位,对时钟初始值进行赋值
initial
begin
    rst_n=0;
    clk=0;
    #400
    rst_n=1;
end
  
endmodule

仿真图:


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
delphidev汉化发布时间:2022-07-18
下一篇:
chipscope数据导入matlab发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap