FPGA数字信号处理之verilog实现混频器

描述

混频:两个不同频率之间的混合,得到第三个频率。在数字信号处理中用来完成频谱搬移求和,是数字信号处理中的基本元件之一。例如通信中的混频合路:FPGA常见的数字混频器结构如下,由移频模块和求和模块组成。比如信号A、B是输入的两个单音信号,B是上一节讲到的NCO信号,使用复乘将A、B信号进行搬移,然后求和。FPGA

频谱搬移的过程如下,输入信号Data_in,与NCO产生的单音信号进行复乘得到Data_out;

FPGA

 

将Data_in与Data_out的频谱放到一起如下,可以看到频谱搬移的过程。

FPGA

频谱搬移在计算上就是复乘:(i+q*j)*(cos+sin*j)=(cos*i-sin*q)+(sin*i+cos*q)*j,用xilinx片子实现的话我们还是选择DSP48,其结构如下:

FPGA

其中用到了dsp的级联,可以参考之前dsp48e1详细讲解的文章:FPGA的底层资源之DSP48E1和Xilinx DSP48E1仿真。这里不再详细描述。

代码实现如下:

首先的端口声明:

// ============================================================
// File Name: cm_mix
// VERSION  : V1.0
// DATA     : 2022/11/6
// Author   : FPGA干货分享
// ============================================================
// 功能:数字混频器  (i+q*j)*(cos+sin*j) = (cos*i - sin*q) + (sin*i + cos*q)*j
// delay  
// ============================================================


