FM调制的FPGA实现

一、前言

1.1. 平台

  • Vivado 2017.4;
  • Matlab 2016b;

1.2. 参数

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

二、关于FM调制

[外链图片转存失败(img-IOpiIkja-1567782517390)(https://upload.wikimedia.org/wikipedia/commons/a/a4/Amfm3-en-de.gif)]

简单来说就是:幅度改变频率
与之相对应的是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核的配置如下
FM调制的FPGA实现_第1张图片
FM调制的FPGA实现_第2张图片
FM调制的FPGA实现_第3张图片

  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

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核配置如下:
FM调制的FPGA实现_第4张图片
FM调制的FPGA实现_第5张图片

  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

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

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

3.5. 仿真结果

运行仿真结果如下:
FM调制的FPGA实现_第6张图片

其实从仿真来看看不出什么明显的效果,是因为频偏相对于载频来说太小了,变化不明显。如果将频偏改成2MHz再仿真,结果如下:
FM调制的FPGA实现_第7张图片

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

四、总结

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

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

你可能感兴趣的:(FPGA学习之---通信算法)