> 技术文档 > 基于FPGA的过零检测算法测量两路信号相位差(verilog语言)_fpga计算信号相位

基于FPGA的过零检测算法测量两路信号相位差(verilog语言)_fpga计算信号相位

        本文介绍了使用过零检测算法测量相位差的方法,不适用于测量精度要求较高的场合。

        过零检测原理如下图所示,我们使用DDS IP核产生两路同频不同相的正弦信号,输出数据位宽为16位。假设正弦信号无直流偏置,当正弦信号sig1前一个时刻的值小于0,后一个时刻的值大于0时,判断为信号上升沿,此时将过零检测信号sig1_zero拉高一个时钟周期。同理,当检测到sig2信号的上升沿时,也拉高sig2_zero一个时钟周期。通过计数sig1_zero自身两个脉冲之间的时钟周期数,即可得到正弦信号sig1的周期T;而通过计数sig1_zero和sig2_zero之间的时钟周期数,即可得两信号上升沿的时间差Td。

        我们知道:如果两个信号之间相差一个周期T,那么可以认为相位差为360°(0°);而两信号之间相差半个周期,则相位差为180°。故有eq?%5Cfrac%7BT%7D%7BTd%7D%3D%5Cfrac%7B360%7D%7Bdeg%7D,即

                                        ​​​​​​​        ​​​​​​​        ​​​​​​​        eq?deg%3D360*%5Cfrac%7BTd%7D%7BT%7D

其中,deg为两信号的相位差(°),T为周期,Td为两个信号的过零检测信号的时间差。

基于FPGA的过零检测算法测量两路信号相位差(verilog语言)_fpga计算信号相位

       那相信有同学会问,那如果正弦信号是有直流偏置的情况呢?对于任意16位正弦信号,其最高位等于1,低15位全部为0时,此时幅值为峰值的一半。所以,在写给过零检测信号赋值代码的时候,只要用信号的最高位来判断就可以了。如 if((sig1[15]==0)&&sig1_reg[15]==1) sig1_zero==1;这样对于任意正弦信号,我们都可以用此方式来得到过零检测信号了。

        原理很简单,我们直接附上过零检测相位差的verilog代码。

`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company: // Engineer: 树下友人// // Create Date: 2024/10/21 09:51:08// Design Name: // Module Name: phase_meter// Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //////////////////////////////////////////////////////////////////////////////////module phase_meter( input wire aclk, input wire rstn, input wire sig_base, input wire sig_test, output wire [15:0] phase_out, output wire [15:0] period_out ); reg[15:0] sig_base_reg; reg[15:0] sig_test_reg; reg sig_base_zero; reg sig_test_zero; //参考信号边沿检测 always@(posedge aclk) begin sig_base_reg<=sig_base;//用寄存器寄存信号,多打一拍 sig_test_reg<=sig_test; if(sig_base==1\'b1 && sig_base_reg==1\'b0) sig_base_zero<=1\'b1;//检测到信号上升边沿 else sig_base_zero<=1\'b0;  if(sig_test==1\'b1 && sig_test_reg==1\'b0) sig_test_zero<=1\'b1;//检测到信号上升边沿  else sig_test_zero<=1\'b0; end reg [31:0] phase_cnt_reg; reg [31:0] phase_out_reg; reg [31:0] period_cnt_reg; reg [31:0] period_out_reg; always@(posedge aclk) if(!rstn)begin phase_cnt_reg <= 32\'b0; period_cnt_reg <= 32\'b0; end else begin if(sig_base_zero==1\'b1)begin  phase_cnt_reg <= 32\'b0; period_cnt_reg<= 32\'b0; period_out_reg <= period_cnt_reg; end else begin phase_cnt_reg <= phase_cnt_reg + 32\'b1; period_cnt_reg <= period_cnt_reg + 32\'b1; end if(sig_test_zero==1\'b1)begin  phase_out_reg <= phase_cnt_reg; end end assign phase_cnt=phase_cnt_reg; assign phase_out=phase_out_reg+32\'b1; assign period_cnt=period_cnt_reg; assign period_out=period_out_reg+32\'b1;endmodule

        代码里面的信号命名sig_base(sig1)和sig_test(sig2)。代表一个为基准信号,一个为测量信号。上述代码中,wire [15:0] phase_out代表的是sig1_zero和sig2_zero两个过零信号的时间差Td。wire[15:0] period_out代表的是sig1_zero和下一次sig1_zero拉高时的时间差,即sig1信号的周期T。得到这两个值后,根据公式计算即可得到两个信号的相位差deg°。