1.演算法模擬效果
vivado2019.2模擬結果如下(完整程式碼執行後無水印):
設定SNR=8db
設定SNR=12db
和之前開發的普通16QAM調製解調系統相比,軟解調誤位元速率更低。
基於FPGA的16QAM基帶通訊系統,包含testbench,高斯通道模組,誤位元速率統計模組,可以設定不同SNR_基於fpga的實時套刻誤差測量系統的設計與實現-CSDN部落格
模擬操作步驟可參考程式配套的操作影片。
2.演算法涉及理論知識概要
16QAM軟解調是一種常用的數字調製解調技術,用於將接收到的16QAM調製的訊號轉換為原始資料。該技術結合了16種相位和振幅的調製方式,透過軟判決演算法對接收訊號進行解調,16QAM軟解調的系統原理是將接收到的16QAM調製訊號轉換為軟判決結果,從而恢復原始資料。軟解調是一種非硬判決的解調方法,它利用接收訊號的取樣值和相位資訊來判斷訊號所處的調製狀態,並對其進行解調。在16QAM軟解調中,接收訊號經過取樣後,透過比較取樣值和16個調製點的距離,選擇最近的調製點作為解調結果。
16QAM調製將每四個位元對映到一個複數點上,共有16種相位和振幅的調製方式。每個複數點對應一個調製符號,透過軟解調,我們可以確定接收到的訊號所對應的調製符號,進而推匯出原始資料。
設接收訊號的取樣值為$r$,我們需要透過比較$r$與16個調製點的距離,選擇最近的調製點。
以下是16QAM軟解調的具體步驟:
步驟1:接收訊號取樣
接收訊號經過抽樣過程,得到取樣值$r$。
步驟2:計算距離
計算取樣值$r$與每個調製點的距離$d_i$,其中$i=1,2,...,16$。距離可以使用歐氏距離或其他度量方法進行計算。
步驟3:選擇最近的調製點
選擇與取樣值$r$距離最近的調製點,記為$d_{\min}$,並記錄其索引$i_{\min}$。
步驟4:軟判決
根據索引$i_{\min}$,確定接收訊號對應的調製符號。根據調製符號,可以推匯出原始資料。
數學公式示例
以下是16QAM軟解調的數學公式示例:
對於接收訊號的取樣值$r$,與每個調製點的距離$d_i$可以計算為:
根據索引$i_{\min}$可以確定接收訊號對應的調製符號,並進一步推匯出原始資料。
實現16QAM軟解調的難點在於選擇合適的距離度量方法和判決閾值,以及在存在噪聲的情況下進行準確的判決。此外,還需要解決調製點的對映問題,確保軟解調能夠準確還原原始資料。 總結而言,16QAM軟解調是一種透過比較取樣值與調製點的距離,選擇最近的調製點來解調接收訊號的方法。透過軟解調,可以恢復原始資料並實現高效的資料傳輸。
3.verilog核心程式
// DUT tops_16QAM_mod top( .clk(clk), .rst(rst), .start(start), .parallel_data(parallel_data), .sin(sin), .cos(cos), .I_com(), .Q_com(), .I_comcos(I_com),//基帶方式輸出,即實際通訊中的複數模式 .Q_comsin(Q_com) ); //加入通道 //實部 awgns awgns_u1( .i_clk(clk), .i_rst(~rst), .i_SNR(i_SNR), //這個地方可以設定訊雜比,數值大小從-10~50, .i_din(I_com), .o_noise(), .o_dout(I_Ncom) ); //虛部 awgns awgns_u2( .i_clk(clk), .i_rst(~rst), .i_SNR(i_SNR), //這個地方可以設定訊雜比,數值大小從-10~50, .i_din(Q_com), .o_noise(), .o_dout(Q_Ncom) ); wire signed[15:0]o_b1; wire signed[15:0]o_b2; wire signed[15:0]o_b3; wire signed[15:0]o_b4; tops_16QAM_demod top2( .clk(clk), .rst(rst), .start(start), .I_Ncom(I_Ncom), .Q_Ncom(Q_Ncom), .I_comcos2(I_comcos2), .Q_comsin2(Q_comsin2), .o_Ifir(o_Ifir), .o_Qfir(o_Qfir), .o_b1(), .o_b2(), .o_b3(), .o_b4(), .o_sdout(o_sdout) ); //4個bit同時統計誤位元速率 wire signed[31:0]o_error_num1; wire signed[31:0]o_total_num1; Error_Chech Error_Chech_u1( .i_clk(clk), .i_rst(~rst), .i_trans(parallel_data), .i_rec(o_sdout), .o_error_num(o_error_num1), .o_total_num(o_total_num1) ); assign o_total_num = o_total_num1; assign o_error_num = o_error_num1; endmodule 0sj_020m