m基于FPGA的带相位偏差16QAM调制信号相位估计和补偿算法verilog实现

284 阅读3分钟

1.算法仿真效果

本系统进行了Vivado2019.2平台的开发,Vivado2019.2仿真结果如下:

40febc835e72e3ed0acb1a8ef749b908_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

9b607bfc01234a44d8d835dd3431a3c5_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png  

将FPGA的仿真结果导入到matlab显示星座图。

 

cc46b2e096615c572b428fbaef05b60f_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

896e69571ff98985ab68493b8a4200b1_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png  

2.算法涉及理论知识概要

       从以下几个方面进行介绍:16QAM调制信号的基本原理、相位偏差的处理方法、VV算法的原理和实现步骤等。

 

2.1. 16QAM调制信号的基本原理

     16QAM调制是一种常见的数字调制方式,其将四个二进制比特映射到一个复平面上的16个点,如图1所示。16QAM调制信号可以表示为:

 

3c92c8c1c0170fbdc0af076149d5f3d2_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png  

       其中,AcA_c是载波幅度,ana_n是二进制比特,p(t)p(t)是脉冲成形滤波器,TT是符号间隔,fcf_c是载波频率,ϕn\phi_n是相位。

 

图1. 16QAM调制信号映射图

 

 

2.2. 相位偏差的处理方法

 

      在实际应用中,16QAM调制信号的相位可能会受到多种因素的影响,如噪声、多径衰落等,从而导致信号存在相位偏差。为了保证信号的正确解调,需要对信号进行相位估计和补偿。

 

相位估计和补偿的一般流程包括以下几个步骤:

 

选择合适的相位参考信号,例如载波信号或训练序列等。

 

提取接收信号的相位信息,例如使用差分解调器提取相位差等。

 

        对相位信息进行滤波和处理,例如使用低通滤波器平滑相位信息,使用PLL等算法进行相位跟踪等。

 

根据估计得到的相位信息,对信号进行相位补偿,以消除相位偏差。

 

2.3. VV算法的原理和实现步骤

 

       VV算法是一种基于相位差的相位估计算法,它可以对16QAM调制信号的相位进行高精度的估计和补偿。VV算法的原理如下:

 

将16QAM调制信号分为实部和虚部两路,分别进行差分解调,得到相位差Δϕ\Delta\phi

 

对相位差进行累积,并进行非线性处理,得到相位估计值。

 

根据相位估计值,对信号进行相位补偿。

 

VV算法的实现步骤如下:

 

对接收信号进行采样和定时,并进行载波恢复,得到16QAM调制信号的实部和虚部。

 

对实部和虚部分别进行差分解调,得到相位差Δϕ\Delta\phi

 

a8868d34643ef452ec368add60148d99_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.png

 

        最后,将补偿后的信号进行解调和解码,得到原始的二进制比特流。需要注意的是,VV算法的实现需要使用高精度的浮点运算,因此需要使用FPGA等硬件加速器来实现。在实现过程中,需要根据具体的硬件平台和信号特性进行优化,以达到较高的运算速度和较低的资源消耗。

 

3.Verilog核心程序 `module TEST;

 

reg clk;

reg rst;

reg start;

 

    wire  [3:0] parallel_data;

    wire [15:0]sin;

    wire [15:0]cos;

wire signed[19:0]  I_com;

wire signed[19:0]  Q_com;

wire signed[19:0]  I_com2;

wire signed[19:0]  Q_com2;

    wire signed[15:0]I_comcos;

    wire signed[15:0]Q_comsin;

 

 

// DUT

tops_16QAM_mod  top(

   .clk(clk),

   .rst(rst),

   .start(start),

   .parallel_data(parallel_data),

   .sin(sin),

   .cos(cos),

   .I_com(I_com),

   .Q_com(Q_com),

   .I_com2(I_com2),

   .Q_com2(Q_com2),

   .I_comcos(I_comcos),

   .Q_comsin(Q_comsin)

   );

   

   

wire signed[23:0]I_comcos2;

wire signed[23:0]Q_comsin2;

wire signed[7:0]o_Ifir;

wire signed[7:0]o_Qfir;

wire signed[15:0]o_Ifir_phase;

wire signed[15:0]o_Qfir_phase;

wire signed[31:0]o_phase;

tops_16QAM_phase_est  top2(

   .clk(clk),

   .rst(rst),

   .start(start),

   .I_comcos(I_comcos),

   .Q_comsin(Q_comsin),

   .I_comcos2(I_comcos2),

   .Q_comsin2(Q_comsin2),

   .o_Ifir(o_Ifir),

   .o_Qfir(o_Qfir),

   .o_I_phase(o_Ifir_phase),

   .o_Q_phase(o_Qfir_phase),

   .o_phase(o_phase)

   );  

   

 

initial begin

clk = 0;

rst = 0;

start = 1;

#10;

rst = 1;

end

always #5

clk <= ~clk;

reg writeen;

initial

begin

    writeen = 1'b0;

    #150000

    writeen = 1'b1;

end`