AM解调的FPGA实现(二)

				版权声明:本文为博主原创文章,如果觉得不错欢迎转载,记得标明出处就行。					https://blog.csdn.net/HOOKNET/article/details/79157260				</div>
							<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
							            <div id="content_views" class="markdown_views">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h2 id="一说明"><a name="t0"></a>一、说明:</h2>
  1. 功能:AM解调
  2. 平台:Vivado 2016.4 和 Matlab R2017a

二、原理:

1.AM解调原理

  • 模拟电路中采用“包络检波”的方法:
    这里写图片描述
  • 数字电路中采用类似的方法:
    先将已调信号取绝对值,再经过低通滤波器,滤除高频分量(经AM调制的信号包含两个高频分量:载波频率+/-调制信号频率,因此低通滤波器的截止频率小于两个高频分量就可以),得到的就是叠加了直流分量的调制信号,去直流后便可以得到调制信号。

三、AM解调的FPGA实现

1.将已调制的AM信号取绝对值

关于AM信号的产生,参见上一篇博客: AM调制的FPGA实现
简单说明一下对数据取反的思路:如果是无符号数,则不存在符号位,也就是说数据都是正数,不需要取绝对值;如果是有符号数,通过检测最高位的符号位,如果符号位是1,则表示数据是负数,对数据取反,如果符号位是0,则表示数据是正数,不需要取反操作。

  • 取绝对值的Verilog实现:
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)  begin
        data_tdata <= 0;
    end
    else if(AM_mod[15] == 1)    begin
        data_tdata <= -{AM_mod};        //如果符号位是1,对数据取反
    end
    else if(AM_mod[15] == 0)    begin
        data_tdata <= AM_mod;           //如果符号位是0,数据不变
    end
    else    begin
        data_tdata <= data_tdata;
    end
end
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2.使用FIR滤波器滤除高频分量

关于Vivado的FIR IP核可以说是功能很强大的,但这里不需要其他复杂的功能,只需要简单的生成一个的低通滤波器就行了。
类似于ROM核的生成,配置FIR同样需要Matlab配合。可见,Matlab的功能是多么强大。这里Matlab的主要作用是对滤波器的性能进行仿真并生成相应的抽头系数。

  • 使用Matlab生成FIR的抽头系数
    在Matlab的命令行窗口输入:filterDesigner(以前是用fdatool命令,不过输入fdatool也可以,只是会提醒你改用新的命令)弹出滤波器设计窗口:

    接下来,对滤波器的一些参数进行设置:

    参数设置好后,点击Design Filter 按钮查看生成滤波器的幅频响应图,通过幅频响应等图来判断滤波器是否达到设计要求:

    设计的滤波器满足性能指标后需要将抽头系数导出,保存为.coe文件。在导出前需要对系数进行量化。因为需要解调的AM信号也是16位宽,所以这里的位宽设置保持默认值,这些可以根据实际情况自行修改。

    量化过后就能将抽头系数导出为.coe文件了:

  • 生成FIR IP核
    IP核的具体配置如下:



    其他保持默认即可:


    同样,在IP核配置界面也可以查看滤波器的幅频特性:

IP核生成完毕后,就可以编写IP核的调用模块了。

  • FIR IP核调用模块:
module FIR_Control(
    input   clk,
    input   rst_n,
    input   signed  [15:0]  s_axis_data_tdata,
    output  reg     [7:0]   data_out
);

wire    s_axis_data_tready;
wire    m_axis_data_tvalid;
wire    [39:0]  m_axis_data_tdata;      //滤波器输出信号

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)  begin
        data_out <= 0;
    end
    else    begin
        data_out <= m_axis_data_tdata[33:26];   //根据仿真结果进行截位
    end
end

//--------------调用FIR核----------------//
FIR                     FIR_inst0(
  .aclk                 (clk),
  .s_axis_data_tvalid   (1),                    //拉高时IP核开始工作
  .s_axis_data_tready   (s_axis_data_tready),   
  .s_axis_data_tdata    (s_axis_data_tdata),    //输入信号
  .m_axis_data_tvalid   (m_axis_data_tvalid),   //拉高时表明数据输出有效
  .m_axis_data_tdata    (m_axis_data_tdata)     //输出信号
);
//---------------------------------------//


endmodule 

  
  
  • 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

需要注意的是:
m_axis_data_tdata 信号是滤波器的数据输出信号,我们在使用时一般都要对此数据进行截位操作,如何进行截位需要根据仿真结果来确定。比如,在这个工程中,我需要的滤波器的输出数据是8位,但不能一下子截取高8位,而且m_axis_data_tdata是个40位的数据,从仿真波形来看m_axis_data_tdata[39:34]都是符号位,因此从33位开始往下截取8位数据(当然也可以从34位开始截,这样的话就多了一位符号位,相应的数据位就变少了一位)。

3.去直流处理

经过FIR滤波后的波形其实就是一个叠加了直流分量的调制信号。在本工程中,AM调制是100%调制,也就是说解调时经过FIR后的信号的最小值为0,可以把它看作是无符号的数,直接经DA输出就行了。
如果不是100%调制呢?也就是说解调时经过FIR后的信号的最小值是大于0的,那么这个大于0的量就相当于直流,需要去掉后再经DA输出。
因此,在这个工程中,不需要去直流处理。下面给出顶层文件的代码。

  • 顶层模块编写:
module TOP(
    input   clk,
    input   rst_n,
    output  [7:0]   AM_demod
);

//--------------------------------//
reg     signed  [15:0]  data_tdata;
wire    signed  [15:0]  AM_mod;
//--------------------------------//

//-----------取绝对值-------------//
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)  begin
        data_tdata <= 0;
    end
    else if(AM_mod[15] == 1)    begin
        data_tdata <= -{AM_mod};        //如果符号位是1,对数据取反
    end
    else if(AM_mod[15] == 0)    begin
        data_tdata <= AM_mod;           //如果符号位是0,数据不变
    end
    else    begin
        data_tdata <= data_tdata;
    end
end
//--------------------------------//

//-----------AM已调信号------------//
modulate        modulate_inst0(
    .clk        (clk),
    .rst_n      (rst_n),
    .AM_mod     (AM_mod)
);
//--------------------------------//

//----------滤波器控制模块---------//
FIR_Control             FIR_Control_inst2(
    .clk                (clk),
    .rst_n              (rst_n),
    .s_axis_data_tdata  (data_tdata),
    .data_out           (AM_demod)
);
//--------------------------------//

endmodule

  
  
  • 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

4.解调仿真

  • 编写TestBeach:
`timescale 1ns/1ps

module tb_AM();

//===================解调部分====================//
//----------接口设置----------//
reg     sclk;
reg     rst_n;
wire    [7:0]   AM_demod;
//--------------------------//
initial     sclk = 1;
always  #5  sclk = ~sclk;      //100M时钟

initial begin
    rst_n = 0;
    #500
    rst_n = 1;
end
//----------解调模块----------//
TOP             TOP_inst(
    .clk        (sclk),
    .rst_n      (rst_n),
    .AM_demod   (AM_demod)
);
//---------------------------//

endmodule

  
  
  • 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
  • 仿真结果

    由仿真结果可知,最终输出信号正确还原了已调制信号的包络,表明解调正确。
				版权声明:本文为博主原创文章,如果觉得不错欢迎转载,记得标明出处就行。					https://blog.csdn.net/HOOKNET/article/details/79157260				</div>
							<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
							            <div id="content_views" class="markdown_views">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h2 id="一说明"><a name="t0"></a>一、说明:</h2>

猜你喜欢

转载自blog.csdn.net/weixin_37182342/article/details/89502623