目录
在FPGA中实现串行FIR滤波器的过程中,除了使用移位寄存器之外,还可以使用双端口RAM实现数据的移位效果。为了实现基于双端口RAM的串行FIR滤波器 ,主要的是要知道如何控制RAM的读写地址。本文将该实现分为以下三个部分,第一步使用MATLAB的滤波器工具箱,将设计指标输入进去之后获得FIR滤波系数,然后使用产生的系数在MATLAB上进行仿真,观察滤波效果。第二部使用FPGA生成测试用的波形。第三步创建模块用于ram读写地址的控制,在ram的输出端实现实现输入数据的周期性流动),最后一步是FIR计算,其实就是一个简单的乘累加过程,系统框图设计如下 :
1.基于MATLAB的FIR滤波器设计
1.1 使用matlab获得FIR滤波系数
打开matlab 的滤波器设计工具
响应类型选择低通,设计方法选择FIR滤波器的窗函数设计法,指定阶设定为511(为系数个数减一),窗函数选择hamming窗,频率设定一栏,我们所产生的波形是500Hz, 1000Hz,1500Hz的正弦波叠加,采样频率为50K, 想要实现的实验效果是将1500Hz的正弦波过滤掉,因此单位选择Hz, Fs设为50000(Hz),Fc设为1200(Hz)。点击设计滤波器后产生的滤波器幅值响应如下所示:
系统冲击函数,为对称分布

1.2 基于MATLAB的FIR滤波仿真
matlab仿真代码 :
%采样频率为50000Hz,三个正弦波对应的频率分别为50Hz,1000,1500Hz,
%wave_gen
%设置参数
FS = 50000; %采样频率
T = 1/FS; %采样周期
N = 1024; %仿真点数
t = (0:N-1) * T; %时间向量
f1 = 500; %500Hz
f2 = 1000; %100Hz
f3 = 1500; %1500Hz
sin_500Hz = sin(2*pi*f1*t);
sin_1000Hz = sin(2*pi*f2*t);
sin_1500Hz = sin(2*pi*f3*t);
sin_sum_1 = sin_500Hz + sin_1000Hz;
sin_sum_2 = sin_500Hz+ sin_1000Hz + sin_1500Hz;
num_of_filter = 512;
% fir 计算
% fir_sum
data_buffer = zeros(1,num_of_filter);
fir_o = zeros(1,N);
fir_0_o = zeros(1,N);
fir_1_o = zeros(1,N);
for i = 1: N
data_buffer = [sin_sum_2(i),data_buffer(1:num_of_filter - 1)]; %移位
fir_0 = param_1200_512.*data_buffer*2^16;
fir_o(i) = sum(fir_0);
end
subplot(3,1,1);
plot(sin_sum_2);
xlabel('时间 (秒)');
ylabel('振幅');
title("sin\_500Hz+ sin\_1000Hz + sin\_1500Hz");
subplot(3,1,2);
plot(sin_sum_1);
xlabel('时间 (秒)');
ylabel('振幅');
title('sin\_500Hz + sin\_1000Hz ');
hold on;
subplot(3,1,3);
plot(fir_o);
xlabel('时间 (秒)');
ylabel('振幅');
title('滤波后的波形');
matlab仿真效果:
2.基于CORDIC IP核的测试波形生成
作用 : 产生一个500Hz、1000Hz、1500Hz的正弦波叠加信号
2.1 端口定义
module wave_gen(
input sys_clk, //时钟周期为20ns
input rst ,
input start,
output reg [17:0] wave_top,
output reg wave_top_vld
);
2.2 触发脉冲产生
always@(posedge sys_clk)begin
if(rst)
cnt_20us <= 'd0;
else if(start)begin
if(end_of_cnt_20us)
cnt_20us <= 'd0;
else
cnt_20us <= cnt_20us + 'd1;
end
end
always@(posedge sys_clk)begin
if(rst)
flag_20us <= 'd0;
else if(end_of_cnt_20us)
flag_20us <= 'd1;
else
flag_20us <= 'd0;
end
always@(posedge sys_clk)begin
flag_20us_r1 <= flag_20us ;
flag_20us_r2 <= flag_20us_r1;
end
assign end_of_cnt_20us = cnt_20us == 'd999;