MATLAB设计FPGA实现联合ISE和Modelsim仿真的FIR滤波器设计

更新时间:2024-01-13 09:48:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

QQ:290632690 肤浅。。。制作

图3

用MATLAB回读C盘根目录下的matlab_wave_data.txt文件,验证存入的波形数据是否正确,MATLAB代码如下:

fid = fopen('c:/matlab_wave_data.txt','r'); for i = 1 : 5001;%一共有5001个数据

num(i) = fscanf(fid, '%x', 1);%从fid所指的文件中,以16进制的方式读出一个数据 end fclose(fid); figure(2); plot(num,'b');

legend('MATLAB从txt文件中读出的原始叠加波形数据'); title('直接回读MATLAB产生的两个正弦信号的叠加波形'); 显示的波形如图4所示:

1

QQ:290632690 肤浅。。。制作

图4

对比图4和图2中的叠加波形,可知以上操作的正确性。 1) 用MATLAB设计FIR滤波器

输入信号是频率别为0.5MHz和2MHz的正弦信号的叠加,我们的任务是设计一个低通滤波器滤除掉2MHz的干扰信号。因此,我们可以设计一个采样率为25MHz的低通滤波器,其通带带宽为1MHz,阻带宽度为2MHz。通带内纹波抖动为1dB,阻带下降为80dB。

在MATLAB的命令窗口输入:fdatool命令并回车,打开FDATool工具箱,用MATLAB的FDATool工具设计该滤波器,参数设置如图5所示:

设计好参数后,点击DesignFilter,可以在FDATool窗口的左上角看到滤波器的阶数为63阶,点击File ?Generate M-file,并将滤波器命名为mylowfilter。

2

QQ:290632690 肤浅。。。制作

图5

编写如下代码,滤除混叠信号中的高频信号。 Hd = mylowfilter; % 滤波器名称

output = filter(Hd, y1); % 对叠加信号 y ,进行滤波处理 figure(3); plot(y2, 'k'); hold on; plot(output, 'r');

legend('0.5MHz原始信号','滤波后取出的信号'); title('信号通过MTALAB的低通滤波器后的波形'); 滤波后的波形如图6所示:

3

QQ:290632690 肤浅。。。制作

图6

生成.coe文件,用于Xilinx的IPCore设计滤波器,FDATool窗口点击File ?Export…,保持默认设置,点击Export即可,次数在MATLAB的workspace窗口多出一个Num的1*64的数组,这就是滤波器的系数,如图7所示:

图7

由于MATLAB生成的滤波器系数全是一些小数,而FPGA只能处理整数,因此我们必须将这些小数扩大一定的倍数,使它们变成整数。

在MATLAB的命令窗口输入下面的一段代码然后按Enter,即可将上面这些系数变为整数,注意这里的*32767,表示将系数扩大32767倍,这里的扩大倍数只能选2^N,目的是为了后面滤波后的波形数据的高位截取(丢掉低位,即除以2^N)。返回ans=0,表示操作正确。

4

QQ:290632690 肤浅。。。制作

coeff=round(Num/max(abs(Num))*32767);

% abs() 求绝对值,max() 求最大值,round() 四舍五入 fid = fopen('e:/fircoe.txt','wt'); %将滤波器系数写入文件件中

fprintf(fid,'.0f\\n',coeff);% 将滤波器系数以16位浮点数的格式保存 fclose(fid)

程序运行的结果如图8所示:

图8

将文件的格式改为.coe格式,在文件的开口加上: radix = 10; coefdata =

5

QQ:290632690 肤浅。。。制作

图11

图12

FIR的IPCore的列化如下: FIR16_IP FIR16_IP_ins (

.clk(clk), // input clk

.rfd(rfd), // output rfd 在其上升沿将输入数据加载到滤波器内核中

6

QQ:290632690 肤浅。。。制作

.rdy(rdy), // output rdy 在其上升沿输出滤波器的计算结果 .din(data_in_reg), // input [15 : 0] din

.dout(dout)); // output [35 : 0] dout 特别注意这个数据位宽

我们主要对其进行简单的控制:在rfd 上升沿将输入数据加载到滤波器内核中,在rdy

上升沿输出滤波器的计算结果。具体的Verilog代码如下: always @ (posedge clk) begin end

always @ (posedge clk) begin

