关于VIVADO FIR Compiler的设计与使用
1、MATLAB的FIR使用参照官方文档
FIR 滤波器设计 - MATLAB & Simulink - MathWorks 中国
一般选用I类的FIR的滤波器。
2、matlab输出FIR滤波器抽头系数
%可复制进MATLAB R2016a以上版本使用
clear;
%设计一个带通滤波器。
%采样频率越高,所需要的阶数n也就越高,FPGA资源使用量越高,
%可以适当减少,但考虑到奈奎斯特采样定理,采样频率必须大于两倍的截止频率
fs=2.5*10^6;%单位Hz
%滤波器系数量化分辨率位数,位数越大,实际频响越接近理想频响,但会增加FPGA资源使用量
qm=16;
%过渡带 [50K 100K 400K 450K] 单位Hz
fc=[50*10^3 100*10^3 400*10^3 450*10^3];
%三个数表示了50K~100K,100K~400K,400K~450KHz三个频带中理想的幅度值
mag=[0 1 0];
%设置通带误差容限a1及阻带误差容限a2,a3,通带没有特别需求通常设置为0.3,即-3dB
%通带最大衰减 = 20*log10(1-a2) dB
%阻带最小衰减 = 20*log10(1-a1) dB
%阻带最小衰减 = 20*log10(1-a3) dB
a1=0.001;a2=0.3;a3=0.001;
dev=[a1 a2 a3];
%采用凯塞窗函数获取满足要求的最小滤波器阶数,阶数大小影响FPGA资源使用量
[n,~,~,~] = kaiserord(fc,mag,dev,fs);
%firpm函数的频段向量,新增0与fs/2
fpm=[0 fc(1) fc(2) fc(3) fc(4) fs/2];
%firpm函数的幅值向量,与上述频段向量一一对应即可
magpm=[0 0 1 1 0 0 ];
%频率归一化
wnpm=fpm*2/fs;
%为满足I型FIR滤波器,将n选择为偶数
n=n + rem(n,2);
%采用firpm函数设计最优滤波器
h_pm=firpm(n,wnpm,magpm);
%计算得出的系数向量归一化
h_pm = h_pm/max(abs(h_pm));
%量化滤波系数为12bit有符号整数
q_pm=round(h_pm*(2^(qm-1)-1));
%将生成的滤波器系数数据写入FPGA所需的coe文件中
fid=fopen('.\fir_coe.coe','w');
fprintf(fid, 'RADIX=10;\n');%生成索引
fprintf(fid, 'COEFDATA = \n');
for i = 1:n+1
if i == n+1
fprintf(fid,'%d;', q_pm(i));
else
fprintf(fid,'%d,', q_pm(i));
end
end
fclose(fid);
%获取量化前后滤波器的幅频响应数据
m_pm=20*log10(abs(fft(h_pm,1024)));
m_pm=m_pm-max(m_pm);
q_pm=20*log10(abs(fft(q_pm,1024)));
q_pm=q_pm-max(q_pm);
%设置幅频响应的横坐标单位为MHz
x_f = (0:(fs/length(m_pm)):fs/2)/10^6;
%只显示正频率部分的幅频响应
mf_pm=m_pm(1:length(x_f)); %未量化时理想幅值
mf_qm=q_pm(1:length(x_f)); %量化后的实际幅值
%由于量化后取整的操作,可能导致频响变化,为作对比将其打印
%绘制幅频响应曲线
plot(x_f,mf_pm,'--',x_f,mf_qm,'-');
xlabel('频率(MHz)');ylabel('幅度(dB)');
legend('未量化','12位量化');
grid;
3、VIVADO FIR Compiler
官方文档TDATA • FIR Compiler (PG149) • Reader • AMD Adaptive Computing Documentation Portal (xilinx.com)
1
- :选择Filter Options页面
- :选择.coe文件,这里的.coe文件与上述MATLAB程序生成的文件不一致,由于上述的阶数n过长,会导致综合编译时间过长,故使用另外的.coe文件,文件内容如下。
RADIX=10;
COEFDATA =
-29,-91,-166,-194,-135,-45,-88,-371,-727,-724,-36,1130,2047,2047,1130,-36,-724,-727,-371,-88,-45,-135,-194,-166,-91,-29,-18,-54,-44,-32,-141,-110,-28,-295,-185,90,-625,-235,2047,2047,-235,-625,90,-185,-295,-28,-110,-141,-32,-44,-54,-18;
频响如下
该内容中含有2组的FIR抽头系数。
- :如果.coe文件中只含有1组滤波器系数,这里填入1;2组系数则填2,以此类推。程序运行过程中可通过特定接口选择不同组的系数,用以切换不同需求的频率响应。这里选择了2组。
- :勾选选择是否使用重新加载系数。与上述切换不同组的系数相同,最终目的都是为了切换不同需求的频率响应,但过程有所不同。与③相同,这里的重新装填的系数可以来自预先存储于FPGA内部的寄存器,不同的是,它也可来自与外部通信接收得到的数据,或者来自FPGA内部计算。将准备好的数据再通过特定接口送入FIR滤波器。目前还未有相关需求,暂未实现此部分功能。
- :默认选择Single Rate。
- :选择Freq.Response页面
- :如果②③步骤中选择了多组滤波器系数,则在这里可以选择不同的组别,观察不同的频率响应函数。如图最大增益大约为80dB,这是因为系数量化成为了12bit的二进制数据,12bit二进制数最大值为12’d4095,20*lg(4095) ≈ 72.25dB,接近图像上的频响曲线波峰。
2
- :选择Channel Specification页面
- :默认Basic,还未研究advance功能
- :交错通道数量设,增加数量会增加DSP资源的消耗,此次设定为16个
- :并行通道数量设定,本质上是例化了多个FIR滤波器,大大增加了FPGA资源使用量
- :关于采样的设定,默认选择频率采样。
- :采样频率为前述的2.5MHz
- :工作频率决定了时分复用下可容纳的交错通道数量,这里设定为FPGA工作频率100MHz,最多可容纳100MHz/2.5MHz=40个交错通道。
3
- :选择Implementation页
- :.coe文件中准备好的是整型的系数,故选择整型系数
- :MATLAB计算的时候以及确定抽头系数的分辨率为12bit,即位宽是12bit。
- :输入的波形数据带符号位
- :输入的波形数据包括符号位在内位宽为16bit
- :输出的波形数据为全精度
4
- :选择Interface页面
- :将TLAST选为Packet Framing,在输入数据时可作标记,在滤波完成输出的时候也会在相应的地方标记,根据官方文档,其用意是为简化逻辑设计。
- :TUSER输入都选择Channel ID Field,由于存在时分复用,故需要它作为标记,就目前使用情况可不使用TLAST,只使用TUSER,TUSER为位宽为log2(通道数),上述设定了位宽为16bit,这里TUSER为4bit的0~15。在输入通道0的数据时,将TUSER置为0;在输入通道1的数据时,将TUSER置为1,依此类推。
- :TUSER输出同理
- :配置通道默认选择向量
- :默认选择单端
- :勾选低电平复位
- :勾选后在复位时也将所有数据向量包括波形数据等复位
- :选择Implementation Details页面。可以看到各个接口的详细的数据分配。例如S_AXIS_DATA-TDATA中,可以看到0~15代表了16个通道,16bit全字段都代表了输入的波形数据。
5
- :Summary页面中再核验一遍设置
- :IP Symbol中可以查看模块的完整接口
4、输入数据源
使用MATLAB产生,代码如下:
clear;
%输出sin函数频率 = FIR采样频率/(div*2) 现基频 2500K/50*2 = 25K
div = 50;
%实际上想要做2^16的分辨率sin函数,
%但是归一化后输出取值在-1~1,差值为2,故2^16的分辨率实际只需要2^15
limit = 2^15;
data_length = 100; %数据长度
if data_length < 2*div
data_length = 2*div;
end
y_pre =zeros(1,div*2);
%y_hex =zeros(1,div*2);
x = 0 : pi/div : (data_length/div)*pi-pi/div;
%可以增加需要叠加的频率信号,合成多种频率的信号
y=1*sin(24*x) + 0.1*sin(2*x) + 0.1*sin(40*x);
y_max = max(abs(y));
y = y/y_max; %归一化
y=fix(y*(limit-1));
plot(x,y);
for j = 1:data_length
if y(j) < 0
y_pre(j)= y(j) + limit*2;
else
y_pre(j) = y(j);
end
end
%plot(x,y_pre);
y_hex=dec2hex(y_pre);
fid=fopen('.\sin_test.txt','w');
for i = 1:data_length
fprintf(fid,'%c%c%c%c\n', y_hex(i,1), y_hex(i,2), y_hex(i,3), y_hex(i,4));
end
fclose(fid);
5、接口时序
1 输入交错通道的波形数据
数据通道中,上电后等待tready被FIR模块拉高,而后可拉高tvaild发送数据,tuser也随之开始递增,根据tuser的不同,表示发送不同通道的数据,当发送最后一个通道的数据即tuser=4‘hf时,tlast被拉高,如果拉高时机不对,incorrect将会被置1表示数据错误。
前述有计算过此FIR模块最多可容纳100MHz/2.5MHz=40个交错通道,即每40个系统时钟周期中每个交错通道都必须完成一次采样,故上述时序图的行为必须在每40个时钟周期完成一次,不能缩短也不能延长。否则,根据FIR模块的构成,将会导致输出数据混乱。
2 输入配置通道数据
配置通道同理。从3、VIVADO FIR Compiler中的4-⑨可以了解到tdata的最低位0或1的选择控制FIR系数选择。
3 输出交错通道的波形数据
输出数据tvalid被拉高时有效,此时根据tuser值,将tdata归为相应通道的数据。代码如下。
filter_signal[m_axis_data_tuser] <= m_axis_data_tdata;
6、仿真结果
频响如下
上图红色字体表明了该通道输入的波形频率成分,右侧波形为滤波后的波形结果。可以看到滤波效果良好。