Numpy卷积(convolve)似乎在复杂信号上产生了巨大的误差
Numpy convolution (convolve) seems to produce a huge error on complex signals
我注意到 numpy.convolve
在足够复杂的信号上会产生奇怪的结果。这是一个简单的测试示例:
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
def conv_np(x, win):
return np.convolve(x, win, 'valid')
def conv_dot(x, win):
Z = np.asarray( [x[cnt:cnt+win.shape[0]] for cnt in range(x.shape[0]-win.shape[0]+1)] )
return np.dot(Z, win)
# test 1
x = np.repeat([0., 1., 0.], 300)
win = signal.hamming(50)
plt.subplot(2,1,1)
plt.plot( conv_np(x, win) - conv_dot(x, win) )
# test 2
x = np.random.random(size=(10000,))
win = x[4000:5000]
plt.subplot(2,1,2)
plt.plot( conv_np(x, win) - conv_dot(x, win) )
plt.show()
结果如下:
这些图显示了 numpy.convolve
和使用点生成直接实现卷积之间的区别。上面的图是一个简单的信号和 window(一个步骤和一个 Hann window)。底部图是随机信号,window 只是该信号的一部分。
所以对于简单的 signal/window,点积和 numpy
的卷积实现几乎没有区别,但是对于复杂的 signal/window 却有巨大的区别。
由于点积实现可以被认为是基本事实,我将这种差异解释为 numpy
的错误。如果我错了或者是否有办法使 numpy
产生与点积相同的结果,请告诉我。
使用点积正确实现卷积 you need to reflect the kernel。如果将 conv_dot
重新定义为:
def conv_dot(x, win):
Z = [x[cnt:cnt+win.size] for cnt in range(x.size-win.size+1)]
return np.dot(Z, win[::-1]) # the [::-1] is the only real change
你会发现错误现在可以忽略不计了,最多 2e-13
在试验中 运行 我用你的第二个例子做了。
我注意到 numpy.convolve
在足够复杂的信号上会产生奇怪的结果。这是一个简单的测试示例:
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
def conv_np(x, win):
return np.convolve(x, win, 'valid')
def conv_dot(x, win):
Z = np.asarray( [x[cnt:cnt+win.shape[0]] for cnt in range(x.shape[0]-win.shape[0]+1)] )
return np.dot(Z, win)
# test 1
x = np.repeat([0., 1., 0.], 300)
win = signal.hamming(50)
plt.subplot(2,1,1)
plt.plot( conv_np(x, win) - conv_dot(x, win) )
# test 2
x = np.random.random(size=(10000,))
win = x[4000:5000]
plt.subplot(2,1,2)
plt.plot( conv_np(x, win) - conv_dot(x, win) )
plt.show()
结果如下:
这些图显示了 numpy.convolve
和使用点生成直接实现卷积之间的区别。上面的图是一个简单的信号和 window(一个步骤和一个 Hann window)。底部图是随机信号,window 只是该信号的一部分。
所以对于简单的 signal/window,点积和 numpy
的卷积实现几乎没有区别,但是对于复杂的 signal/window 却有巨大的区别。
由于点积实现可以被认为是基本事实,我将这种差异解释为 numpy
的错误。如果我错了或者是否有办法使 numpy
产生与点积相同的结果,请告诉我。
使用点积正确实现卷积 you need to reflect the kernel。如果将 conv_dot
重新定义为:
def conv_dot(x, win):
Z = [x[cnt:cnt+win.size] for cnt in range(x.size-win.size+1)]
return np.dot(Z, win[::-1]) # the [::-1] is the only real change
你会发现错误现在可以忽略不计了,最多 2e-13
在试验中 运行 我用你的第二个例子做了。