我正在尝试计算两个实数时间序列之间的相位角。为了检查我的函数是否正常运行,我创建了两个相位为 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()
提前感谢您的帮助。
您可以使用
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
作为相位差。