我是靠谱客的博主 体贴玫瑰,这篇文章主要介绍基于高云FPGA的FM调制与解调一、概述二、平台三、要求四、原理五、调试过程六、程序六、注意事项,现在分享给大家,希望可以做个参考。

基于高云FPGA的FM调制与解调

  • 一、概述
  • 二、平台
  • 三、要求
  • 四、原理
  • 五、调试过程
    • 1、FM调制
    • 2、FM解调
  • 六、程序
    • (1)生成.mi文件
    • (2)主程序
    • (3)微分
  • 六、注意事项

一、概述

基于高云FPGA开发板自主设计支持FM调制方式的数字发射机,FM调制外部输入的音频信号,可使FM接收机正确接收并播放。

二、平台

Gowin_V1.9.8
Modelsim SE-64 2019.2
(如果用Gowin,首先要学会Gowin和Modelsim 如何进行联调;用vivado可忽略)

三、要求

(1)FM调制信号由外部音频输入;
(2)FM发射机在国家划分的FM广播频段,包含多个电台频率;
(3)调制信号通过天线发出,接收距离可达两米以上;

四、原理

FM调制的结构如下图所示:在这里插入图片描述
  调制信号是用DDS产生正弦信号来模拟实现的。DDS的实现需要用到ROM IP核,在配置ROM IP核之前需要用Matlab生成IP核所需要的.mi文件。
  在FM调制中,有两个比较重要的概念:中心频率和频偏。中心频率可以理解为只有“Freq”时的频率;频偏可以理解为当再加上一个变量后,输出频率大小与中心频率的差值。因此FM调制的关键就在于如何确定“Freq”这个常量后面再加上的这个变量的值。
  假设中心频率为:5M,频偏为:-75KHz ~ 75KHz。当输入调制信号幅度为0时,输出的FM已调信号频率为5MHz,即载波频率;当输入调制信号幅度最大(即+211)时,输出的FM已调信号频率为5.075MHz(5M+75K);当输入调制信号幅度最小(即-211)时,输出的FM已调信号频率为4.925MHz(5M-75K)。根据以上情况,可以通过调制信号的大小计算出此时输出频率的大小。总结如下表:
在这里插入图片描述

五、调试过程

1、FM调制

  (1)首先,通过MATLAB生产.mi文件,.mi文件里是一个正弦波的采样:
在这里插入图片描述

  (2)Gowin_pROM ip核调用.mi文件生成一个5k HZ、12位的正弦调制波。(通过rom_addr地址的长度控制频率)
在这里插入图片描述
  (3)通过调制波幅度控制载波频率;生成中心频率为500k HZ,频偏为:-15k Hz ~ 15k Hz的已调信号。(根据调制波幅度修改rom_addr地址的长度)
在这里插入图片描述

  (4)最后截取已调信号的高8位作为输出。

2、FM解调

  (1)首先对FM已调波进行微分,将调制信号与载波的频率关系转换为幅度关系;

  (2)再进行FIR低通滤波,得到滤波信号。(可能是截止频率计算得有问题,信号不平滑)
在这里插入图片描述
  (3)由于滤波后的信号不平滑,故增加一个均值滤波算法。
在这里插入图片描述

六、程序

(1)生成.mi文件

复制代码
1
2
3
4
5
6
7
8
9
10
x = linspace(0,6.28,4096); %在0和2pi间取1024个点 y1 = sin(x)+1; y1 = round(y1 * 2047); fid = fopen('sine.mi','wt'); % 生成.mi文件 fprintf(fid,'#File_format=Hexn'); fprintf(fid,'#Address_depth=4096n'); fprintf(fid,'#Data_width=12n'); fprintf(fid,'%03xn',y1); % 生成三位数据,不足的在前面补零 fclose(fid);

(2)主程序

