我是靠谱客的博主 体贴玫瑰,最近开发中收集的这篇文章主要介绍基于高云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文件

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)主程序


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)微分

//对调制信号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的FM调制与解调一、概述二、平台三、要求四、原理五、调试过程六、程序六、注意事项所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部