天天看點

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)));
           
FIR濾波器設計

該程式中對信号進行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;

[email protected](posedge clk)
begin
    sum11 <= mult_out[0] + mult_out[1] + mult_out[2] + mult_out[3];
end

[email protected](posedge clk)
begin
    sum12 <= mult_out[4] + mult_out[5] + mult_out[6] + mult_out[7];
end

[email protected](posedge clk)
begin
    sum13 <= mult_out[8] + mult_out[9] + mult_out[10] + mult_out[11];
end

[email protected](posedge clk)
begin
    sum14 <= mult_out[12] + mult_out[13] + mult_out[14] + mult_out[15];
end

[email protected](posedge clk)
begin
    sum21 <= sum11 + sum12;
end

[email protected](posedge clk)
begin
    sum22 <= sum13 + sum14;
end

[email protected](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仿真結果如圖所示:

FIR濾波器設計
FIR濾波器設計

由圖中可以看到與MATLAB仿真結果相同,FPGA的資料導到MATLAB做fft之後與MATLAB直接做fft有些不同的原因是做付fft的資料長度不同,可關注MATLAB讀取的FPGA資料,會發現資料FPGA處理結果與MATLAB處理結果相同。

繼續閱讀