提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
FPGA信号处理系列文章——Xilinx FIR IP的matlab模型的使用
前言
Xilinx FIR IP作为一个信号处理的IP,考虑到了如何在matlab和C模型环境下如何模拟该IP核的输入输出数据,运用Xilinx FIR IP的模型,我们无需考虑时序有关的问题就可以对输入输出进行大样本的验证,而不是通过modelsim去进行仿真。相对于matlab和C环境下的仿真效率比在modelsim上效率高千百倍,最重要的是,modelsim出来的结果和matlab或者C模型只要参数设置一致,那么输入输出会是完全一致的。因此很多大型工程,尤其是做芯片,都有一个C或者matlab模型进行支撑,通过C模型来指导verilog设计。
FIR IP C/MATLAB模型的说明
在于pg149文档的第五章。
介绍了C模型和matlab模型,C模型的话暂时还没研究,这里主要记录下matlab模型的使用,以及自带例程的运行。
matlab模型使用起来也很简单,每次例化了一个FIR ip核之后,ip核的文件夹会带一个cmodel的文件夹。
里面包含了这两个压缩文件,lin64是在linux下使用,nt64是在windows下使用。我们解压nt64压缩文件后,也就看到了上表格中红色方框中的这些文件了。
首先,我们需要在matlab中运行 make_fir_compiler_v7_2_mex 这个文件,会生成一个fir_compiler_v7_2_bitacc_mex.mexw64这样的文件,然后,在运行 run_fir_compiler_v7_2_mex,这样matlab例程就可以运行起来的了。
还有一些详细的函数说明可以参照数据手册说的,直接通过看例程也可以快速了解该模型的使用,这里就不多说了。
注意,我这里用的是matlab2019b,操作系统是win10,vivado2019.2
FIR ip MATLAB模型的简要说明
run_fir_compiler_v7_2_mex 文件中自带5个例子。
公共参数
fft_size = 4096; %FFT分析点数
data_samples = 4096; %数据采样点数
window_name = @hamming; %窗函数
下面是使用其他窗函数的定义,
@barthannwin
@bartlett
@blackman
@blackmanharris
@bohmanwin
@chebwin
@flattopwin
@gausswin
@hamming
@hann
@kaiser
@nuttallwin
@parzenwin
@rectwin
@taylorwin
@triang
@tukeywin
使用这种@方法,实际上使用一个参数固定的典型窗函数,例如@hamming
对于系数的幅频响应分析方法
fr_filter = fft(config1.coeff,fft_size);
plot(20*log10(abs(fr_filter(1:fft_size/2))./max(abs(fr_filter))));
grid on;
IP核中使用的是,没有归一化的:
plot(20*log10(abs(fr_filter(1:fft_size/2))));
而Xilinx IP核中的图:
这两个图是一样的
示例1:(Create default filter IP核默认设置)
默认设置的系数就是这个:
% Constants
fft_size = 4096;
data_samples = 4096;
window_name = @hamming;
%window_name = @rectwin; %矩形窗
% Create default filter
disp('---------------------------------------------------------------------');
disp('INFO: Create default filter');
disp('---------------------------------------------------------------------');
fir1 = fir_compiler_v7_2_bitacc()
config1 = get_configuration(fir1);
% Create an input data vector
% - Scaled to match the default models data format; Fix16_0
disp('INFO: Generate input data...');
data_in = 16e3*(sin(0.5*[1:1:data_samples])+sin(2*[1:1:data_samples]));
% Filter data
disp('INFO: Filter...');
data_out = filter(fir1,data_in);
% Plot normalized filter response, input data and output data
disp('INFO: Plot filter response, input data and output data');
fr_filter = fft(config1.coeff,fft_size);
fr_data_in = fft(data_in.*window(window_name,data_samples)',fft_size);
%fr_data_in = fft(data_in,fft_size);
fr_data_out = fft(data_out.*window(window_name,data_samples)',fft_size);
%fr_data_out = fft(data_out,fft_size);
figure;
plot(20*log10(abs(fr_filter(1:fft_size/2))./max(abs(fr_filter))));
hold on;
grid on;
plot(20*log10(abs(fr_data_in(1:fft_size/2))./max(abs(fr_data_in))),'r');
plot(20*log10(abs(fr_data_out(1:fft_size/2))./max(abs(fr_data_out))),'g');
legend('Filter','Data in','Data out');
title('Default filter configuration');
disp('Press any key to continue...'); pause;
看绿色的曲线,经过滤波器后,幅度正好到达滤波器的包络处
示例2:(Create 2 channel upsampling filter 双通道升采样滤波)
% Constants
fft_size = 4096;
data_samples = 4096;
window_name = @hamming;
%window_name = @rectwin; %矩形窗
% Create 2 channel upsampling filter
disp('---------------------------------------------------------------------');
disp('INFO: Create 2 channel upsampling filter');
disp('---------------------------------------------------------------------');
disp('Press any key to continue...'); pause;
fir3 = fir_compiler_v7_2_bitacc('filter_type',1,'interp_rate',2,'num_channels',2)
config3 = get_configuration(fir3);
% Create input data vector
% - Scaled to match the default models data format; Fix16_0
disp('INFO: Generate input data...');
clear data_in;
data_in(1,:) = 16e3*(sin(0.5*[1:1:data_samples/2]));
data_in(2,:) = 8e3*(sin(0.2*[1:1:data_samples/2]));
% Create upsampled data with no filtering for comparison
data_up(1,:) = upsample(data_in(1,:),2); % 实际上是数据中间补0
data_up(2,:) = upsample(data_in(2,:),2); % 实际上是数据中间补0
% Filter data
disp('INFO: Filter...');
data_out = filter(fir3,data_in);
% Plot normalized filter response, input data and output data
disp('INFO: Plot filter response, input data and output data');
wndw(1,:) = window(window_name,data_samples/2);
wndw(2,:) = window(window_name,data_samples/2);
wndw_up(1,:) = window(window_name,data_samples);
wndw_up(2,:) = window(window_name,data_samples);
fr_filter = fft(config3.coeff,fft_size);
fr_data_in = fft(data_in.*wndw,fft_size,2);
fr_data_up = fft(data_up.*wndw_up,fft_size,2);
fr_data_out = fft(data_out.*wndw_up,fft_size,2);
figure;
subplot(3,1,1);
plot(20*log10(abs(fr_data_in(1,1:fft_size/2))./max(max(abs(fr_data_in)))),'b');
hold on;
grid on;
plot(20*log10(abs(fr_data_in(2,1:fft_size/2))./max(max(abs(fr_data_in)))),'r');
legend('Data In (ch1)','Data In (ch2)');
title('Input data');
subplot(3,1,2);
plot(20*log10(abs(fr_data_up(1,1:fft_size/2))./max(max(abs(fr_data_up)))),'g');
hold on;
grid on;
plot(20*log10(abs(fr_data_up(2,1:fft_size/2))./max(max(abs(fr_data_up)))),'c');
legend('Data upsampled (ch1)','Data upsampled (ch2)');
title('Upsampled no filtering');
subplot(3,1,3);
plot(20*log10(abs(fr_filter(1:fft_size/2))./max(abs(fr_filter))),'b');
hold on;
grid on;
plot(20*log10(abs(fr_data_out(1,1:fft_size/2))./max(max(abs(fr_data_out)))),'r');
plot(20*log10(abs(fr_data_out(2,1:fft_size/2))./max(max(abs(fr_data_out)))),'g');
legend('Filter','Data upsampled (ch1)','Data upsampled (ch2)');
title('Upsampled plus filtering');
disp('Press any key to continue...'); pause;
示例3:(使用自定义抽头滤波器,且观察量化后的误差)
函数: cfirpm
b = cfirpm(n,f,@fresp) n 阶数 f [0 FP FS 1] @lowpass 的一个用法
% Constants
fft_size = 4096;
data_samples = 4096;
window_name = @hamming;
%window_name = @rectwin; %矩形窗
% Create filter using coefficients created by firpm
% - Coefficients will be quantized by the FIR Compiler object
disp('---------------------------------------------------------------------');
disp('INFO: Create filter using coefficients generated by cfirpm');
disp('---------------------------------------------------------------------');
disp('Press any key to continue...'); pause;
disp('INFO: Creating coefficients...');
fl = 99;
f = [0,0.2,0.3,1];
coeff = cfirpm(fl,f,@lowpass);
disp('INFO: Creating filter quantizing coefficients to Fix16_15 ...');
fir4 = fir_compiler_v7_2_bitacc('coeff',coeff,'num_coeffs',fl+1,'coeff_width',16,'coeff_fract_width',15,'data_width',16,'data_fract_width',14)
config4 = get_configuration(fir4);
% Plot source and quantized filter coefficients
disp('INFO: Plot quantized coefficients vs source coefficients');
figure;
fr_filter = fft(config4.coeff,fft_size);
fr_filter_quant= fft(filter(fir4,[1,zeros(1,fl)]),fft_size);
%这个语句 filter(fir4,[1,zeros(1,fl)])
%等价于
%coeff1 = round(coeff*2^15)/2^15; 2^15 与coeff_fract_width参数对应
%还没搞清楚为什么
%plot(filter(fir4,[1,zeros(1,fl)]) - coeff1)
plot(20*log10(abs(fr_filter(1:fft_size/2))./max(abs(fr_filter))),'b');
hold on;
grid on;
plot(20*log10(abs(fr_filter_quant(1:fft_size/2))./max(abs(fr_filter_quant))),'r');
legend('Source Coefficients','Quantized Coefficients');
title('Coefficient Quantization');
disp('Press any key to continue...'); pause;
% Create an input data vector
disp('INFO: Generate input data...');
clear data_in;
data_in = sin(0.5*[1:1:data_samples])+sin(2*[1:1:data_samples]);
% Filter data
disp('INFO: Filter...');
data_out = filter(fir4,data_in);
% Plot normalized filter response, input data and output data
disp('INFO: Plot filter response, input data and output data');
fr_data_in = fft(data_in.*window(window_name,data_samples)',fft_size);
fr_data_out = fft(data_out.*window(window_name,data_samples)',fft_size);
figure;
plot(20*log10(abs(fr_filter_quant(1:fft_size/2))./max(abs(fr_filter_quant))));
hold on;
grid on;
plot(20*log10(abs(fr_data_in(1:fft_size/2))./max(abs(fr_data_in))),'r');
plot(20*log10(abs(fr_data_out(1:fft_size/2))./max(abs(fr_data_out))),'g');
legend('Filter','Data in','Data out');
title('Filter using quantized coefficients');
disp('Press any key to continue...'); pause;
量化后与没有量化幅频响应对比