我是靠谱客的博主 彪壮咖啡豆,这篇文章主要介绍FM调制的FPGA实现一、前言二、关于FM调制三、FM调制的FPGA实现四、总结,现在分享给大家,希望可以做个参考。

一、前言

1.1. 平台

  • Vivado 2017.4;
  • Matlab 2016b;

1.2. 参数

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

二、关于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代码如下:

复制代码
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
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)。根据以上情况,可以通过调制信号的大小计算出此时输出频率的大小。总结如下表:

输入调制信号大小对应的频率偏移对应频偏的频率控制字
000
2^1175k2^32 * 75k / 100M = 3221225
XYN

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

  1. 乘法操作

乘法器IP核配置如下:

  1. 除法操作

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

  1. DDS输出已调信号

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

复制代码
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
48
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. 顶层模块设计

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

复制代码
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
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

复制代码
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
`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. 仿真结果

运行仿真结果如下:

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

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

四、总结

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

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

最后

以上就是彪壮咖啡豆最近收集整理的关于FM调制的FPGA实现一、前言二、关于FM调制三、FM调制的FPGA实现四、总结的全部内容,更多相关FM调制内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(90)

评论列表共有 0 条评论

立即
投稿
返回
顶部