一、概述
本文先简要介绍了频率调制(frequency modulation,FM,简称调频)的原理,然后对其进行方案设计,最后基于 VIVADO 2018.3 使用 Verilog 进行实现。
二、FM 原理
角度调制(angle modulation)是已调波的总相角 随着基带信号 作某种变化的调制方式,它包括频率调制和相位调制。一般而言,角调信号的表达式为:
其中, 称为相角,它是随 变化的。
频率调制(frequency modulation,FM,简称调频)的调制表达式可以下式表示:
其中, 称为频偏常数,单位 Hz/V。
三、参数设计
(1)调制参数
时钟频率:1 MHz
调制信号:4 kHz 正弦波
载波频率:100 kHz
(2)解调参数
解调参数主要是包络检波(低通滤波)器的参数配置,我们使用 Matlab 中的 filterDesigner 进行设计。滤波器可以选择等波纹的 FIR 低通滤波器,采样率设置为 1000 kHz,通带截止频率 10 kHz,阻带截止频率 30 kHz。
设计好后点击左侧边栏第三个框进行量化,选择定点模式,最后点击上方的 “ 目标 ” 生成 .coe 文件。
四、IP 核参数配置
(1)调制信号发生器
调制信号使用 DDS IP 核产生正弦波数据,Configuration Option 选择 “ Phase Generator and SIN COS LUT ”,输入时钟设置 1 MHz,如下图所示。
由于调制信号的频率已固定为 4 kHz,因此这里的频率控制字(Phase Increment Programmabilit,相位增量可编程性)选择为 Fixed;相位控制字(Phase Offset Programmability,相位偏移可编程性)选择为 None;输出信号选择正弦波(Sine)。
点击 Next 进入下一页配置,选上 Output TREADY 和 ARESETn。
然后在输出频率处选择 4 kHz,即 0.004 MHz。
最后 Generate IP 即可。
(2)已调信号发生器
已调 FM 信号也用 DDS IP 核产生,Configuration Option 选择 “ SIN COS LUT only ”,其余默认,如下图所示。
进入下一页后选择输出模式为正弦波(Sine)。
再进入下一页,将 Output TREADY 和 ARESETn 选上。
(3)低通滤波器
采用包络检波法进行解调,我们通过 FIR IP 核(FIR Compiler)来实现低通滤波提取包络信息。在 IP 核中选择导入 COE File 的模式,并在下方的 “ Coefficient File ” 处导入 .coe 文件。
下面三页的 Channel Specification、Implementation 和 Detail Implementation 均保存默认参数。
在最后的 Inerface 页面上,勾选上 Output TREADY 和 ARESETn。
五、代码设计
(1)顶层代码
顶层代码对调制和解调两大模块进行连线,这里是以直连线代替了无线信道。其中,调制模块中所需的相位控制字 POFF 也可由顶层进行参数配置,以满足用户的不同需求。
`timescale 1ns / 1ps
//
// Company: UESTC
// Engineer: chylinne
//
// Create Date: 2022/08/15 14:17:30
// Design Name: fm
// Module Name: fm_top
// Project Name: fm
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fm_top # (
/* Phase Offset Programmability
poff = 2^N * f_carrier
= 2^16 * 100 kHz
= 2^16 * 0.1 MHz
= 6554
*/
parameter POFF = 'd6554 //100KHz
)(
input rst_n,
input clk
);
wire signed [15:0] fm_mod_data;
wire fm_mod_valid;
wire fm_mod_ready;
wire signed [15:0] fm_demod_data;
wire fm_demod_valid;
wire fm_demod_ready = 1'b1;
fm_modulation # (
.POFF(POFF)
) u_fm_modulation (
.clk(clk),
.rst_n(rst_n),
.fm_mod_data(fm_mod_data),
.fm_mod_valid(fm_mod_valid),
.fm_mod_ready(fm_mod_ready)
);
fm_demodulation u_fm_demodulation (
.clk(clk),
.rst_n(rst_n),
.fm_mod_data(fm_mod_data),
.fm_mod_valid(fm_mod_valid),
.fm_mod_ready(fm_mod_ready),
.fm_demod_data(fm_demod_data),
.fm_demod_valid(fm_demod_valid),
.fm_demod_ready(fm_demod_ready)
);
endmodule
(2)调制模块
调制模块较简单,通过调用 2 个 DDS IP 核实现调制信号(正弦波)和已调信号(FM 信号)的产生,重点在于需要通过相位计数器和相位控制字来计算出正弦波数据对应的相位信息。
`timescale 1ns / 1ps
//
// Company: UESTC
// Engineer: chylinne
//
// Create Date: 2022/08/15 13:45:42
// Design Name: fm
// Module Name: fm_modulation
// Project Name: fm
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fm_modulation # (
/* Phase Offset Programmability
poff = 2^N * f_carrier
= 2^16 * 100 kHz
= 2^16 * 0.1 MHz
= 6554
*/
parameter POFF = 'd6554 //100KHz
)(
input clk,
input rst_n,
input fm_mod_ready,
output fm_mod_valid,
output signed [15:0] fm_mod_data
);
reg signed [15:0] phase_cnt;
wire signed [15:0] phase_data;
reg phase_valid;
wire phase_ready;
wire signed [15:0] phase_add;
wire signed [7:0] sine_signal; // sine modulate signal
wire sine_valid;
wire sine_ready;
assign phase_add = sine_signal << 4; // multiply 16
assign sine_ready = phase_ready;
assign phase_data = phase_cnt;
always @(posedge clk)
begin
if(!rst_n)
phase_valid <= 0;
else if(phase_ready)
phase_valid <= sine_valid;
end
always @(posedge clk)
begin
if(!rst_n)
begin
phase_cnt <= 0;
end
else if(phase_ready && sine_valid)
begin
phase_cnt <= phase_cnt + phase_add + POFF;
end
end
dds_compiler_sine dds_1 (
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.m_axis_data_tvalid (sine_valid), // output wire m_axis_data_tvalid
.m_axis_data_tready (sine_ready), // input wire m_axis_data_tready
.m_axis_data_tdata (sine_signal) // output wire [7 : 0] m_axis_data_tdata
);
dds_compiler_fm dds_2 (
.aclk (clk), // input wire aclk
.aresetn (rst_n), // input wire aresetn
.s_axis_phase_tvalid(phase_valid), // input wire s_axis_phase_tvalid
.s_axis_phase_tready(phase_ready), // output wire s_axis_phase_tready
.s_axis_phase_tdata (phase_data), // input wire [15 : 0] s_axis_phase_tdata
.m_axis_data_tvalid (fm_mod_valid), // output wire m_axis_data_tvalid
.m_axis_data_tready (fm_mod_ready), // input wire m_axis_data_tready
.m_axis_data_tdata (fm_mod_data) // output wire [15 : 0] m_axis_data_tdata
);
endmodule
(3)解调模块
解调模块则是通过 FIR 低通滤波器的 IP 核实现包络提取。文章来源:https://uudwc.com/A/XwVz
`timescale 1ns / 1ps
//
// Company: UESTC
// Engineer: chylinne
//
// Create Date: 2022/08/15 13:47:23
// Design Name: fm
// Module Name: fm_demodulation
// Project Name: fm
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fm_demodulation (
input clk,
input rst_n,
output fm_mod_ready,
input fm_mod_valid,
input signed [15:0] fm_mod_data,
input fm_demod_ready,
output fm_demod_valid,
output signed [15:0] fm_demod_data
);
reg signed [15:0] mem_data = 0;
reg signed [15:0] dif_data = 0;
reg dif_valid = 0;
wire dif_ready;
reg [15:0] abs_data = 0;
reg abs_valid = 0;
wire abs_ready;
wire signed [39:0] fir_data;
wire fir_valid;
wire fir_ready;
always @(posedge clk)
begin
if(!rst_n)
dif_valid <= 0;
else
dif_valid <= (dif_ready) ? fm_mod_valid : dif_valid;
end
/* Calculate difference data
dx/dt
dt is the clock period.
dx is the difference of data in current clock and data in last clock.
*/
always @(posedge clk)
begin
if(!rst_n)
begin
mem_data <= 0;
dif_data <= 0;
end
else begin
if(dif_ready && fm_mod_valid)
begin
mem_data <= fm_mod_data; // Save the data in current clock
dif_data <= fm_mod_data - mem_data; // data in current clock minus data in last clock
end
else ;
end
end
always @(posedge clk)
begin
if(!rst_n)
abs_valid <= 0;
else
abs_valid <= (abs_ready) ? dif_valid : abs_valid;
end
// Calculate absolute value
always @(posedge clk)
begin
if(!rst_n)
abs_data <= 0;
else begin
if(abs_ready && dif_valid)
begin
if(dif_data >= 0)
abs_data <= dif_data;
else
abs_data <= -dif_data;
end
else ;
end
end
assign fir_ready = fm_demod_ready;
assign fm_demod_data = fir_data >>> 19;
assign fm_demod_valid = fir_valid;
assign fm_mod_ready = abs_ready;
assign dif_ready = abs_ready;
// FIR lowpass filter
fir_compiler_lowpass fir_1 (
.aresetn (rst_n), // input wire aresetn
.aclk (clk), // input wire aclk
.s_axis_data_tvalid (abs_valid), // input wire s_axis_data_tvalid
.s_axis_data_tready (abs_ready), // output wire s_axis_data_tready
.s_axis_data_tdata (abs_data), // input wire [15 : 0] s_axis_data_tdata
.m_axis_data_tvalid (fir_valid), // output wire m_axis_data_tvalid
.m_axis_data_tready (fir_ready), // input wire m_axis_data_tready
.m_axis_data_tdata (fir_data) // output wire [31 : 0] m_axis_data_tdata
);
endmodule
文章来源地址https://uudwc.com/A/XwVz