复制代码
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
module FM_mod( input clk, input rst_n, output wire [11:0] Data_in_carry, output wire [11:0] Data_in_modulate, output wire [7:0] Data_out, output wire clk_out_DA, output wire [11:0]data_out2, output wire [11:0]demolate_final, output wire wr_en_data_i, output wire wr_en_coeffi_i, output wire [15:0] din_coeffi_i, output wire input_rdy, output reg [4:0]cnt, output wire done, output wire [53:0]demolate_final_out ); wire clk_200M; assign Data_out[7:0] = Data_in_carry[11:4]; assign clk_out_DA = clk_200M ; reg [11:0] rom_addr_carry; reg [11:0] rom_addr_modulate; //倍频 Gowin_rPLL your_instance_name_1( .clkout(clk_200M), //output clkout .clkin(clk) //input clkin ); //分频5M reg [3:0] counter; reg clk_5M; always@(posedge clk or negedge rst_n) if(!rst_n) begin counter <= 4'd0; clk_5M <= 0; end else if(counter== 4'd4) begin clk_5M <=~clk_5M; counter <= 4'd0; end else begin counter <= counter + 1; end //频率控制 always@(posedge clk_5M or negedge rst_n) if(!rst_n) begin rom_addr_modulate <= 10'd0; end else begin rom_addr_modulate <= rom_addr_modulate+1; //1.25KHZ //4096 end always@(posedge clk or negedge rst_n) if(!rst_n) begin rom_addr_carry <= 10'd0; end else begin rom_addr_carry <= rom_addr_carry +10+Data_in_modulate[11:8]-7; //500KHZ , 12.5K/1 , +-75K // rom_addr_carry <= rom_addr_carry +5; //1MHZ +-0.4M end //正弦//调制 Gowin_pROM Gowin_pROM_modulate( .dout(Data_in_modulate), //output [11:0] dout .clk(clk_5M), //input clk .ce(1'b1), //input ce .reset(~rst_n), //input reset .ad(rom_addr_modulate) //input [9:0] ad ); //正弦//载波 Gowin_pROM Gowin_pROM_carry( .dout(Data_in_carry), //output [11:0] dout .clk(clk_200M), //input clk .ce(1'b1), //input ce .reset(~rst_n), //input reset .ad(rom_addr_carry) //input [9:0] ad ); //对调制信号 FM_Mod 进行微分,对微分后的信号取绝对值 wire [11:0]FM_Mod; assign FM_Mod[11:0] = Data_in_carry[11:0]; Weifen_FM_Mod Weifen_FM_Mod( .clk(clk), .rst_n(rst_n), //rst_n, .FM_Mod(FM_Mod),// [11:0] FM_Mod, //输入已调信号 .buffer(buffer), //reg [11:0] buffer, .data_out1(data_out1), //[11:0] data_out1, //微分后的信号data_out1 .data_out2(data_out2) //reg [11:0] data_out2 //取绝对值后的数据data_out2 ); wire [11:0]AM_abs; assign AM_abs = data_out2; wire [53:0] demolate_signal; //------------调用FIR滤波器--------------// Basic_FIR_Filter_Top Basic_FIR_Filter_Top_1( .clk(clk), //input clk .rst_n(rst_n), //input rst_n .ini(ini_i), //input ini .wr_en_data(wr_en_data_i), //input wr_en_data .wr_en_coeffi(wr_en_coeffi_i), //input wr_en_coeffi .din_coeffi(din_coeffi_i), //input [11:0] din_coeffi .din_data(AM_abs), //input [11:0] din_data .dout(demolate_signal), //output [53:0] dout .done(done), //output done .input_rdy(input_rdy) //output input_rdy ); reg [5:0]flag_sery; reg wr_en_coeffi; reg signed [15:0]din_coeffi; reg ini; //系数写入时序// always @(posedge clk or negedge rst_n) begin if(!rst_n) begin wr_en_coeffi <= 1; flag_sery <= 0; ini <= 1; end else begin if(flag_sery == 0) begin wr_en_coeffi <= 1; din_coeffi <= 28; flag_sery <= 1; end else if(flag_sery == 1) begin din_coeffi <= 29; flag_sery <= 2; end else if(flag_sery == 2) begin din_coeffi <= 31; flag_sery <= 3; end else if(flag_sery == 3) begin din_coeffi <= 32; flag_sery <= 4; end else if(flag_sery == 4) begin din_coeffi <= 33; flag_sery <= 5; end else if(flag_sery == 5) begin din_coeffi <= 34; flag_sery <= 6; end else if(flag_sery == 6) begin din_coeffi <= 34; flag_sery <= 7; end else if(flag_sery == 7) begin din_coeffi <= 35; flag_sery <= 8; end else if(flag_sery == 8) begin din_coeffi <= 35; flag_sery <= 9; end else if(flag_sery == 9) begin din_coeffi <= 34; flag_sery <= 10; end else if(flag_sery == 10) begin din_coeffi <= 34; flag_sery <= 11; end else if(flag_sery == 11) begin din_coeffi <= 33; flag_sery <= 12; end else if(flag_sery == 12) begin din_coeffi <= 32; flag_sery <= 13; end else if(flag_sery == 13) begin din_coeffi <= 31; flag_sery <= 14; end else if(flag_sery == 14) begin din_coeffi <= 29; flag_sery <= 15; end else if(flag_sery == 15) begin din_coeffi <= 28; flag_sery <= 16; end else begin wr_en_coeffi <= 0; ini <= 0; end end end //数据输入时序// reg wr_en_data; reg [4:0]cnt_1; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin wr_en_data <= 0; cnt <= 0; cnt_1 <= 0; end else if(input_rdy == 1&cnt[4] == 1) begin wr_en_data <= 1; cnt <= cnt+1; end else if(cnt_1[4] == 0) begin wr_en_data <= 0; cnt_1 <= cnt_1+1; end else begin wr_en_data <= 0; cnt <= cnt+1; end end assign wr_en_data_i = wr_en_data; assign wr_en_coeffi_i = wr_en_coeffi; assign din_coeffi_i = din_coeffi; assign ini_i = ini; reg [53:0]demolate_final_1; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin demolate_final_1 <= 0; end else if(demolate_signal !== 0) begin demolate_final_1 <= demolate_signal; end else begin demolate_final_1 <= demolate_final_1; end end assign demolate_final[11:0] = demolate_final_1[16:5]; //截位 //平滑 reg [53:0]Smooth_1; reg [53:0]Smooth_2; reg [53:0]Smooth_3; reg [53:0]Smooth_4; reg [53:0]Smooth_5; reg [53:0]Smooth_6; reg [53:0]Smooth_7; reg [53:0]Smooth_8; always @(posedge clk_5M or negedge rst_n) begin if(!rst_n) begin Smooth_1 <= 0; Smooth_2 <= 0; Smooth_3 <= 0; Smooth_4 <= 0; Smooth_5 <= 0; Smooth_6 <= 0; Smooth_7 <= 0; Smooth_8 <= 0; end else if(demolate_final_1) begin Smooth_1 <= demolate_final_1; Smooth_2 <= Smooth_1; Smooth_3 <= Smooth_2; Smooth_4 <= Smooth_3; Smooth_5 <= Smooth_4; Smooth_6 <= Smooth_5; Smooth_7 <= Smooth_6; Smooth_8 <= Smooth_7; end end assign demolate_final_out = Smooth_1 + Smooth_2 + Smooth_3 + Smooth_4 + Smooth_5 + Smooth_6 + Smooth_7 + Smooth_8; endmodule

