FM调制的FPGA实现(三)

				版权声明:本文为博主原创文章,如果觉得不错欢迎转载,记得标明出处就行。					https://blog.csdn.net/HOOKNET/article/details/81278232				</div>
							<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
							            <div id="content_views" class="markdown_views prism-atom-one-dark">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h1><a name="t0"></a><a id="_1" target="_blank"></a>一、前言</h1>

1.1. 平台

  • Vivado 2017.4;
  • Matlab 2016b;

1.2. 参数

  • 载波频率:5M;
  • 频率偏移:-75KHz ~ 75KHz;
  • 系统时钟:100M;
  • AD位宽:12位;

二、关于FM调制

图解AM、FM

简单来说就是:幅度改变频率
与之相对应的是AM:幅度改变幅度

怎么理解呢?对FM来说:调制信号的幅度大小决定了已调信号的频率。当调制信号的幅度改变时,已调信号的频率也会随之改变,而且只有频率会改变,幅度是保持不变的。

这里对FM调制的理论部分不过多讲述,有兴趣的可以自行上网查阅。

三、FM调制的FPGA实现

一个完整的FM调制系统主要分为以下几个部分:

  • AD模块
  • FM调制模块
  • DA模块

其中,AD模块将模拟调制信号转换成数字调制信号。调制信号可以通过信号发生器产生。在本工程中,将在FPGA内部通过DDS产生一个正弦信号来模拟AD采样数据。FM调制模块的功能就是将调制信号变成FM已调信号。已调信号通过DA模块变成模拟信号后就可以通过天线发送出去。

3.1. 产生调制信号

调制信号是用DDS产生正弦信号来模拟实现的。DDS的实现需要用到ROM IP核,在配置ROM IP核之前需要用Matlab生成IP核所需要的.coe文件。

  1. 生成.coe配置文件

Matlab代码部分参考本人之前的博客:
AM调制的FPGA实现

其中只需要把位宽(改成12)和文件生成路径作相应修改即可。

  1. 调用一个单口ROM IP核

关于IP核的配置如下


  1. 产生调制信号

整个工程的系统时钟为100MHz,这里假设调制信号是一个频率为500KHz的单频信号,换算成频率控制字的话为:

500K * 2^32 / 100M = 21474836

DDS代码如下:

module DDS_Mod(
    input 	clk,
    input   rst_n,
output  signed  [11:0]  sin		//调制信号

);
//--------------------------------------------------------//
parameter Freq = 32’d21474836; //500kHz
parameter cnt_width = 8’d32;
//--------------------------------------------------------//

//--------------------------------------------------------//
reg [cnt_width-1:0]cnt_I = 0;
wire [9:0] addr_I;

always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_I <= 0;
end
else begin
cnt_I <= cnt_I + Freq;
end
end

assign addr_I = cnt_I[cnt_width-1:cnt_width-10];
//--------------------------------------------------------//

//--------------------调用一个单口ROM核--------------------//
Sin Sin_inst(
.clka (clk),
.addra (addr_I),
.douta (sin)
);

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

3.2. FM调制模块

其实FM调制模块本质上也是一个DDS,区别就在于前者是一个频率可以按照一定规律变化的DDS。那么如何才能让频率不断变化呢?回到上面的代码中,有一个名为“Freq”的常量,这个常量的大小决定了DDS输出频率的大小。如果在这个常量后面再加上一个不断变化的值,那么这个DDS输出的就是一个频率不断变化的波形了。

在FM调制中,有两个比较重要的概念:中心频率和频偏。中心频率可以理解为只有“Freq”时的频率;频偏可以理解为当再加上一个变量后,输出频率大小与中心频率的差值。因此FM调制的关键就在于如何确定“Freq”这个常量后面再加上的这个变量的值。

本工程中中心频率为:5M,频偏为:-75KHz ~ 75KHz。当输入调制信号幅度为0时,输出的FM已调信号频率为5MHz,即载波频率;当输入调制信号幅度最大(即+211)时,输出的FM已调信号频率为5.075MHz(5M+75K);当输入调制信号幅度最小(即-211)时,输出的FM已调信号频率为4.925MHz(5M-75K)。根据以上情况,可以通过调制信号的大小计算出此时输出频率的大小。总结如下表:

输入调制信号大小 对应的频率偏移 对应频偏的频率控制字
0 0 0
2^11 75k 2^32 * 75k / 100M = 3221225
X Y N

上表中,X是已知量,只需要通过等式 N = x * 3221225 / 2^11 求出N的值即可。

  1. 乘法操作

乘法器IP核配置如下:

  1. 除法操作

除法操作可以调用除法器IP核来实现,也可以通过移位相加的方法实现。考虑到除数是2的整数次幂,因此只需要把乘法器输出的结果右移11位即可。

  1. DDS输出已调信号

这部分其实和上面的DDS实现方法类似,只是在频率控制字后面再加上频偏控制字即可。代码如下:

module FM_Mod(
	input	clk,
	input	rst_n,
	input	[11:0]	adc_data,
	output	[11:0]	FM_Mod
);

parameter Freq_I = 32’d214_748_365; //载波信号的频率5M,时钟100M
parameter Freq_Word = 32’d3_221_225; //频偏为75K
parameter cnt_width = 8’d32;

//-------------计算频偏控制字--------------//
wire signed [43:0] mult_data;
wire signed [31:0] Freq_Offset;

MULT MULT_inst(
.CLK (clk),
.A (adc_data),
.B (Freq_Word),
.P (mult_data)
);

assign Freq_Offset = mult_data[43:12]; //移位

//---------------------------------------//
reg [cnt_width-1:0]cnt_I;
wire [9:0] addr_I;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_I <= 0;
end
else begin
cnt_I <= cnt_I + Freq_I + Freq_Offset;
end
end

assign addr_I = cnt_I[cnt_width-1:cnt_width-10];

//----------------ROM核-----------------//
Sin Sin_inst(
.clka (clk),
.addra (addr_I),
.douta (FM_Mod)
);

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

3.3. 顶层模块设计

顶层文件不过多介绍,代码如下:

module TOP(
    input			clk,
	input			rst_n,
output         	[11:0]  FM_Mod_data

);

//----------------ADC-----------------//
wire [11:0] adc_data;

DDS_Mod DDS_Mod_inst(
.clk (clk),
.rst_n (rst_n),
.sin (adc_data)
);
//------------------------------------//

//---------------FM调制----------------//
FM_Mod FM_Mod_inst(
.clk (clk),
.rst_n (rst_n),
.adc_data (adc_data),
.FM_Mod (FM_Mod_data)
);

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3.4. TestBench

`timescale	1ns/1ps

module tb_TOP();

reg sclk;
reg rst_n;

wire [11:0] FM_Mod_data;

//---------系统时钟----------//
initial sclk = 1;
always #5 sclk = !sclk;
//---------复位---------//
initial begin
rst_n = 0;
#100
rst_n = 1;
end

//-----------------------//
TOP TOP_inst(
.clk (sclk),
.rst_n (rst_n),
.FM_Mod_data (FM_Mod_data)
);
//-----------------------//

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

3.5. 仿真结果

运行仿真结果如下:

其实从仿真来看看不出什么明显的效果,是因为频偏相对于载频来说太小了,变化不明显。如果将频偏改成2MHz再仿真,结果如下:
在这里插入图片描述

从仿真结果来看输出波形存在着明显的频率变化,表明输出的是FM已调信号了。但这些都只是基于仿真来看的,至于输出信号是否正真满足指标要求,还得将已调信号通过DA输出到频谱仪上进行验证。

四、总结

FM调制在实现方式上还是比较简单的,但是可能需要一定的理解。以上的实现过程比较粗糙,只是从仿真层面去大致实现一个FM调制的效果,在实际应用中会有更加复杂的情况。另外,本人建议有条件的尽量在频谱仪上验证调制效果,对于指标严格的调制,普通示波器的频谱分析功能不一定能胜任。

另外,如有需要改进的地方,欢迎各位指出。

        </div>
					<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet">
                  </div>
</article>
				版权声明:本文为博主原创文章,如果觉得不错欢迎转载,记得标明出处就行。					https://blog.csdn.net/HOOKNET/article/details/81278232				</div>
							<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
							            <div id="content_views" class="markdown_views prism-atom-one-dark">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h1><a name="t0"></a><a id="_1" target="_blank"></a>一、前言</h1>

猜你喜欢

转载自blog.csdn.net/weixin_37182342/article/details/89502650