FIR Compiler IP系数重加载方法
1 基本介绍
FIR Compiler模块提供了两种滤波器系数重加载方法。
1、reload方法,利用reload接口写入新系数。
2、config方法,提前将系数分组后写到Coefficient Vector中,再通过config接口写入系数组编号,选择相应的滤波器系数。与reload方法相比,config方法较为简单,缺点是灵活性不够,需要提前规划好所有需要重配置的滤波器系数。
2 实现流程
1、利用MATLAB生成两个带通滤波器的coe系数文件。
第一个带通滤波器允许5M的信号通过,第一个带通滤波器允许10M的信号通过。
2、在Vivado利用DDS产生两个点频信号。其频率分别为5M和10M,并将两个点频信号相加。
3、调用FIR IP,并将coe系数文件加载到IP中。
3 具体实现步骤
3.1 生成两个带通滤波器的coe系数文件
close all;
clear all;
clc;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 参数定义
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Quantify_bit=16; % 量化位数 16位
fs=125e6; % 采样频率
N=1e3;
t=(0:N-1)/fs;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%---- 产生原始信号 5M+10M的混叠信号
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
f1=5e6;
f2=10e6;
x=cos(2*pi*f1*t)+cos(2*pi*f2*t+pi/6);
figure(1);
plot(t,x);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 带通滤波器
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ---------BANDPASS_5M Returns a discrete-time filter object.
% All frequency values are in MHz.
Fs = 125; % Sampling Frequency
N = 100; % Order
Fc1 = 3; % First Cutoff Frequency
Fc2 = 7; % Second Cutoff Frequency
flag = 'scale'; % Sampling Flag
Beta = 0.5; % Window Parameter
% Create the window vector for the design algorithm.
win = kaiser(N+1, Beta);
% Calculate the coefficients using the FIR1 function.
b1 = fir1(N, [Fc1 Fc2]/(Fs/2), 'bandpass', win, flag);
%------BANDPASS_10M Returns a discrete-time filter object.
% All frequency values are in MHz.
Fs = 125; % Sampling Frequency
N = 100; % Order
Fc1 = 8; % First Cutoff Frequency
Fc2 = 12; % Second Cutoff Frequency
flag = 'scale'; % Sampling Flag
Beta = 0.5; % Window Parameter
% Create the window vector for the design algorithm.
win = kaiser(N+1, Beta);
% Calculate the coefficients using the FIR1 function.
b2 = fir1(N, [Fc1 Fc2]/(Fs/2), 'bandpass', win, flag);
%----拼接
h=[b1,b2];
L_h=length(h);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 导出滤波器的数据
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fid=fopen('bandpass.coe','w'); % 实部
[b1_data]= coe_generate(fid,Quantify_bit,L_h,h);
%----5M的带通
y1=conv(x,b1);
delay=(length(b1)-1)/2;
y1=y1( delay+1:1:end-delay );
L=length(y1);
f=(0:L-1)*fs/L-fs/2;
Y1=fftshift(fft(y1));
P1=abs(Y1)/L;
figure(2);
subplot(211);plot(t,y1);
subplot(212);plot(f,P1);
%----10M的带通
y2=conv(x,b2);
y2=y2( delay+1:1:end-delay );
L=length(y2);
Y2=fftshift(fft(y2));
P2=abs(Y2)/L;
figure(3);
subplot(211);plot(t,y2);
subplot(212);plot(f,P2);
function [yt]= coe_generate(fid,Quantify_bit,L,b)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB生成coe文件
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 在.coe文件中
% 第一行为定义数据格式, 2代表 ROM 的数据格式为二进制。
% 从第 3 行开始yong到第最后一行,是这个 L(数据长度为1024)* ADC_bit(16bit) 大小 ROM 的初始化数据。
% 第一行到倒数第二行的数字后面用逗号,最后一行数字结束用分号。
yt=round(b*(2^(Quantify_bit-1)-1)); % 16bit量化
% fid=fopen('band_filter.coe','w'); % w表示write
fprintf(fid,'Radix = 10;\r\n'); % 二进制
fprintf(fid,'coefdata = \r\n');
for p=1:L
fprintf(fid,'%d',yt(p)); % 写入数据
% 下面if语句的目的
% 每行数字后面用逗号(,),最后一行数字结束用分号(;)
if (p<L)
fprintf(fid,' \r\n');
else
fprintf(fid,';\r\n'); % 分号(;) 结束标志位
end
end
fclose(fid);
end
3.2 配置 DDS
3.3 配置 FIR IP
下图中,选择COE file,Coefficient File 选择MATLAB生成的coe系数文件
由于有两组滤波器系数,所以Number of Coefficient Sets选择2。
下图中,MATLAB的量化位数为16bit,所以这里的Quantization选择16,COE系数为十进制有符号数。
Quantify_bit=16; % 量化位数 16位
FIR滤波器的输入信号的位宽为16。
5 实现代码
5.1 源文件
`timescale 1ns / 1ps
module FIR_COEF_Reload(
input clk , //系统时钟 125M
input reset , //复位
input [1:0] Freq_Select // config信道上选择系数的组别
);
//--------1、产生10M和5M的正弦波信号,然后两个信号混叠
// 输出频率字的计算公式:deta_theta=f_out*(2^B)/f_clk
// 相位位宽:32bit 系统时钟 f_clk=125M
wire [31:0] PINC_10M;
wire [31:0] PINC_5M;
assign PINC_10M=32'h147AE148; //10M对应的频率字
assign PINC_5M=32'hA3D70A4; //5M对应的频率字
wire [31:0] Signal_Freq10M;//10M的正弦波
wire [31:0] Signal_Freq5M; //5M的正弦波
wire Freq10M_vaild;
wire Freq5M_vaild;
// 输出10M的正弦波
dds_sin Inst_dds_sin_10M (
.aclk(clk), // input wire aclk
.s_axis_config_tvalid(1'b1), // input wire s_axis_config_tvalid
.s_axis_config_tdata(PINC_10M), // input wire [31 : 0] s_axis_config_tdata
.m_axis_data_tvalid(Freq10M_vaild ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (Signal_Freq10M), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata() // output wire [31 : 0] m_axis_phase_tdata
);
// 输出5M的正弦波
dds_sin Inst_dds_sin_5M (
.aclk(clk), // input wire aclk
.s_axis_config_tvalid(1'b1), // input wire s_axis_config_tvalid
.s_axis_config_tdata(PINC_5M), // input wire [31 : 0] s_axis_config_tdata
.m_axis_data_tvalid(Freq5M_vaild ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (Signal_Freq5M), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata() // output wire [31 : 0] m_axis_phase_tdata
);
// 信号截取
wire [15:0] Signal_Freq10M_16bit;//10M的正弦波
wire [15:0] Signal_Freq5M_16bit; //5M的正弦波
assign Signal_Freq10M_16bit=Signal_Freq10M[31:16];
assign Signal_Freq5M_16bit=Signal_Freq5M[31:16];
//-----------------两个正弦波信号叠加
// 为什么需要扩展1位
// 2个信号相加需要扩展1位,4个信号相加需要扩展2位,
wire [16:0] SignalMix_temp;
wire [15:0] SignalMix;
assign SignalMix_temp= {Signal_Freq5M_16bit[15] ,Signal_Freq5M_16bit } +
{Signal_Freq10M_16bit[15],Signal_Freq10M_16bit};
assign SignalMix= SignalMix_temp[16:1];
//add Inst_16add16 (
// .A(Signal_Freq10M_16bit), // input wire [15 : 0] A
// .B(Signal_Freq5M_16bit), // input wire [15 : 0] B
// .CLK(clk), // input wire CLK
// .S(SignalMix) // output wire [15 : 0] S
//);
//----信号带通滤波 通过系数重加载选择10M还是5M的信号通过
reg filter_config_tvalid ;// input
wire filter_config_tready ;// output
reg [7:0] filter_config_tdata ;// input
//output
wire [31:0] y;
wire y_vaild;
// 调用带通滤波器
fir_compiler_Freq1 Inst_bandpass (
.aclk(clk), // input wire aclk
.s_axis_data_tvalid(Freq10M_vaild && Freq5M_vaild), // input wire s_axis_data_tvalid
.s_axis_data_tready( ), // output wire s_axis_data_tready
.s_axis_data_tdata (SignalMix ), // input wire [15 : 0] s_axis_data_tdata
.s_axis_config_tvalid(filter_config_tvalid), // input wire s_axis_config_tvalid
.s_axis_config_tready(filter_config_tready), // output wire s_axis_config_tready
.s_axis_config_tdata (filter_config_tdata ), // input wire [7 : 0] s_axis_config_tdata
.m_axis_data_tvalid(y_vaild), // output wire m_axis_data_tvalid
.m_axis_data_tdata(y) // output wire [31 : 0] m_axis_data_tdata
);
wire [15:0] y_16bit;
assign y_16bit=y[31 : 16]; //截位
//-------s_axis_config配置
// 功能:通过控制filter_config_tvalid和filter_config_tdata,进而实现动态配置FIR的coe系数
always@(posedge clk)
begin
if(reset)
begin
filter_config_tvalid<=1'b0;
filter_config_tdata<=8'd0;
end
else if( filter_config_tready )//config通道准备好接收数据
begin
filter_config_tvalid<=1'b1;
case(Freq_Select)
2'd0: filter_config_tdata<=8'd0; //选择系数的组别
2'd1: filter_config_tdata<=8'd1;
default:
filter_config_tdata<=8'd0;
endcase
end
else
begin
filter_config_tvalid<=filter_config_tvalid;
filter_config_tdata<=filter_config_tdata;
end
end
endmodule
5.2 testbench
`timescale 1ns / 1ps
module sim_FIR_COEF_Reload;
reg clk ;
reg reset ;
reg [1:0] Freq_Select; // config信道上选择系数的组别
FIR_COEF_Reload Inst_FIR_COEF_Reload(
.clk (clk ) , //系统时钟 125M
.reset (reset ) , //复位
.Freq_Select (Freq_Select) // config信道上选择系数的组别
);
initial
begin
clk<=1'b0;
reset<=1'b1;
Freq_Select<=2'd0;
#20
reset<=1'b0;
#5000 //5us
Freq_Select<=2'd1;
end
always #4 clk=~clk;//T=8ns F_clk=125M
endmodule
5.3 结果
coe文件的第1组数据,允许5M的信号通过,所以当s_axi_config_tdata=0时,输出信号y的频率为5M。
coe文件的第2组数据,允许10M的信号通过,所以当s_axi_config_tdata=1时,输出信号y的频率为10M。
6 注意点
DDS和FIR的钟都是125M,所以生成的钟的频率必须为125M。
7 工程文件链接
工程文件
https://download.csdn.net/download/weixin_46136963/74135712