- 滤波器说明:设计一个采样率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
仿真图:
请发表评论