FIR滤波器设计

该博客意义在于将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)));

由图可以看出30Hz的信号被滤掉了,说明滤波器设计的正确
该程序中对信号进行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仿真结果如图所示:
FPGA行为级仿真时域图
FPGA的数据导到MATLAB中做fft看的结果
由图中可以看到与MATLAB仿真结果相同,FPGA的数据导到MATLAB做fft之后与MATLAB直接做fft有些不同的原因是做付fft的数据长度不同,可关注MATLAB读取的FPGA数据,会发现数据FPGA处理结果与MATLAB处理结果相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值