在Python中四舍五入非常小/接近零的复数值
考虑以下这个序列/信号:
import numpy as np
from scipy.fft import fft
# %% Discrete data
x = np.array([0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875,
0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875, 0.7966875])
我定义了一个函数来计算离散傅里叶变换(DFT):
def DFT(x):
N = len(x)
n = np.arange(0, N)
k = n.reshape((N, 1))
omega = 2*np.pi*k/N
e = np.exp(-1j*omega*n)
X = np.dot(x, e)
X_round = np.round(X, 6)
return X, X_round, N, n
X, X_round, N, n = DFT(x)
在这里,我们的 X
对于非零频率的值非常小(这很正常,因为信号 x
没有变化)。然后,我尝试用 np.round(X, 6)
来四舍五入,结果是:
array([38.241+0.j, -0. +0.j, -0. -0.j, -0. -0.j, 0. -0.j,
0. +0.j, -0. -0.j, 0. -0.j, -0. +0.j, -0. -0.j,
-0. -0.j, -0. -0.j, -0. +0.j, 0. -0.j, -0. -0.j,
-0. -0.j, -0. -0.j, 0. -0.j, 0. -0.j, 0. -0.j,
0. +0.j, 0. +0.j, -0. +0.j, -0. +0.j, 0. +0.j,
-0. -0.j, 0. +0.j, -0. +0.j, -0. -0.j, -0. -0.j,
-0. -0.j, 0. -0.j, 0. -0.j, 0. -0.j, -0. -0.j,
-0. -0.j, 0. -0.j, 0. -0.j, 0. -0.j, 0. +0.j,
-0. +0.j, -0. -0.j, 0. -0.j, -0. +0.j, -0. -0.j,
0. +0.j, 0. -0.j, 0. -0.j])
但是,如果我尝试计算 X_round
的角度,使用 X_round_angle = np.angle(X_round)
,结果并不是我预期的零(你可以试试使用 scipy 的 fft
函数)。这是 X_round_angle
的输出:
array([ 0. , 3.14159265, -3.14159265, -3.14159265, -0. ,
0. , -3.14159265, -0. , 3.14159265, -3.14159265,
-3.14159265, -3.14159265, 3.14159265, -0. , -3.14159265,
-3.14159265, -3.14159265, -0. , -0. , -0. ,
0. , 0. , 3.14159265, 3.14159265, 0. ,
-3.14159265, 0. , 3.14159265, -3.14159265, -3.14159265,
-3.14159265, -0. , -0. , -0. , -3.14159265,
-3.14159265, -0. , -0. , -0. , 0. ,
3.14159265, -3.14159265, -0. , 3.14159265, -3.14159265,
0. , -0. , -0. ])
使用 np.angle(fft(x))
可以返回所有频率的正确相位值为零。我该如何修正我的 DFT
函数呢?
编辑:补充一下答案,我找到这个 链接,它也做了同样的事情:
当 Im(X) 和 Re(X) 都等于零时, 相位值是未定义的。可以将其设为零,正如我们下面将要做的,这样相位谱会更容易阅读。
1 个回答
2
你观察到的行为其实并不奇怪,因为对于复数0来说,无法定义一个相位角。np.angle()
返回的结果是0、π和-π的混合,这些都是正确的。
官方文档中提到:
虽然复数0的角度是未定义的,但numpy.angle(0)会返回0。
如果我们按照文档中的说法进行测试,结果确实是0。然而,当我们把参数z
从0(整数)改成0.0(浮点数)时,你看到的行为就会发生变化。这种情况其实是一个未记录的边缘案例,所以我们不能指望它会有一致的表现。我们可以测试不同组合的正负0.0,是否带有0.0j,结果会很混乱。
从数学上讲,这一切都是合理的,但你可能希望所有类型的零都有一致的相位(比如在绘图时)。在这种情况下,我建议用一个简单的方法把那些不合适的值替换成0。
phase = np.angle(X_round)
phase = np.array([0.0 if np.abs(a)<0.000001 else theta for a, theta in zip(X_round, phase)])