利用FPGA的IP核实现FIR滤波器

一、首先是设计指标:

采用最优化设计方法(firpm),设计一个阶数为16阶(长度为17)的线性相位低通FIR滤波器,截止频率为500hz,fs=2000hz。,系数量化位数为12bit,输入数据位宽为12bit,输出数据位宽为25Bit,系统时钟为2khz。

 

二、设计流程:

(1)利用MATLAB设计滤波器系数,浮点数类型。

(2)Matlab测试滤波器性能,输入观察输出。

(3)利用FPGA的FIR滤波器IP核设计滤波器。

(4)编写testbench,测试滤波器性能。输入Matlab产生的激励文本文件,

             输出硬件处理后的信号,写入文本文件中。

(5)Matlab分析硬件处理后保存在文本文件中的信号。

三、设计步骤:

1,利用MATLAB设计滤波器系数。代码如下:

function hn=Fir_Coefficient_Design

N=17;      %滤波器长度

Sample_Freq=2000;   %采样频率

fc=500;    %低通滤波器的通带截止频率

B=12;      %量化位数

Cut_Off_Freq=[0 500 700 Sample_Freq/2];

Cut_Off_Freq=Cut_Off_Freq./(Sample_Freq/2); %归一化

Fir_Amplitude=[1 1 0 0];

Fir_Coefficient=firpm(N-1,Cut_Off_Freq,Fir_Amplitude);

hn=Fir_Coefficient;

freqz(Fir_Coefficient,1,1024,Sample_Freq);

 

注意MATLAB中频率归一化是针对fs/2,即采样率的一半。

利用FPGA的IP核实现FIR滤波器

接下来将滤波器系数写入文本文件中,

fid=fopen('Fir_Coefficient.txt','w');

for k=1:length(Fir_Coefficient)    

      fprintf(fid,'%.14f',Fir_Coefficient(k));

      if(k~=length(Fir_Coefficient) )          

       fprintf(fid,'\r\n');

      end

end

fclose(fid);

由于采用FIR Complier13.0,其中的用户手册有这么一句:

利用FPGA的IP核实现FIR滤波器

 

 

需要注意的就是最后一个系数后面不能有回车,否则导入系数文件的时候又会被FIR Complier识别为一个新的系数。这样,系数就被写进了文本文件Fir_Coefficient.txt

(2)Matlab测试滤波器性能,输入观察输出。

    思路就是生成两个信号,一个在通带内,一个在阻带内,然后调用filter函数进行滤波处理,观察输出信号的频谱。代码如下:    

f1=200;       %信号1频率为200Hz

f2=800;       %信号2频率为800Hz

Fs=2000;      %采样频率为2KHz

N=12;         %量化位数

t=0:1/Fs:1;

c1=2*pi*f1*t;

c2=2*pi*f2*t;

s1=sin(c1);%产生正弦波

s2=sin(c2);%产生正弦波

s=s1+s2;   %产生两个单载波合成后的信号

s=s/max(abs(s));%归一化处理

Q_s=round(s*(2^(N-1)-1));%12比特量化

%调用自已设计的滤波器函数对信号进行滤波

hn=Fir_Coefficient_Design;

Filter_s=filter(hn,1,Q_s);

然后观察输入输出频谱:可以看到800hz处的信号被衰减在-40db一下,符

合要求。

利用FPGA的IP核实现FIR滤波器 

 

接下来将测试信号以二进制数据格式写入Excitation_Signal_Bin.txt文件中,供给第四步仿真FPGA时testbench调用。

    fid=fopen('Excitation_Signal_Bin.txt','w');

for i=1:length(Q_s)

   B_s=dec2bin(Q_s(i)+(Q_s(i)<0)*2^N,N)

   for j=1:N

      if B_s(j)=='1'

          tb=1;

      else

          tb=0;

      end

      fprintf(fid,'%d',tb);  

   end

   fprintf(fid,'\r\n');

end

fprintf(fid,';');

fclose(fid);

 

(3)利用FPGA的FIR滤波器IP核设计滤波器。

 

    这个Altera提供的FIR Compiler v13.0有些老了,现在有FIR Compiler II v13.0,也就是2.0版本的FIR的IP核。这里还是用FIR Compiler v13.0吧,2.0版本日后再研究研究。

    打开MegaWizard Plug-In Manager,选择FIR Compiler v13.0,特别需要注意的是文件保存位置!只能保存在当前的工程目录下,不能放在别的文件夹里面!如果不放在工程目录下,后一步的modeisim仿真就会出错!

利用FPGA的IP核实现FIR滤波器

    

 接下来就是参数设置,单击上方的"Edit Coefficient",跳出"Coefficient Generator Dialog"对话框,选择下方的"Imported Coefficient Set",导入之前设计的滤波器系数"Fir_Coefficient.txt"。

    输入输出声明如下,输入一路,有符号二进制数,输入位宽12bit,输出选择基于"实际的系数","全精度"。输出位宽这里计算出是25bit。

利用FPGA的IP核实现FIR滤波器     

系数量化单位选择12bit,滤波器结构选择"分布式算法,全并行结构",流水级数选择1,数据和滤波器系数的存储都选择"Logic Cells"。这里 有什么不懂的,就要多看用户手册,写的比较清楚。

 