(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
30
31
32
33
34
35
36
37
//对调制信号FM_Mod进行微分,对微分后的信号取绝对值 module Weifen_FM_Mod( input clk, input rst_n, input [11:0] FM_Mod, //输入已调信号 output reg [11:0] buffer, output [11:0] data_out1, //微分后的信号data_out1 output reg [11:0] data_out2 //取绝对值后的数据data_out2 ); assign data_out1=FM_Mod-buffer; //--------------------------微分(累减)--------------------------------------------// always @(posedge clk or negedge rst_n) begin if(!rst_n) begin buffer<=0; end else begin buffer<=FM_Mod; //一个时钟的延迟 end end //--------------------------取绝对值-----------------------------------------// always @(posedge clk or negedge rst_n) begin if(!rst_n) begin data_out2 <= 0; end else if(data_out1[11] == 1) begin data_out2 <= -{data_out1}; //如果符号位是1,对数据取反 end else if(data_out1[11] == 0) begin data_out2 <= data_out1; //如果符号位是0,数据不变 end else begin data_out2 <= data_out2; end end endmodule

六、注意事项

   FIR滤波器这块的系数时序写入,写的有点拉胯。仅限参考

最后

以上就是体贴玫瑰最近收集整理的关于基于高云FPGA的FM调制与解调一、概述二、平台三、要求四、原理五、调试过程六、程序六、注意事项的全部内容,更多相关基于高云FPGA内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部