本文链接:https://blog.csdn.net/qq_46621272/article/details/125334644
FIR 基础应用 - AM 调幅波调制解调(FIR 低通滤波)
这是 XILINX FIR IP 详解、Verilog 源码、Vivado 工程 这篇文章的实验部分,用 FIR 低通滤波实现了调幅波的解调输出。
采用 Xilinx vivado 2017.4 版本

//am_modulation_dds.v
module am_modulation_dds
(
output m_axis_data_tvalid,
input m_axis_data_tready,
output [15:0] m_axis_data_tdata,
input rst_n,
input clk
);
wire signed [7:0] dds_100khz_tdata_i; // 100KHz 正弦波 AM 载波
wire dds_100khz_tvalid_i;
wire dds_100khz_tready_i;
wire signed [7:0] dds_4khz_tdata_i; // 4khz 正弦波 AM 调制信号
wire dds_4khz_tvalid_i;
wire dds_4khz_tready_i;
reg signed [15:0] am_tdata_r;
reg am_tvalid_r;
wire am_tready_i;
assign am_tready_i = m_axis_data_tready;
assign dds_100khz_tready_i = am_tready_i;
assign dds_4khz_tready_i = am_tready_i;
assign m_axis_data_tvalid = am_tvalid_r;
assign m_axis_data_tdata = am_tdata_r;
always @(posedge clk) //AM 调制算法实现
begin
if(rst_n == 0 )
begin
am_tdata_r <= 0;
am_tvalid_r <= 0;
end
else if(am_tready_i == 1)
begin
am_tdata_r <= dds_100khz_tdata_i * (dds_4khz_tdata_i/2 + 128); // 128 是直流分量,式中的除2是为了不使数据超过16位溢出
// 这个代码中,载波频率很低,就直接用乘法去写代码了。
// 如果载波频率比较高就需要用DSP单元或乘法 IP 去实现。
am_tvalid_r <= dds_4khz_tvalid_i & dds_100khz_tvalid_i;
end
end
dds_compiler_1m_100k dds1 // XILINX VIVADO DDS IP,1MHz 时钟输入,100KHz正弦波 8 位输出
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (dds_100khz_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (dds_100khz_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (dds_100khz_tdata_i) // output wire [7 : 0] m_axis_data_tdata
);
dds_compiler_1m_4k dds2 // XILINX VIVADO DDS IP,1MHz 时钟输入,4khz正弦波 8 位输出
(
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (dds_4khz_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (dds_4khz_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (dds_4khz_tdata_i) // output wire [7 : 0] m_axis_data_tdata
);
endmodule

//am_demodulation_fir.v
module am_demodulation_fir
(
input rst_n,
input clk,
input s_axis_data_tvalid,
output s_axis_data_tready,
input signed[15:0] s_axis_data_tdata,
output m_axis_data_tvalid,
input m_axis_data_tready,
output signed[15:0] m_axis_data_tdata
);
reg [15:0] abs_data_r = 0;
reg abs_valid_r = 0;
wire abs_tready_i;
always @(posedge clk)
begin
if(rst_n == 0 )
abs_valid_r <= 0;
else if(abs_tready_i == 1)
abs_valid_r <= s_axis_data_tvalid;
end
always @(posedge clk) //取绝对值
begin
if(rst_n == 0 )
abs_data_r <= 0;
else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
begin
if(s_axis_data_tdata >= 0)
abs_data_r <= s_axis_data_tdata;
else
abs_data_r <= -s_axis_data_tdata;
end
end
wire signed [39:0] fir_fm_tdata_i;
wire fir_fm_tvalid_i;
wire fir_fm_tready_i;
assign fir_fm_tready_i = m_axis_data_tready;
assign m_axis_data_tdata = fir_fm_tdata_i >>>19;
assign m_axis_data_tvalid = fir_fm_tvalid_i;
assign s_axis_data_tready = abs_tready_i;
fir_compiler_lowpass_10k_30k_1m am_fir_u1
(
.aresetn (rst_n), // input wire aresetn
.aclk (clk), // input wire aclk
.s_axis_data_tvalid (abs_valid_r), // input wire s_axis_data_tvalid
.s_axis_data_tready (abs_tready_i), // output wire s_axis_data_tready
.s_axis_data_tdata (abs_data_r), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_fm_tvalid_i), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_fm_tready_i), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_fm_tdata_i) // output wire [39 : 0] m_axis_data_tdata
);
endmodule
///////////////////////////////////////////////////////////////////////
`timescale 1ns / 100ps
//am_modem_fir_testbench.v
module am_modem_fir_testbench;
reg rst_n;
reg clk;
parameter CLK_PERIOD = 1000; //1MHz
initial begin
rst_n = 0;
#(20 * CLK_PERIOD)
rst_n = 1;
#(3000 * CLK_PERIOD)
$stop;
end
initial
clk = 0;
always
begin
clk = #(CLK_PERIOD/2.0) ~clk;
end
wire signed [15:0] am_mod_tdata; //调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
wire am_mod_tvalid;
wire am_mod_tready;
wire signed [15:0] am_demod_tdata; //经过解调还原的 4KHz 正弦波
wire am_demod_tvalid;
wire am_demod_tready=1;
am_modulation_dds am_u1 //调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.m_axis_data_tdata (am_mod_tdata), //调幅波数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_mod_tvalid),
.m_axis_data_tready (am_mod_tready)
);
am_demodulation_fir am_u2 //调幅波解调模块,将调幅波解调还原调制信号
(
.clk (clk), //1MHz
.rst_n (rst_n), //复位
.s_axis_data_tdata (am_mod_tdata), //调幅信号输入 intput wire [16 : 0]
.s_axis_data_tvalid (am_mod_tvalid),
.s_axis_data_tready (am_mod_tready),
.m_axis_data_tdata (am_demod_tdata), //调幅波解调数据输出, output wire [16 : 0]
.m_axis_data_tvalid (am_demod_tvalid),
.m_axis_data_tready (am_demod_tready)
);
endmodule
; XILINX CORE Generator(tm)Distributed Arithmetic FIR filter coefficient (.COE) File
; Generated by MATLAB(R) 9.7 and DSP System Toolbox 9.9.
; Generated on: 17-Jun-2022 13:49:47
Radix = 16;
Coefficient_Width = 16;
CoefData =
fd36,fed1,fe98,fe5f,fe27,fdf3,fdc4,fd9c,fd80,fd72,fd74,fd8a,fdb8,fe00,fe67,feed,
ff99,006b,0166,028d,03e0,0561,0711,08ef,0afb,0d34,0f98,1224,14d5,17a7,1a94,1d9a,
20b0,23d2,26f9,2a1d,2d37,3041,3333,3604,38af,3b2d,3d75,3f84,4152,42db,441b,450e,
45b1,4603,4603,45b1,450e,441b,42db,4152,3f84,3d75,3b2d,38af,3604,3333,3041,2d37,
2a1d,26f9,23d2,20b0,1d9a,1a94,17a7,14d5,1224,0f98,0d34,0afb,08ef,0711,0561,03e0,
028d,0166,006b,ff99,feed,fe67,fe00,fdb8,fd8a,fd74,fd72,fd80,fd9c,fdc4,fdf3,fe27,
fe5f,fe98,fed1,fd36;








dds_compiler_1m_4k 与 dds_compiler_1m_100k 设置基本一致,这里只贴了一处不一样的设置。




