该博客意义在于将MATLAB与FPGA有机的联系到一起,首先在MATLAB里验证了FIR的原理,并在MATLAB里对数据进行了量化,然后将MATLAB量化之后的信号与滤波器系数导到FPGA中,对FPGA程序进行验证,在行为级仿真中将滤波器输出导到txt文件中,并用MATLAB对数据进行分析,下面对整个过程进行说明。
滤波器原理:FIR滤波器公式很简单就是信号与滤波器系数的卷积,具体公式可见本文的MATLAB程序。
滤波器系数的设计:使用MATLAB中自带的fdatool进行设计,该设计中设置采样率为100Hz,Fpass = 15Hz,Fstop = 20Hz;滤波器阶数选择15阶;
FIR滤波器的MATLAB程序如下:
clc;
clear all;
close all;
%%
%fs = 100MHz; f_stop = 20MHz;
fs = 100;
f0 = 30;
f1 = 20;
t = 0:1/fs:256/fs - 1/fs;
coe = [0.0415447024516036,0.0581247192565150,-0.0281561932904513,-0.0535757585989063,-0.0617443413601994,0.0507874404653094,0.207893661228422,0.332736093778257,0.332736093778257,0.207893661228422,0.0507874404653094,-0.0617443413601994,-0.0535757585989063,-0.0281561932904513,0.0581247192565150,0.0415447024516036];
coe = round(coe*2^11);
x = 0.5*cos(2*pi*f0.*t) + 0.5*cos(2*pi*f1.*t);
x = round(x*2^11);
x_fft = abs(fft(x, 256));
xl = 0:fs/256:fs/2 - 1/256;
y = zeros(1, length(x));
for i = 1:length(x)
for k = 1:min(length(coe), i)
temp = x(i - k + 1)*coe(k)
y(i) = y(i) + x(i - k + 1)*coe(k);
end
end
y1 = conv(coe, x);
figure(1);
plot(real(y1));
y_fft = abs(fft(y, 256));
y1_fft = abs(fft(y1, 256));
figure(2);
plot(xl, y_fft(1:128));
figure(3);
plot(xl, y1_fft(1:128), 'r');
fidi = fopen('D:\Project\fir\signal.txt','w+');
ficoe = fopen('D:\Project\fir\coe.txt','w+');
PulseFlow = round(x);
for n=1:length(PulseFlow)
if(PulseFlow(n)< 0)
PulseFlow1(n) = PulseFlow(n)+ 2^12;
else
PulseFlow1(n) = PulseFlow(n);
end
end
for n=1:length(coe)
if(coe(n)< 0)
coe(n) = coe(n)+ 2^12;
else
coe(n) = coe(n);
end
end
for i = 1:length(PulseFlow)
fprintf(fidi,'%x\n',PulseFlow1(i) );
end
for i = 1:length(coe)
fprintf(ficoe,'%x\n',coe(i) );
end
fclose all;
data_out = textread('D:\Project\fir\pow_ch0.txt','%s');
data_out1 = hex2dec(data_out(57:261));
for i = 1:length(data_out1)
if(data_out1(i) > 2^27)
data_out1(i) = data_out1(i) - 2^28;
else
data_out1(i) = data_out1(i);
end
end
data_out1 = data_out1';
data_out_fft = fft(data_out1, 256);
figure(5);
plot(xl, abs(data_out_fft(1:128)));
该程序中对信号进行12位量化,高位是符号位,并在MATLAB中将原码变成了补码,滤波器系数操作相同。量化之后的数据给FPGA使用。
FPGA程序如下:
`timescale 1ns / 1ps
//
// Company: HEU
// Engineer: Fuxin
//
// Create Date: 2018/11/04 09:01:26
// Design Name:
// Module Name: fir
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fir
(
rstn,
clk,
data_in,
data_out
);
input rstn;
input clk;
input signed [11 : 0] data_in;
output signed [31 : 0] data_out;
reg signed [11 : 0] data_temp [0 : 15];
wire signed [11 : 0] coef [0 : 15];
reg [3 : 0] i = 4'd0;
reg [3 : 0] k = 4'd0;
wire signed [23 : 0] mult_out [0 : 15];
integer j;
assign coef[0] = 12'h055;
assign coef[1] = 12'h077;
assign coef[2] = 12'hfc6;
assign coef[3] = 12'hf92;
assign coef[4] = 12'hf82;
assign coef[5] = 12'h068;
assign coef[6] = 12'h1aa;
assign coef[7] = 12'h2a9;
assign coef[8] = 12'h2a9;
assign coef[9] = 12'h1aa;
assign coef[10] = 12'h068;
assign coef[11] = 12'hf82;
assign coef[12] = 12'hf92;
assign coef[13] = 12'hfc6;
assign coef[14] = 12'h077;
assign coef[15] = 12'h055;
always @(posedge clk)
begin
begin
for( i = 4'd0; i < 15; i = i + 1 )
begin
data_temp[0] <= data_in;
data_temp[i + 1] <= data_temp[i];
end
end
end
generate
genvar z;
for(z = 0; z <= 15; z = z + 1)
begin :filter
mult mult_inst (
.CLK(clk), // input wire CLK
.A(data_temp[z]), // input wire [11 : 0] A
.B(coef[z]), // input wire [11 : 0] B
.P(mult_out[z]) // output wire [23 : 0] P
);
end
endgenerate
//reg signed [35 : 0] sum = 36'd0;
//reg signed [35 : 0] out_temp = 36'd0;
reg signed [25 : 0] sum11 = 26'd0;
reg signed [25 : 0] sum12 = 26'd0;
reg signed [25 : 0] sum13 = 26'd0;
reg signed [25 : 0] sum14 = 26'd0;
reg signed [26 : 0] sum21 = 27'd0;
reg signed [26 : 0] sum22 = 27'd0;
reg signed [27 : 0] sum = 28'd0;
always@(posedge clk)
begin
sum11 <= mult_out[0] + mult_out[1] + mult_out[2] + mult_out[3];
end
always@(posedge clk)
begin
sum12 <= mult_out[4] + mult_out[5] + mult_out[6] + mult_out[7];
end
always@(posedge clk)
begin
sum13 <= mult_out[8] + mult_out[9] + mult_out[10] + mult_out[11];
end
always@(posedge clk)
begin
sum14 <= mult_out[12] + mult_out[13] + mult_out[14] + mult_out[15];
end
always@(posedge clk)
begin
sum21 <= sum11 + sum12;
end
always@(posedge clk)
begin
sum22 <= sum13 + sum14;
end
always@(posedge clk)
begin
sum <= sum21 + sum22;
end
assign data_out = sum;
integer fp_power0;
initial
begin
fp_power0 = $fopen("D:/Project/fir/pow_ch0.txt");
end
always @(posedge clk)
begin
begin
$fdisplay(fp_power0 ,"%h",sum[27:0]);
end
end
initial
begin
#3000;
$fclose(fp_power0);
end
endmodule
FPGA程序开发工具Vivado2015.4,使用其他编译器需要调整乘法器IP的延迟。FPGA仿真结果如图所示:
由图中可以看到与MATLAB仿真结果相同,FPGA的数据导到MATLAB做fft之后与MATLAB直接做fft有些不同的原因是做付fft的数据长度不同,可关注MATLAB读取的FPGA数据,会发现数据FPGA处理结果与MATLAB处理结果相同。