Vivado hilbert变换的实现
1 待解决的问题
1、如何生成希尔伯特滤波器IP核的系数;
2、希尔伯特滤波器的硬件如何实现;
2 实现流程
1、MATLAB产生希尔伯特滤波器的输入数据(正弦波信号);
2、将输入数据经过希尔伯特变换,把实信号变成复信号。
2.1 希尔伯特滤波器的输入数据生成
步骤:MATLAB产生一个正弦波------将正弦波导出为coe文件----将coe文件导入到ROM IP核中-----调用ROM IP,将该IP的输出作为希尔伯特滤波器的输入数据
具体而言:
1、coe文件的生成
close all;
clear all;
clc;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 参数定义
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
L=1024; % AD9238采样点数
ADC_bit=12; % 采样位数
fc=5e6; % 信号频率
fs=65e6; % 采样频率
% L=1920; % 采样点数
yinzi=100; % 缩减因子,避免出现 D 必须为小于 flintmax 的非负整数。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 产生信号
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
t=0:1/fs:(L-1)/fs;
st=sin(2*pi*fc*t);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 信号处理
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
y=st/yinzi; % 估计信号幅度,不能归一化来解决
yt=round(y*(2^(ADC_bit-1)-1)); % 12bit量化
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 绘图
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure(1);
plot(st);hold on;
title('原信号');
figure(2);
plot(y,'-r');hold on;
legend('缩减后的信号');
figure(3);
plot(yt);hold on;
legend('量化后的信号');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 信号幅度估计
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ST_FFT=fftshift(fft(st)); % 傅里叶变换
P_ST=abs(ST_FFT)/L; % 幅度谱
u_st=max(P_ST); % 得到波束1接收到的信号的幅度值
fprintf('u_st信号的幅度值为%g\n',u_st);
Y_FFT=fft(y,L); % 傅里叶变换
P_Y=abs(Y_FFT)/L; % 幅度谱
u_y=max(P_Y); % 得到波束1接收到的信号的幅度值
fprintf('u_y信号的幅度值为%g\n',u_y);
YT_FFT=fft(yt,L); % 傅里叶变换
P_YT=abs(YT_FFT)/L; % 幅度谱
u_yt=max(P_YT); % 得到波束1接收到的信号的幅度值
fprintf('u_yt信号的幅度值为%g\n',u_yt);
AM=(u_st/yinzi)*(2^(ADC_bit-1)-1)/u_yt; % 扩大倍数
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB生成coe文件
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 在.coe文件中
% 第一行为定义数据格式, 2代表 ROM 的数据格式为二进制。
% 从第 3 行开始到第最后一行,是这个 L(数据长度为1024)* ADC_bit(16bit) 大小 ROM 的初始化数据。
% 第一行到倒数第二行的数字后面用逗号,最后一行数字结束用分号。
fid=fopen('data_in.coe','w'); % w表示write
% fid=fopen('data.txt','w'); % w表示write
fprintf(fid,'Memory_Initialization_Radix = 2;\r\n'); % 二进制
fprintf(fid,'Memory_Initialization_Vector = \r\n');
for p=1:L
B_s=dec2bin(yt(p)+(yt(p)<0)*2^ADC_bit,ADC_bit);
for q=1:ADC_bit % 12位,依次判断这12位的数值
if B_s(q)=='1'
data=1;
else
data=0;
end
fprintf(fid,'%d',data);
end
% 下面if语句的目的
% 每行数字后面用逗号(,),最后一行数字结束用分号(;)
if (p<L)
fprintf(fid,',\r\n');
else
fprintf(fid,';\r\n'); % 分号(;) 结束标志位
end
end
fclose(fid);
2、将coe文件导入到ROM IP核中
如何MATLAB生成的数据导入到FPGA,ROM IP实现 具体见该博客的2.1节
2.2 生成希尔伯特滤波器IP核的系数文件
需要注意的是,matlab生成的系数文件有一定的要求。必须保证相邻非零系数之间有一个0。
2.2.1 生成hilbert滤波器的系数,即生成系数coe文件
1、打开MATLAB的FDATOOL,设置好参数,并生成滤波器。如下图所示
2、导出滤波器系数,用数组h_hilbert表示。并在MATLAB中,将系数生成coe文件,实现代码如下:
close all;
clear all;
clc;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 参数定义
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Quantify_bit=16; % 希尔伯特滤波器量化位数 16位
fc=10e6; % 信号频率
fs=65e6; % 采样频率
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 希尔伯特滤波器
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 50阶
h_hilbert=[-0.00590097650222754,9.43634831392954e-16,-0.00592861323210342,-2.35672047624096e-16,-0.00882355094551652,1.88156326605263e-18,-0.0125967335950592,-8.81824807467578e-16,-0.0174619206426258,1.47113177594992e-15,-0.0237310276515661,-5.39946714016346e-16,-0.0318877221102664,2.65287762614106e-16,-0.0427583109535232,-5.89104004757738e-18,-0.0578928531993323,3.13510365619452e-16,-0.0806543322511701,-4.84766911383691e-16,-0.119801339972733,1.88465096830876e-16,-0.207626768075381,-1.51969570132042e-16,-0.635083803394948,0,0.635083803394948,1.51969570132042e-16,0.207626768075381,-1.88465096830876e-16,0.119801339972733,4.84766911383691e-16,0.0806543322511701,-3.13510365619452e-16,0.0578928531993323,5.89104004757738e-18,0.0427583109535232,-2.65287762614106e-16,0.0318877221102664,5.39946714016346e-16,0.0237310276515661,-1.47113177594992e-15,0.0174619206426258,8.81824807467578e-16,0.0125967335950592,-1.88156326605263e-18,0.00882355094551652,2.35672047624096e-16,0.00592861323210342,-9.43634831392954e-16,0.00590097650222754];
L=length(h_hilbert);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB生成coe文件
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 在.coe文件中
% 第一行为定义数据格式, 2代表 ROM 的数据格式为二进制。
% 从第 3 行开始yong到第最后一行,是这个 L(数据长度为1024)* ADC_bit(16bit) 大小 ROM 的初始化数据。
% 第一行到倒数第二行的数字后面用逗号,最后一行数字结束用分号。
yt=round(h_hilbert*(2^(Quantify_bit-1)-1)); % 12bit量化
fid=fopen('fir_hilbert_50order.coe','w'); % w表示write
fprintf(fid,'Radix = 10;\r\n'); % 10进制
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);
AM=yt./h_hilbert;
% plot(AM);
plot( AM );
3、打开coe文件,观察系数规律。可以看出,0在每相邻的系数之间。
4、根据Xilinx的pg149文档的图3-22,可以看出,希尔伯特滤波器的设计是正确的。
2.2.2 调用FIR IP核
1、在ip目录搜索FIR
2、设置FIR滤波器参数,设置如下
注意点:在FIR IP的implementation一栏,coefficient Width=16,如上图所示。这个值是根据在生成希尔伯特滤波器的系数的coe文件时,有一个参数,即希尔伯特滤波器量化位数Quantify_bit。该值在MATLAB仿真中设置的是16,所以coefficient Width=16。
2.3 顶层模块
2.3.1 新建源文件,编写源文件
`timescale 1ns / 1ps
/* 实现流程:
1、MATLAB产生希尔伯特滤波器的输入数据(ROM IP);
2、将输入数据变成复信号,输出数据的实部和虚部(FIR IP)。
*/
module top(
input sys_clk, //50MHz时钟
input rst_n //复位,低电平有效
);
/*
模块功能:利用ROM IP产生输入信号
*/
wire [11:0] rom_data1; //ROM读出数据
reg [9:0] rom_addr1; //ROM输入地址
//产生ROM地址读取数据
always @ (posedge sys_clk or negedge rst_n)
begin
if(!rst_n)
rom_addr1 <= 10'd0;
else
rom_addr1 <= rom_addr1+1'b1;
end
//实例化ROM
rom_ip rom_ip_inst (
.clka(sys_clk), // input wire clka
.addra(rom_addr1), // input wire [9 : 0] addra
.douta(rom_data1) // output wire [11 : 0] douta
);
/*
模块功能:希尔伯特变换
*/
wire [11:0] real_data1;
wire [11:0] imag_data1;
v_hilbert v_hilbert_inat(
.sys_clk (sys_clk ) ,
.rom_data1 (rom_data1 ) ,
.real_data1(real_data1) ,
.imag_data1(imag_data1)
);
/*
模块功能:ila波形观测
*/
ila_0 ila_0_inst (
.clk(sys_clk), // input wire clk
.probe0(rom_addr1), // input wire [9:0] probe0
.probe1(rom_data1), // input wire [11:0] probe1
.probe2(real_data1), // input wire [11:0] probe2
.probe3(imag_data1) // input wire [11:0] probe3
);
endmodule
2.3.2 编写v_hilbert源文件
`timescale 1ns / 1ps
module v_hilbert(
input sys_clk ,//input
input [11:0] rom_data1 ,
output [11:0] real_data1 ,//output
output [11:0] imag_data1
);
// 在FIR IP的implementation一栏,coefficient Width=16,
// 这个值是根据在生成希尔伯特滤波器的系数的coe文件时,
// 有一个参数,即希尔伯特滤波器量化位数Quantify_bit。
// 该值在MATLAB仿真中设置的是16,所以coefficient Width=16。
// 所以滤波器的输入值dataInputTemp1的位宽也为16,
wire [16-1:0] dataInputTemp1;
assign dataInputTemp1 = {rom_data1[11],rom_data1[11],rom_data1[11],rom_data1[11], rom_data1};//将12位扩展为16位
wire m_axis_data_tvalid;
wire [47:0] m_axis_data_tdata1;
fir_hilbert fir_hilbert_inst (
.aclk (sys_clk ), // input wire aclk
.s_axis_data_tvalid (1 ), // input wire s_axis_data_tvalid
.s_axis_data_tready ( ), // output wire s_axis_data_tready
.s_axis_data_tdata (dataInputTemp1 ), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_axis_data_tdata1 ) // output wire [47 : 0] m_axis_data_tdata
);
//assign real_data = m_axis_data_tdata[15:0];
//assign imag_data = m_axis_data_tdata[46:31];
assign real_data1 = m_axis_data_tdata1[11:0];
assign imag_data1 = m_axis_data_tdata1[42:31];
endmodule
2.3.3 新建约束文件,编写约束文件
############## clock and reset define##################
create_clock -period 20 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_clk}]
set_property PACKAGE_PIN U18 [get_ports {sys_clk}]
set_property IOSTANDARD LVCMOS33 [get_ports {rst_n}]
set_property PACKAGE_PIN N15 [get_ports {rst_n}]
2.3.4 结构示意图
3 ILA结果
1、设置触发条件
2、结果
可以看出,希尔伯特变换后的实部和原信号一样;虚部与原信号相差90度。说明希尔伯特变换成功。