使用希尔伯特变换计算两个时间序列之间的相位角时出错

问题描述 投票:0回答:1

我正在尝试计算两个实数时间序列之间的相位角。为了检查我的函数是否正常运行,我创建了两个相位为 17 度的正弦波。然而,当我计算这两个正弦波之间的相位角时,我没有得到 17 度。这是我的脚本:

import numpy as np
from scipy.signal import hilbert
import matplotlib.pyplot as plt

def coupling_angle_hilbert(x, y, datatype, center=True, pad=True):
    """
    Compute the phase angle between two time series using the Hilbert transform.

    Parameters:
    - x: numpy array
        Time series data for the first signal.
    - y: numpy array
        Time series data for the second signal.
    - center: bool, optional
        If True, center the amplitude of the data around zero. Default is True.
    - pad: bool, optional
        If True, perform data reflection to address issues arising with data distortion. Default is True.
    - unwrap: bool, optional
        If True, unwrap the phase angle to avoid phase wrapping. Default is True.

    Returns:
    - phase_angle: numpy array
        Phase angle between the two signals.
    """
    
    # Convert input data to radians if specified as degrees
    if datatype.lower().strip() == 'degs':
        x = np.radians(x)
        y = np.radians(y)
    
    # Center the signals if the 'center' option is enabled    
    if center:
       # Adjust x to be centered around zero: subtract minimum, then offset by half the range
        x = x - np.min(x) - ((np.max(x) - np.min(x))/2)
        
        # Adjust y to be centered around zero: subtract minimum, then offset by half the range
        y = y - np.min(y) - ((np.max(y) - np.min(y))/2)

    # Reflect and pad the data if padding is enabled
    if pad:
        # Number of padding samples equal to signal length
        # Ensure that the number of pads is even
        npads = x.shape[0] // 2 * 2  # Ensure npads is even

        # Reflect data at the beginning and end to create padding for 'x' and 'y'
        x_padded = np.concatenate((x[:npads][::-1], x, x[-npads:][::-1]))
        y_padded = np.concatenate((y[:npads][::-1], y, y[-npads:][::-1]))
       
    else:
        # If padding not enabled, use original signals without modification
        x_padded = x
        y_padded = y
                
    # Apply the Hilbert transform to the time series data
    hilbert_x = hilbert(x_padded)
    hilbert_y = hilbert(y_padded)

    # Calculate the phase of each signal by using arctan2 on imaginary and real parts
    phase_angle_x = np.arctan2(hilbert_x.imag, x_padded)
    phase_angle_y = np.arctan2(hilbert_y.imag, y_padded)
    
    # Calculate the phase difference between y and x    
    phase_angle = phase_angle_y - phase_angle_x   

    # Trim the phase_angle to match the shape of x or y
    if pad:
        # Remove initial and ending padding to return only the original signal's phase angle difference
        phase_angle = phase_angle[npads:npads + x.shape[0]]
    
    return phase_angle 

# input data
angles = np.radians(np.arange(0, 360, 1))
phase_offset = np.radians(17)

wav1 = np.sin(angles)
wav2 = np.sin(angles + phase_offset)

# Compute phase_angle usig Hilbert transform    
ca_hilbert =  coupling_angle_hilbert(wav1, 
                                    wav2,
                                    'rads', 
                                    center=True, 
                                    pad=True)

plt.plot(np.degrees(ca_hilbert))
plt.show()

提前感谢您的帮助。

python scipy signal-processing
1个回答
0
投票

您可以使用

arctan2(hilbert.imag, x)
代替
[np.angle()][1]
,它返回复数的参数(角度)(始终在
[-π, π]
范围内)。它本质上是对复数
arctan2(y, x)
执行
x + iy

此外,在

phase_angle = phase_y - phase_x
之后,我们需要再次确保它位于 [-π, π] 中,因此我们按照文档执行
phase_angle = np.angle(np.exp(1j * phase_angle))

因此,你的函数就变成了:

import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import hilbert


def coupling_angle_hilbert(x, y, datatype="rads", center=True, pad=True):
    """
    Compute the phase angle between two time series using the Hilbert transform.

    Parameters:
    - x: numpy array
        Time series data for the first signal.
    - y: numpy array
        Time series data for the second signal.
    - datatype: str, optional
        Specify if input is in 'rads' or 'degs'. Default is 'rads'.
    - center: bool, optional
        If True, center the amplitude of the data around zero. Default is True.
    - pad: bool, optional
        If True, perform data reflection to address issues arising with data distortion. Default is True.

    Returns:
    - phase_angle: numpy array
        Phase angle between the two signals in radians.
    """
    if datatype.lower().strip() == "degs":
        x = np.radians(x)
        y = np.radians(y)

    # Center the signals if the 'center' option is enabled
    if center:
        # Adjust x to be centered around zero: subtract minimum, then offset by half the range
        x = x - np.min(x) - ((np.max(x) - np.min(x)) / 2)

        # Adjust y to be centered around zero: subtract minimum, then offset by half the range
        y = y - np.min(y) - ((np.max(y) - np.min(y)) / 2)

    # Reflect and pad the data if padding is enabled
    if pad:
        # Number of padding samples equal to signal length
        # Ensure that the number of pads is even
        npads = x.shape[0] // 2 * 2  # Ensure npads is even

        # Reflect data at the beginning and end to create padding for 'x' and 'y'
        x_padded = np.concatenate((x[:npads][::-1], x, x[-npads:][::-1]))
        y_padded = np.concatenate((y[:npads][::-1], y, y[-npads:][::-1]))

    else:
        # If padding not enabled, use original signals without modification
        x_padded = x
        y_padded = y

    # Apply the Hilbert transform to the time series data
    hilbert_x = hilbert(x_padded)
    hilbert_y = hilbert(y_padded)

    # Calculate the instantaneous phases
    phase_x = np.angle(hilbert_x)
    phase_y = np.angle(hilbert_y)

    # Calculate the phase difference
    phase_angle = phase_y - phase_x

    # Ensure phase angle is in [-π, π]
    phase_angle = np.angle(np.exp(1j * phase_angle))

    # Trim the phase_angle to match the shape of x or y
    if pad:
        # Remove initial and ending padding to return only the original signal's phase angle difference
        phase_angle = phase_angle[npads : npads + x.shape[0]]

    return phase_angle

这样,我得到

17.41
作为相位差。

© www.soinside.com 2019 - 2024. All rights reserved.