我是靠谱客的博主 眯眯眼中心,这篇文章主要介绍基于 VIVADO 的 FM 调制解调(上)设计篇,现在分享给大家,希望可以做个参考。

一、概述

        本文先简要介绍了频率调制(frequency modulation,FM,简称调频)的原理,然后对其进行方案设计,最后基于 VIVADO 2018.3 使用 Verilog 进行实现。

二、FM 原理

        角度调制(angle modulation)是已调波的总相角 phi left ( t right ) 随着基带信号 mleft ( t right ) 作某种变化的调制方式,它包括频率调制和相位调制。一般而言,角调信号的表达式为:

sleft ( t right ) = A_{c}cosleft [ phi left ( t right ) right ]

其中,phi left ( t right ) 称为相角,它是随 mleft ( t right ) 变化的。

        频率调制(frequency modulation,FM,简称调频)的调制表达式可以下式表示:

s_{FM}left ( t right )=A_{c}cosleft [ 2pi f_{c}t+2pi k_{FM}int mleft ( t right ) dt right ]

其中,k_{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 也可由顶层进行参数配置,以满足用户的不同需求。

复制代码
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
`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 信号)的产生,重点在于需要通过相位计数器和相位控制字来计算出正弦波数据对应的相位信息。

复制代码
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
`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 核实现包络提取。

复制代码
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
`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

最后

以上就是眯眯眼中心最近收集整理的关于基于 VIVADO 的 FM 调制解调(上)设计篇的全部内容,更多相关基于内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部