if(reset == 1'b0) begin end else begin end

rfd_1q rfd_2q

<= <=

rfd; rfd_1q;

i

<= <= <=

1'b0; 1'b0; 16'h0000;

m

data_in_reg

if(rfd_1q & ~rfd) begin // rfd 信号的上升沿将输入数据加载到滤波器内核中 end

data_in_reg i

<= <=

data_in[i]; i + 1; ~m;

m <= if(i == 2002)

i

<=

0;

if(reset == 1'b0) begin end

7

Data_out_reg j n

<=

0;

0; 0;

<= <=

QQ:290632690 肤浅。。。制作

end

else begin end

rdy_1q <= rdy_2q <=

rdy; rdy_1q;

if(rdy_1q & ~rdy) begin end

Data_out_reg j

<=

dout;

j + 1'b1; ~n;

<=

n <=

这里还做了一个附加功能,将FIR滤波器的输入数据存放到一个.txt文件当中,然后用MATLAB去读取这个波形文件数据,看看读出的波形是否和原来的混叠波形一样。具体的Verilog和MATLAB代码如下: integer wr_file; initial

wr_file = $fopen(\

always @( m ) begin end

fid = fopen('c:/FIR_in_data.txt','r'); for j = 1 : 2000;

num1(j) = fscanf(fid, '%x', 1);%这句话的意思是从fid所指的文件以16进制方式读出一个数据。 end fclose(fid); figure(4); plot(num1,'r');

8

if(reset == 1'b1) begin end

$fdisplay(wr_file,\数 if(j == 11'd2002) //共写入2001个数据 $stop;

QQ:290632690 肤浅。。。制作

legend('Verilog读出的txt文件中的数据'); title('FIR滤波器的输入数据');

MATLAB读出的波形数据如图13所示:

图13

这里我也搞了好久才搞好,这里FIR滤波器的输出数据位宽变成了36bit,而输入数据位宽是16bit,为什么数据会变大几万倍呢?

因为我们在将滤波器的系数由小数变成整数的时候,对这些系数整体扩大了32767倍,再做了一个四舍五入(影响滤波器精度),对滤波器的系数扩大的倍数越大,四舍五入对精度的影响就越小,但是系数乘的倍数越大,FPGA在做乘加运算也就越复杂,也就越耗时,越耗资源,因此我们需要找一个平衡点。

这里为了将信号的幅度变回原始的幅度(尽可能的靠近),我们只能通过将低位截取掉,截取低位相当于对数据做除法(除2),所以前面的滤波器系数的扩大倍数我们一定要用2^N,这样我们在这里还原信号幅度的时候,只需要截位就能达到目的。

比如这里我们对滤波器的系数乘了32767,那我们在做除法还原波形幅度时,只需要除以32767即可(即截掉低16bit)。还有一种操作方式就是我们只保留数据的高16bit(和输入数据的位宽保持一致),这两种方式波形的幅度也就几倍的差距,我还没有完全搞懂这里,究竟怎样才能将波形的幅度完全的还原回去,还是一个值得好好思考的问题?

另一个问题是我的电脑是32bit位宽的,如果我们一次性让MATLAB读取36bit的数据那么数据的高4bit会读不上来,会导致很奇怪的波形,我也遇到了这个问题。如图14所示,

9

QQ:290632690 肤浅。。。制作

波形明显可以通过一些平移拼合成一个正弦波。通过对波形数据一个个的分析,我找到了这个问题。

图14

图15是波形幅度发生变化的截图:

图15

字滤波器的性能,肯定能够大大的缩短设计周期,提升滤波器性能。

附录:

附录为Verilog源代码和MATLAB源代码,这些源代码是经过调试的,是可以直接使用的。供大家参考。

Verilog源代码: module FIR_Lowpass(

clk,

10

QQ:290632690 肤浅。。。制作

for j = 1 : 2000;

num1(j) = fscanf(fid, '%x', 1);%这句话的意思是从fid所指的文件以16进制方式读出一个数据。 end fclose(fid); figure(4); plot(num1,'r');

legend('Verilog读出的txt文件中的数据'); title('FIR滤波器的输入数据');

%*********MATLAB回读FIR滤波器滤波后的数据(FIR由Verilog实现)*************** fid = fopen('c:/FIR_out.txt','r'); for i = 1 : 2000;

num(i) = fscanf(fid, '%x', 1);%这句话的意思是从fid所指的文件以16进制方式读出一个数据。 end fclose(fid); figure(5); plot(num,'r'); y4 = y2; hold on; plot(y4, 'k');

legend('经过FIR_IPCore滤波后的数据','0.5MHz的原始数据放大16384倍'); title('经过FIR滤波器的输出数据');

16

本文来源:https://www.bwwdw.com/article/2aeo.html

Top