一、說明:
- 功能:AM解調
- 平台:Vivado 2016.4 和 Matlab R2017a
二、原理:
1.AM解調原理
- 模擬電路中采用“包絡檢波”的方法:
- **數字電路中采用類似的方法: **
先將已調信號取絕對值,再經過低通濾波器,濾除高頻分量(經AM調制的信號包含兩個高頻分量:載波頻率+/-調制信號頻率,因此低通濾波器的截止頻率小於兩個高頻分量就可以),得到的就是疊加了直流分量的調制信號,去直流后便可以得到調制信號。
三、AM解調的FPGA實現
1.將已調制的AM信號取絕對值
關於AM信號的產生,參見上一篇博客: AM調制的FPGA實現
簡單說明一下對數據取反的思路:如果是無符號數,則不存在符號位,也就是說數據都是正數,不需要取絕對值;如果是有符號數,通過檢測最高位的符號位,如果符號位是1,則表示數據是負數,對數據取反,如果符號位是0,則表示數據是正數,不需要取反操作。
- 取絕對值的Verilog實現:
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
data_tdata <= 0;
end
else if(AM_mod[15] == 1) begin
data_tdata <= -{AM_mod}; //如果符號位是1,對數據取反
end
else if(AM_mod[15] == 0) begin
data_tdata <= AM_mod; //如果符號位是0,數據不變
end
else begin
data_tdata <= data_tdata;
end
end
2.使用FIR濾波器濾除高頻分量
關於Vivado的FIR IP核可以說是功能很強大的,但這里不需要其他復雜的功能,只需要簡單的生成一個的低通濾波器就行了。
類似於ROM核的生成,配置FIR同樣需要Matlab配合。可見,Matlab的功能是多么強大。這里Matlab的主要作用是對濾波器的性能進行仿真並生成相應的抽頭系數。
-
使用Matlab生成FIR的抽頭系數
在Matlab的命令行窗口輸入:filterDesigner(以前是用fdatool命令,不過輸入fdatool也可以,只是會提醒你改用新的命令)彈出濾波器設計窗口:
接下來,對濾波器的一些參數進行設置:
參數設置好后,點擊Design Filter 按鈕查看生成濾波器的幅頻響應圖,通過幅頻響應等圖來判斷濾波器是否達到設計要求:
設計的濾波器滿足性能指標后需要將抽頭系數導出,保存為.coe文件。在導出前需要對系數進行量化。因為需要解調的AM信號也是16位寬,所以這里的位寬設置保持默認值,這些可以根據實際情況自行修改。
量化過后就能將抽頭系數導出為.coe文件了:
-
生成FIR IP核
IP核的具體配置如下:
其他保持默認即可:
同樣,在IP核配置界面也可以查看濾波器的幅頻特性:
IP核生成完畢后,就可以編寫IP核的調用模塊了。
- FIR IP核調用模塊:
module FIR_Control(
input clk,
input rst_n,
input signed [15:0] s_axis_data_tdata,
output reg [7:0] data_out
);
wire s_axis_data_tready;
wire m_axis_data_tvalid;
wire [39:0] m_axis_data_tdata; //濾波器輸出信號
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
data_out <= 0;
end
else begin
data_out <= m_axis_data_tdata[33:26]; //根據仿真結果進行截位
end
end
//--------------調用FIR核----------------//
FIR FIR_inst0(
.aclk (clk),
.s_axis_data_tvalid (1), //拉高時IP核開始工作
.s_axis_data_tready (s_axis_data_tready),
.s_axis_data_tdata (s_axis_data_tdata), //輸入信號
.m_axis_data_tvalid (m_axis_data_tvalid), //拉高時表明數據輸出有效
.m_axis_data_tdata (m_axis_data_tdata) //輸出信號
);
//---------------------------------------//
endmodule
需要注意的是:
m_axis_data_tdata 信號是濾波器的數據輸出信號,我們在使用時一般都要對此數據進行截位操作,如何進行截位需要根據仿真結果來確定。比如,在這個工程中,我需要的濾波器的輸出數據是8位,但不能一下子截取高8位,而且m_axis_data_tdata是個40位的數據,從仿真波形來看m_axis_data_tdata[39:34]都是符號位,因此從33位開始往下截取8位數據(當然也可以從34位開始截,這樣的話就多了一位符號位,相應的數據位就變少了一位)。
3.去直流處理
經過FIR濾波后的波形其實就是一個疊加了直流分量的調制信號。在本工程中,AM調制是100%調制,也就是說解調時經過FIR后的信號的最小值為0,可以把它看作是無符號的數,直接經DA輸出就行了。
如果不是100%調制呢?也就是說解調時經過FIR后的信號的最小值是大於0的,那么這個大於0的量就相當於直流,需要去掉后再經DA輸出。
因此,在這個工程中,不需要去直流處理。下面給出頂層文件的代碼。
- 頂層模塊編寫:
module TOP(
input clk,
input rst_n,
output [7:0] AM_demod
);
//--------------------------------//
reg signed [15:0] data_tdata;
wire signed [15:0] AM_mod;
//--------------------------------//
//-----------取絕對值-------------//
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
data_tdata <= 0;
end
else if(AM_mod[15] == 1) begin
data_tdata <= -{AM_mod}; //如果符號位是1,對數據取反
end
else if(AM_mod[15] == 0) begin
data_tdata <= AM_mod; //如果符號位是0,數據不變
end
else begin
data_tdata <= data_tdata;
end
end
//--------------------------------//
//-----------AM已調信號------------//
modulate modulate_inst0(
.clk (clk),
.rst_n (rst_n),
.AM_mod (AM_mod)
);
//--------------------------------//
//----------濾波器控制模塊---------//
FIR_Control FIR_Control_inst2(
.clk (clk),
.rst_n (rst_n),
.s_axis_data_tdata (data_tdata),
.data_out (AM_demod)
);
//--------------------------------//
endmodule
4.解調仿真
- 編寫TestBeach:
`timescale 1ns/1ps
module tb_AM();
//===================解調部分====================//
//----------接口設置----------//
reg sclk;
reg rst_n;
wire [7:0] AM_demod;
//--------------------------//
initial sclk = 1;
always #5 sclk = ~sclk; //100M時鍾
initial begin
rst_n = 0;
#500
rst_n = 1;
end
//----------解調模塊----------//
TOP TOP_inst(
.clk (sclk),
.rst_n (rst_n),
.AM_demod (AM_demod)
);
//---------------------------//
endmodule
- 仿真結果
由仿真結果可知,最終輸出信號正確還原了已調制信號的包絡,表明解調正確。