FPGA实现复信号功率计算

本文介绍了设计并实现了一个复数正弦信号功率检测系统,使用DDS核生成信号,通过FPGA进行功率计算,结果以dBm显示,支持信号幅度可变。设计包括Matlab代码生成、ILA核配置、以及上板验证的过程。

目录

概述

原理

1.信号生成

2.功率计算

代码

仿真

上板验证


概述

        本设计实现了复数正弦信号功率检测系统,该系统在EGO1平台上采用Xilinx Artix-7系列XC7A35T-1CSG324C FPGA。设计的主要目标是在信号频率固定的情况下,允许外部对信号幅度进行可变控制(范围从0.01到1)。最终,系统将检测到的信号功率以dBm为单位进行输出显示,其中满刻度为10dBm。

原理

1.信号生成

  • 使用DDS核生成两路信号,一路cos信号,一路sin信号。初始信号数据宽度7,有符号数,因此最大值为64,满幅度值宽度为16,即32768。
  • 通过matlab生成100个倍率保存到coe文件中,FPGA可以根据按键选择倍率,使信号幅度为32768*(0.01-1)。

2.功率计算

  • 对两路信号采样10000个点,分别平方求和,再除以32768*32768归一化得到总功率。后面要转换成dbm,换算后刚好总功率就是平均功率,因此不用除10000。
  • 将功率转换到dbm进行显示,公式为:

10\lg \tfrac{P(w)}{1000}

  • 这里为了在数码管上显示,因此将计算的dbm值扩大100倍。
  • 因为FPGA算log比较复杂,因此也通过matlab生成对应值,再进行查表。为了保存的lg值没有负数,因此计算1000lg(P*10)的值保存到coe文件中。
  • 满足满刻度为10dbm和用于数码管的显示的dbm值的计算如下:

-3000dbm \leqslant P=1000\lg power-3000\leqslant 1000dbm

代码

1.生成ratedata和logdata的matlab代码

clc
close all

fid = fopen('ratedata.coe','w');
fprintf( fid,'memory_initialization_radix=16;\n');%生成索引
fprintf( fid, 'memory_initialization_vector =\n' );

N = 100; 
r = [0:1:99]; 
s = 2^15/62*0.01*(1+r); %幅值比例

% r = [0:1:9999];
% s = 1000*log10(1+r);  %1000lg转换表
z = round(s);

for k = 1:1:N   
    fprintf(fid,'%x;\n',z(k));
end

fclose(fid);

2.top模块

`timescale 1ns / 1ps

module top(
    input           sys_clk,rst,
    input   [7:0]   sw,
    output  [7:0]   an,sseg,sseg0
    );
    wire    [3:0 ]  dp;
    wire    [32:0]  sum_power;
    wire    [15:0]  i_signal,q_signal;
    wire    [12:0]  dbmdata,t1000logdt;
    wire    [15:0]  ratedt;
    ila_0 ila1(
            .clk            (sys_clk        ),
            .probe0         (sum_power      ),//33
            .probe1         (i_signal       ),
            .probe2         (q_signal       ),
            .probe3         (dbmdata        ),
            .probe4         (sw             )
    );
    ila_1 ila2(
            .clk            (sys_clk        ),
            .probe0         (ratedt         ),//13
            .probe1         (t1000logdt     )//16
    );
//    key_select ukeyd_seg (
//            sys_clk,
//            rst,
//            sw,
//    );
    display udisplay(
            .clk            (sys_clk        ), 
            .reset          (rst            ),
            .data           (sum_power      ),
            .p_select       (an             ),
            .sseg           (sseg           ),
            .sseg0          (sseg0          ),
            .dbm_data       (dbmdata        ),
            .logdt          (t1000logdt     )
    );
    signal_source usgs(
            .s_clk          (sys_clk        ),
            .s_a            (sw             ),
            .i_sig          (i_signal       ),
            .q_sig          (q_signal       ),
            .ratedt         (ratedt         )
    );
    Pow_cal_ctrl power_ins(
            .s_clk          (sys_clk        ),     
            .i_signal       (i_signal       ),  
            .q_signal       (q_signal       ),
            .sw             (sw             ),  
            .s_pow_sum      (sum_power      )
    ); 
endmodule

 两个ila核的设置

3.signal_source模块

`timescale 1ns / 1ps

