m基于FPGA的16QAM软解调verilog实现,含testbench

237 阅读3分钟

1.算法仿真效果

 

本系统进行了两个平台的开发,分别是:

 

Vivado2019.2

 

Quartusii18.0+ModelSim-Altera 6.6d  Starter Edition

 

其中Vivado2019.2仿真结果如下:

 

eb99a2011534dd1305420b1eedb32ec6_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.jpg   89f328b3a4844f60a32fbc92cc603a43_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.jpg

 Quartusii18.0+ModelSim-Altera 6.6d  Starter Edition的测试结果如下:

2d5bb58a110c6fd822762319fa8249d1_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.jpg

  774abe1eccaa011aa2ac912f21270129_watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=.jpg

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

        16QAM软解调是一种常用的数字调制解调技术,用于将接收到的16QAM调制的信号转换为原始数据。该技术结合了16种相位和振幅的调制方式,通过软判决算法对接收信号进行解调,16QAM软解调的系统原理是将接收到的16QAM调制信号转换为软判决结果,从而恢复原始数据。软解调是一种非硬判决的解调方法,它利用接收信号的采样值和相位信息来判断信号所处的调制状态,并对其进行解调。在16QAM软解调中,接收信号经过采样后,通过比较采样值和16个调制点的距离,选择最近的调制点作为解调结果。

 

       16QAM调制将每四个比特映射到一个复数点上,共有16种相位和振幅的调制方式。每个复数点对应一个调制符号,通过软解调,我们可以确定接收到的信号所对应的调制符号,进而推导出原始数据。

 

       设接收信号的采样值为rr,我们需要通过比较rr与16个调制点的距离,选择最近的调制点。

 

解调过程

以下是16QAM软解调的具体步骤:

 

步骤1:接收信号采样

 

接收信号经过抽样过程,得到采样值rr

 

步骤2:计算距离

 

计算采样值rr与每个调制点的距离did_i,其中i=1,2,...,16i=1,2,...,16。距离可以使用欧氏距离或其他度量方法进行计算。

 

步骤3:选择最近的调制点

 

选择与采样值rr距离最近的调制点,记为dmind_{\min},并记录其索引imini_{\min}

 

步骤4:软判决

 

根据索引imini_{\min},确定接收信号对应的调制符号。根据调制符号,可以推导出原始数据。

 

数学公式示例

以下是16QAM软解调的数学公式示例:

 

对于接收信号的采样值rr,与每个调制点的距离did_i可以计算为:

 

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

根据索引imini_{\min}可以确定接收信号对应的调制符号,并进一步推导出原始数据。

 

     实现16QAM软解调的难点在于选择合适的距离度量方法和判决阈值,以及在存在噪声的情况下进行准确的判决。此外,还需要解决调制点的映射问题,确保软解调能够准确还原原始数据。

 

       总结而言,16QAM软解调是一种通过比较采样值与调制点的距离,选择最近的调制点来解调接收信号的方法。通过软解调,可以恢复原始数据并实现高效的数据传输。

 

3.Verilog核心程序 ``timescale 1ns / 1ns

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[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_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_b1;

wire signed[15:0]o_b2;

wire signed[15:0]o_b3;

wire signed[15:0]o_b4;

wire signed[3:0]o_sdout;

tops_16QAM_demod  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_b1(o_b1),

   .o_b2(o_b2),

   .o_b3(o_b3),

   .o_b4(o_b4),

   .o_sdout(o_sdout)

   );  

   

 

initial begin

clk = 0;

rst = 0;

start = 1;

#10;

rst = 1;

end

always #5

clk <= ~clk;

integer fout1;

integer fout2;

initial begin

 fout1 = $fopen("II.txt","w");

 fout2 = $fopen("QQ.txt","w");

end

 

always @ (posedge clk)

 begin

     if(rst==1)

     begin

     $fwrite(fout1,"%d\n",I_com);

 $fwrite(fout2,"%d\n",Q_com);

 end

end

 

endmodule`