利用FPGA的IP核实现FIR滤波器     

 

接下来选择step 2,生成仿真文件,选择"Verilog HDL",还可以生成.m文件供MATLAB进行仿真分析,最后,Step3: Generate,这样整个滤波器便设计完成了。

接下来编写.v文件例化,即可。其输入输出信号参见IP核用户手册即可。这里给出代码参考:

    module Fir_FPGA (

    reset_n,clk,Xin,

    Yout);    

    input        reset_n;   //复位信号,低电平有效

    input        clk;       //FPGA系统时钟/数据速率:2kHz

    input     signed [11:0]    Xin;  //数据输入频率为2kHZ

    output signed [24:0]    Yout; //滤波后的输出数据

    wire ast_sink_valid,ast_source_ready,ast_source_valid;

    wire [1:0] ast_source_error;

    wire [1:0] ast_sink_error;

    assign ast_sink_valid=1'b1;

    assign ast_source_ready=1'b1;

    assign ast_sink_error=2'd0;

    fir    u_fir(

        .clk(clk),

        .reset_n(reset_n),

        .ast_sink_data(Xin),

        .ast_sink_valid(ast_sink_valid),

        .ast_source_ready(ast_source_ready),

        .ast_sink_error(ast_sink_error),

        .ast_source_data(Yout),

        .ast_sink_ready(ast_sink_ready),

        .ast_source_valid(ast_source_valid),

        .ast_source_error(ast_source_error));

(4)编写testbench,测试滤波器性能。    

主要就是将第二步MATLAB生成的激励信号输入module,然后将输出写入文本文件,供下一步MATLAB进行分析。

    这里采用Quartus II 软件的"processing->start->start Test Bench Template Writer"选项自动生成模块测试文件(Fir_FPGA.vt),该目录自动存储在"工程目录\simulation\modelsim"下,然后打开文件,编写文件即可。主要是时钟,复位信号,按照时钟节拍输入和输出数据。这里给出输入和输出:

    //从外部TX文件(SinIn.txt)读入数据作为测试激励

integer Pattern;

reg [11:0] stimulus[1:data_num];

initial

begin

  //文件必须放置在"工程目录\simulation\modelsim"路径下    

    $readmemb("Excitation_Signal_Bin.txt",stimulus);

    Pattern=0;

    repeat(data_num)

        begin

            Pattern=Pattern+1;

            Xin=stimulus[Pattern];

            #clk_period;//采用并行结构,数据周期等于时钟周期

        end

end

 

//将仿真数据dout写入外部TXT文件中(Response_Signal.txt)

integer file_out;

initial

begin

  //文件放置在"工程目录\simulation\modelsim"路径下                                                  

    file_out = $fopen("Response_Signal.txt");

    if(!file_out)

        begin

            $display("could not open file!");

            $finish;

        end

end

wire rst_write;

wire signed [24:0] dout_s;

assign dout_s = Yout;                   //将dout转换成有符号数据

assign rst_write = clk& (reset_n);//产生写入时钟信号,复位状态时不写入数据

always @(posedge rst_write )

    $fdisplay(file_out,"%d",dout_s);

    然后在quartus ii中设置"Assignment->Settings"选择"EDA Tool Setting",设

置如下:主要就是选择modelsim。

利用FPGA的IP核实现FIR滤波器

 

    再选择下边的"Simulation",设置仿真工具名称(Modelsin-Altera),下面的NativeLink setting,选中第二项"Compile test bench",选择上面编辑的Fir_FPGA.vt,设置好名称之类的选项后,选择quartus ii 中的"Tool->Run simulation tool->RT Simulation",就可以启动Modelsim进行仿真。仿真完成后,处理后数据自动保存在Response_Signal.txt中。

 

(5)Matlab分析硬件处理后保存在文本文件中的信号。

 

    最后,用MATLAB分析Response_Signal.txt中的数据,主要就是输入输出的频谱情况。分析结果如下:    

利用FPGA的IP核实现FIR滤波器

 可以看到,800hz处信号被衰减,达到预期效果。

四、总结

(1)Fir滤波器阶数=抽头数目减去1。

(2)firpm函数使用偶数阶系数,偶对称,总是在奈奎斯特频率处不为0。

(3).m文件返回值,可以在函数中指出。例如

function hn=Fir_Coefficient_Design

代码……

Fir_Coefficient=firpm(N-1,Cut_Off_Freq,Fir_Amplitude);

hn=Fir_Coefficient;

(4)也是困扰了我一晚上的,生成的IP核按照CB哥的教程放入自己新建的core文件夹下,启动modelsim进行仿真时总是提示" Library auk_dspip_lib not found",提示找不到这个库。

利用FPGA的IP核实现FIR滤波器    

 

后来google了一下,在这个网址下

"http://www.alteraforum.com/forum/showthread.php?t=29063"。一哥们给出解答:"Move your generated megafunction files back to the main project folder",需要把生成的FIR IP核全部文件放在工程目录下,好像这个Bug不影响其他的IP核,呵呵,日后用到其他IP核再说。


转自:http://blog.chinaaet.com/teenagerold/p/5100051606