module signal_source(
    input           s_clk,
    input   [7:0 ]  s_a,
    output  [15:0]  i_sig,q_sig,ratedt
    );
    
    reg     [13:0]  s_cnt = 0;
    always @(posedge s_clk)
    begin   
        if(s_cnt == 9999) //serve as the addr
            s_cnt <= 'd0;
        else
            s_cnt <= s_cnt + 1;
    end
    
    reg s_syn_10ms;   
    always @(posedge s_clk)
    begin
        if(s_cnt == 101)
            s_syn_10ms <= 1'b1;
        else
            s_syn_10ms <= 1'b0;
    end
    
    wire    [6:0]   s_srci,s_srcq;
    wire            svalid,cvalid; 
    src_i is(
        .aclk                  (s_clk       ),                     //: IN STD_LOGIC;
        .m_axis_data_tvalid    (svalid      ),                     //: OUT STD_LOGIC;
        .m_axis_data_tdata     (s_srci      ),                     //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
        .m_axis_phase_tvalid   (            ),                     //: OUT STD_LOGIC;
        .m_axis_phase_tdata    (            )                      //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
     );
    src_q qc(
        .aclk                  (s_clk       ),                     //: IN STD_LOGIC;
        .m_axis_data_tvalid    (cvalid      ),                     //: OUT STD_LOGIC;
        .m_axis_data_tdata     (s_srcq      ),                     //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
        .m_axis_phase_tvalid   (            ),                     //: OUT STD_LOGIC;
        .m_axis_phase_tdata    (            )                      //: OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
     );
     
    reg     [15:0]  temp_si,temp_sq,temp1,temp2;    
    wire    [15:0]  rate;
    assign ratedt = rate;
    always @ * begin                                            //信号位宽扩展
        if(s_srci[6])
            temp1 = {9'b1_1111_1111,s_srci};
        else
            temp1 = {9'b0_0000_0000,s_srci};
        if(s_srcq[6])
            temp2 = {9'b1_1111_1111,s_srcq};
        else
            temp2 = {9'b0_0000_0000,s_srcq};
    end
    src_ratedata ins_ratedata(
            .a                  (s_a         ),                 //: IN STD_LOGIC_VECTOR(13 DOWNTO 0);
            .clk                (s_clk       ),                 //: IN STD_LOGIC;
            .qspo               (rate        )                  //: OUT STD_LOGIC_VECTOR(12 DOWNTO 0)
    );         
    always @ * begin
         temp_si = temp1*rate;
         temp_sq = temp2*rate;       
     end 
    assign i_sig = temp_si;
    assign q_sig = temp_sq;
endmodule

 i路DDS核的设置(未截图的部分默认设置)。q路只需要把output selection改成sine,其它的和i路设置一样。注意ip核名称。

rom核设置:

        Depth是数据深度,rate的数据个数为100个,所以设置为128;logdata的个数为10000个,所以设置为16384。

        Data Width是数据宽度,rate的为16,logdatade 宽度为13(最大值为4000,够用了)。

        最后一步的路径要设置为对应的coe文件路径

 

4.Pow_cal_ctrl模块

`timescale 1ns / 1ps

module Pow_cal_ctrl(
    input               s_clk,     
    input  [15:0]       i_signal,  
    input  [15:0]       q_signal,
    input  [7:0 ]       sw,
    output [32:0]       s_pow_sum 
    );
    wire            s_syn_flag;
    reg             s_syn_10ms;
    reg     [13:0]  s_cnt = 0;
    wire            reset;
    reg             S_delay;
    
    always@(posedge s_clk)
        S_delay <= sw;
    assign reset = S_delay ^ sw;
    
    always @(posedge s_clk,posedge reset)
    begin     
        if(s_cnt == 9999 || reset) //serve as the addr
            s_cnt <= 'd0;
        else
            s_cnt <= s_cnt + 1;
    end
    always @(posedge s_clk)
    begin
        if(s_cnt == 101)
            s_syn_10ms <= 1'b1;
        else
            s_syn_10ms <= 1'b0;
    end
    Pow_cal    ins_pow_cal(
            /*input            */ . i_clk      (s_clk           ),
            /*input            */ . i_syn_10ms (s_syn_10ms      ),
            /*input [15:0]     */ . i_di       (i_signal        ),
            /*input [15:0]     */ . i_dq       (q_signal        ),
                                  . reset      (reset           ),  
            /*output           */ . o_syn_flag (s_syn_flag      ),
            /*output reg [32:0]*/ . o_pow_sum  (s_pow_sum       )
        );
endmodule

5.Pow_cal模块

`timescale 1ns / 1ps

module Pow_cal(
    input              i_clk      ,
    input              i_syn_10ms ,
    input       [15:0] i_di       ,
    input       [15:0] i_dq       ,
    input              reset      ,
    output reg         o_syn_flag ,
    output reg [32:0]  o_pow_sum
    );

    reg               s_dsp_sel     ;
    reg  [15:0]       s_di_r0       ;
    reg  [15:0]       s_dq_r0       ;
    reg  [11:0]       s_syn_10ms = 0;
    wire [47:0]       s_pouti       ;
    wire [47:0]       s_poutq       ;
    reg  [31:0]       sum_i,sum_q   ;
    reg               s_ce    = 0   ; 
    wire [32:0]       s_adder_p     ; 
    reg  [32:0]       s_pow_sum     ;


    always @(posedge i_clk)
    begin
        s_di_r0 <= i_di;
        s_dq_r0 <= i_dq;
    end
    
    always @(posedge i_clk)
    begin
        if(i_syn_10ms)
            s_dsp_sel <= 1'b0; //the first num per 10ms
        else
            s_dsp_sel <= 1'b1; //acc
    end
    
    genvar i;
    generate
    begin
            for(i = 0;i < 12;i = i + 1)
            begin
                always @(posedge i_clk)
                begin
                    if(0)
                        s_syn_10ms <= 0;
                    else begin
                        if(i == 0)
                        begin
                            s_syn_10ms[0] <= i_syn_10ms;
                        end
                        else
                        begin
                            s_syn_10ms[i] <= s_syn_10ms[i-1];
                        end
                   end
                end
            end
    end
    endgenerate
    
    //**dsp mode : 0 -> A*B+C
    //**         : 1 -> A*B+P
    //sum(i^2)_10ms
     pow_cal_dsp ins_pow_cal_i(
        .CLK (i_clk                          ), //: IN STD_LOGIC;
        .SEL (s_dsp_sel                      ), //: IN STD_LOGIC_VECTOR(0 DOWNTO 0);endmodule
        .A   ({
  {2{s_di_r0[15]}},s_di_r0}     ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
        .B   ({
  {2{s_di_r0[15]}},s_di_r0}     ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
        .C   ('d0                            ), //: IN STD_LOGIC_VECTOR(47 DOWNTO 0);
        .P   (s_pouti                        )  //: OUT STD_LOGIC_VECTOR(47 DOWNTO 0)
      );
    
    //sum(q^2)_10ms
     pow_cal_dsp ins_pow_cal_q(
        .CLK (i_clk                          ), //: IN STD_LOGIC;
        .SEL (s_dsp_sel                      ), //: IN STD_LOGIC_VECTOR(0 DOWNTO 0);endmodule
        .A   ({
  {2{s_dq_r0[15]}},s_dq_r0}     ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
        .B   ({
  {2{s_dq_r0[15]}},s_dq_r0}     ), //: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
        .C   ('d0                            ), //: IN STD_LOGIC_VECTOR(47 DOWNTO 0);
        .P   (s_poutq                        )  //: OUT STD_LOGIC_VECTOR(47 DOWNTO 0)
      );
      
    //sum(i^2)_10ms + sum(q^2)_10ms 
    i_add_q ins_i_add_q(
         .A   (sum_i                         ), //: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
         .B   (sum_q                         ), //: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
         .CLK (i_clk                         ), //: IN STD_LOGIC;
         .CE  (s_ce                          ), //: IN STD_LOGIC; 
         .S   (s_adder_p                     )  //: OUT STD_LOGIC_VECTOR(32 DOWNTO 0)
       ); 
    
     always @(posedge i_clk)
     begin
         o_syn_flag <= 1'b0      ; 
         if(s_syn_10ms[3])                      //the last number of acc mode(A*B+P)
         begin
             sum_i <= s_pouti[14+:32];
             sum_q <= s_poutq[14+:32];          //等于除以2^14
             s_ce  <= 1'b1           ;          //adder on 
         end
         
         if(s_syn_10ms[6])
         begin
             s_ce       <= 1'b0      ;          //adder off,low pow mode
             s_pow_sum  <= s_adder_p ;
             //o_syn_flag <= 1'b1      ;        //last 1 clk
         end
         
         if(s_syn_10ms[11])
         begin
             o_pow_sum  <= s_pow_sum >> 16;     //再除以2^16
             o_syn_flag <= 1'b1        ;        //last 1 clk
         end
     end  
 endmodule

DSP核设置

adder核设置

 6.display模块 

`timescale 1ns / 1ps

module display(    
    input                   clk,reset,
    input       [32:0   ]   data,
    output reg  [7:0    ]   p_select,
    output reg  [7:0    ]   sseg,sseg0,
    output reg  [12:0   ]   dbm_data,
    output      [12:0   ]   logdt 
    );
    
    localparam          N = 19,
                        scale = 3000;                              
    reg                 dp;
    reg     [N-1:0  ]   regN;
    reg     [7:0    ]   hex_in;
    reg     [7:0    ]   d_seg1,d_seg2,d_seg3,d_seg4,d_seg5,d_seg6,d_seg7,d_seg8;
    reg     [12:0   ]   temp;
    wire    [12:0   ]   log_data;
    
    //对输入100 MHz/时钟进行分频(100 MHz/2^16)    
    always @(posedge clk, negedge reset) begin
        if (!reset)
            regN <= 0;           
        else 
            regN <= regN + 1;   
    end
       
    src_logdata ins_logdata(
        .a        (data[15:0]   ),                  //: IN STD_LOGIC_VECTOR(13 DOWNTO 0);
        .clk      (clk          ),                  //: IN STD_LOGIC;
        .qspo     (log_data     )                   //: OUT STD_LOGIC_VECTOR(12 DOWNTO 0)
    );
    assign logdt = log_data;
    
    //计算的dbm值是实际的100倍,为了显示数据保留2位小数 
    //x扩大10倍保证从表中查的功率为非负,计算时在减去扩大的倍数1000,1000lgx-1000-2000
    always @ * begin
        dbm_data = log_data-scale;
    end
    always @ * begin
        if(dbm_data[12]) begin
            temp = {1'b0,~dbm_data[11:0]}+1;
            d_seg1 = temp % 10;
            d_seg2 = (temp /10) % 10;
            d_seg3 = (temp / 100) % 10;
            d_seg4 = temp /1000;
            d_seg5 = 8'b0000_1111;
            d_seg6 = 8'b1111_1111;
            d_seg7 = 8'b1111_1111;
            d_seg8 = 8'b1111_1111;
        end    
        else begin
            d_seg1 = dbm_data % 10;
            d_seg2 = (dbm_data /10) % 10;
            d_seg3 = (dbm_data / 100) % 10;
            d_seg4 = dbm_data /1000;
            d_seg5 = 8'b1111_1111;
            d_seg6 = 8'b1111_1111;
            d_seg7 = 8'b1111_1111;
            d_seg8 = 8'b1111_1111;
        end
    end    
    
    always @ * begin
        if(!reset) begin
            p_select = 0;
            hex_in = 0;
            dp = 0;
        end else begin
            case(regN[N-1:N-3])                             //18:16
                3'd0:begin
                        p_select = 8'b0000_0001;
                        hex_in = d_seg1;
                        dp = 0;
                    end      
                3'd1:begin
                        p_select = 8'b0000_0010;
                        hex_in = d_seg2;
                        dp = 0;
                    end
                3'd2:begin
                        p_select = 8'b0000_0100;
                        hex_in = d_seg3;
                        dp = 1;
                    end
                3'd3:begin
                        p_select = 8'b0000_1000;
                        hex_in = d_seg4;
                        dp = 0;
                    end
                3'd4:begin
                        p_select = 8'b0001_0000;
                        hex_in = d_seg5;
                        dp = 0;
                    end
                3'd5:begin
                        p_select = 8'b0000_0000;
                        hex_in = d_seg6;
                        dp = 0;
                    end
                3'd6:begin
                        p_select = 8'b0000_0000;
                        hex_in = d_seg7;
                        dp = 1;
                    end    
                default:begin
                        p_select = 8'b0000_0000;
                        hex_in = d_seg8;
                        dp = 0;
                    end
            endcase
       end
    end
    
    always @ *  begin
        case (hex_in)
            4'h0: sseg[6:0] = ~7'b0000001;
            4'h1: sseg[6:0] = ~7'b1001111;
            4'h2: sseg[6:0] = ~7'b0010010;
            4'h3: sseg[6:0] = ~7'b0000110;
            4'h4: sseg[6:0] = ~7'b1001100;
            4'h5: sseg[6:0] = ~7'b0100100;
            4'h6: sseg[6:0] = ~7'b0100000;
            4'h7: sseg[6:0] = ~7'b0001111;
            4'h8: sseg[6:0] = ~7'b0000000;
            4'h9: sseg[6:0] = ~7'b0000100;
            4'ha: sseg[6:0] = ~7'b0001000;
            4'hb: sseg[6:0] = ~7'b1100000;
            4'hc: sseg[6:0] = ~7'b0110001;
            4'hd: sseg[6:0] = ~7'b1000010;
            4'he: sseg[6:0] = ~7'b0110000;
            4'hf: sseg[6:0] = 7'b000_0001;                      //4'hf,负号亮
            default:sseg[6:0] = 7'b000_0000;                    //全不亮
        endcase  
        sseg[7] = dp;
        sseg0 = sseg;
    end
endmodule

 

7.tb_top测试模块

`timescale 1ns / 1ps

module tb_top(

    );
    reg             sys_clk,rst;
    wire    [7:0]   d_seg,d_seg0,p_select;
    reg     [7:0]   sw,rate;
    
    initial 
    begin
        sys_clk = 0;
        sw = 0;
        rst = 0;
        #10 rst = 1; 
    end
    always #5 sys_clk = ~sys_clk;
    always #5000_00 begin
        if(sw == 5)
            sw = 0;
        else
            sw = sw + 1;
        if(sw == 1)
            rate = 9;
        else if(sw == 2)
            rate = 99;
        else
            rate =sw;
    end
    
    top utop(
        .sys_clk    (sys_clk    ),
        .rst        (rst        ),      
        .sw         (rate       ),         
        .an         (p_select   ),
        .sseg       (d_seg      ),
        .sseg0      (d_seg0     )
    );
endmodule

仿真

上板验证

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值