`timescale 1ns/1ps
module cm_mix #(
        parameter           C_DATA_WITH     = 16 ) // 
    (
        input  wire                     I_sys_clk    , // 输入时钟
        input  wire                     I_rst_in     , // 输入复位 高有效
        input  wire [6:0]               I_phase      , // 初始相位
        input  wire [7:0]               I_freq       , // 频率,步进,1代表1M
        input  wire [C_DATA_WITH-1:0]   I_data_in_i  , // 输入数据 实部I
        input  wire [C_DATA_WITH-1:0]   I_data_in_q  , // 输入除数 虚部Q
        output reg  [C_DATA_WITH-1:0]   O_data_out_i , // 输出数据 实部I
        output reg  [C_DATA_WITH-1:0]   O_data_out_q );// 输出除数 虚部Q
        
// ============================================================
// 内部参数
// ============================================================


// ============================================================
// 变量
// ============================================================
wire       [10:0]               S_sin_out       ;
wire       [10:0]               S_cos_out       ;
reg        [C_DATA_WITH-1:0]    S_data_in_q     ;
reg        [10:0]               S_sin_out_d     ;
reg        [10:0]               S_cos_out_d     ;


wire       [47:0]               S_pcout_cos_i   ;
wire       [47:0]               S_dsp_out_i     ;
wire       [47:0]               S_pcout_sin_i   ;
wire       [47:0]               S_dsp_out_q     ;

然后调用上一篇文章中的NCO模块FPGA数字信号处理之verilog实现NCO(代码及仿真):

cm_nco_100 cm_nco_100 (
    .I_sys_clk      (I_sys_clk     ) , /// 工作时钟 100M
    .I_rst_n        (!I_rst_in     ) , /// 复位信号,用来清相位
    .I_phase        (I_phase       ) , /// 初始相位
    .I_freq         (I_freq        ) , /// 频率,步进,1代表1M
    .O_sin_out      (S_sin_out     ) , /// 输出正弦值
    .O_cos_out      (S_cos_out     )   /// 输出余弦值
);

接着打拍并调用乘法器:


always @(posedge I_sys_clk )
    if(I_rst_in)
        begin
            S_data_in_q <= 'd0 ;
            S_sin_out_d <= 'd0 ;
            S_cos_out_d <= 'd0 ;
        end
    else
        begin
            S_data_in_q <= I_data_in_q ;
            S_sin_out_d <= S_sin_out   ;
            S_cos_out_d <= S_cos_out   ;
        end
    
// ============================================================
// (cos*i - sin*q)
// ============================================================
//cos*i
cm_dsp48e1 #(
    .C_DATA_WITH_A      (C_DATA_WITH     ),
    .C_DATA_WITH_B      (11              ),
    .C_DATA_WITH_C      (48              ),
    .C_DATA_WITH_D      (25              )
)
U0_cm_dsp48e1(
    .I_CLK              (I_sys_clk      ) , // clk
    .I_RST              (I_rst_in       ) , // RST
    .I_A                (I_data_in_i    ) , // [29:0] 
    .I_B                (S_cos_out      ) , // [17:0] 
    .I_C                (48'd0          ) , // [47:0] 
    .I_D                (25'd0          ) , // [24:0] 
    .I_PCIN             (48'd0          ) , // [47:0] 只能直连PCOUT
    .I_ALUMODE          (4'd0           ) , // [3:0] 
    .I_INMODE           (5'b00101       ) , // [4:0] 
    .I_OPMODE           (7'b0000101     ) , // [6:0] 
    .O_P                (               ) , // [47:0]
    .O_PCOUT            (S_pcout_cos_i  )   // [47:0] 只能直连PCIN
    );


//Pcin - sin*q
cm_dsp48e1 #(
    .C_DATA_WITH_A      (C_DATA_WITH     ),
    .C_DATA_WITH_B      (11              ),
    .C_DATA_WITH_C      (48              ),
    .C_DATA_WITH_D      (25              )
)
U1_cm_dsp48e1(
    .I_CLK              (I_sys_clk      ) , // clk
    .I_RST              (I_rst_in       ) , // RST
    .I_A                (S_data_in_q    ) , // [29:0] 
    .I_B                (S_sin_out_d    ) , // [17:0] 
    .I_C                (48'd0          ) , // [47:0] 
    .I_D                (25'd0          ) , // [24:0] 
    .I_PCIN             (S_pcout_cos_i  ) , // [47:0] 只能直连PCOUT
    .I_ALUMODE          (4'b0011        ) , // [3:0] 
    .I_INMODE           (5'b00101       ) , // [4:0] 
    .I_OPMODE           (7'b0010101     ) , // [6:0] 
    .O_P                (S_dsp_out_i    ) , // [47:0]
    .O_PCOUT            (               )   // [47:0] 只能直连PCIN
    );
    
    
// ============================================================
// (sin*i + cos*q)
// ============================================================
//sin*i
cm_dsp48e1 #(
    .C_DATA_WITH_A      (C_DATA_WITH     ),
    .C_DATA_WITH_B      (11              ),
    .C_DATA_WITH_C      (48              ),
    .C_DATA_WITH_D      (25              )
)
U2_cm_dsp48e1(
    .I_CLK              (I_sys_clk      ) , // clk
    .I_RST              (I_rst_in       ) , // RST
    .I_A                (I_data_in_i    ) , // [29:0] 
    .I_B                (S_sin_out      ) , // [17:0] 
    .I_C                (48'd0          ) , // [47:0] 
    .I_D                (25'd0          ) , // [24:0] 
    .I_PCIN             (48'd0          ) , // [47:0] 只能直连PCOUT
    .I_ALUMODE          (4'd0           ) , // [3:0] 
    .I_INMODE           (5'b00101       ) , // [4:0] 
    .I_OPMODE           (7'b0000101     ) , // [6:0] 
    .O_P                (               ) , // [47:0]
    .O_PCOUT            (S_pcout_sin_i  )   // [47:0] 只能直连PCIN
    );


//Pcin + cos*q
cm_dsp48e1 #(
    .C_DATA_WITH_A      (C_DATA_WITH     ),
    .C_DATA_WITH_B      (11              ),
    .C_DATA_WITH_C      (48              ),
    .C_DATA_WITH_D      (25              )
)
U3_cm_dsp48e1(
    .I_CLK              (I_sys_clk      ) , // clk
    .I_RST              (I_rst_in       ) , // RST
    .I_A                (S_data_in_q    ) , // [29:0] 
    .I_B                (S_cos_out_d    ) , // [17:0] 
    .I_C                (48'd0          ) , // [47:0] 
    .I_D                (25'd0          ) , // [24:0] 
    .I_PCIN             (S_pcout_sin_i  ) , // [47:0] 只能直连PCOUT
    .I_ALUMODE          (4'b0000        ) , // [3:0] 
    .I_INMODE           (5'b00101       ) , // [4:0] 
    .I_OPMODE           (7'b0010101     ) , // [6:0] 
    .O_P                (S_dsp_out_q    ) , // [47:0]
    .O_PCOUT            (               )   // [47:0] 只能直连PCIN
    );

最后四舍五入后输出:

/// 四合五入输出
always @(posedge I_sys_clk )
    if(I_rst_in)
        begin
            O_data_out_i <= 'd0;
            O_data_out_q <= 'd0;
        end
    else
        begin
            O_data_out_i <= S_dsp_out_i[10+:C_DATA_WITH] + S_dsp_out_i[9];
            O_data_out_q <= S_dsp_out_q[10+:C_DATA_WITH] + S_dsp_out_q[9];
        end


endmodule

 

对代码的详细讲解参考B站视频:

【FPGA数字信号处理之verilog实现数字混频器】 https://www.bilibili.com/video/BV1hg411B7Rb/?share_source=copy_web&vd_source=9736f43bc2eebc284f4fbbe5805247a7


审核编辑 :李倩


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分