里曼的手工艺品scipy.signal.con公司

2024-05-13 04:48:24 发布

您现在位置:Python中文网/ 问答频道 /正文

简短摘要:如何快速计算两个数组的有限卷积?在

问题描述

我试图得到由定义的两个函数f(x),g(x)的有限卷积

finite convolution

为了实现这一点,我对函数进行了离散采样,并将它们转换为长度为steps的数组:

xarray = [x * i / steps for i in range(steps)]
farray = [f(x) for x in xarray]
garray = [g(x) for x in xarray]

然后我尝试使用scipy.signal.convolve函数计算卷积。此函数给出的结果与conv建议的算法here相同。然而,结果与解析解有很大不同。修改算法conv以使用梯形规则,可以得到预期的结果。在

为了说明这一点,我让

^{pr2}$

结果是:

enter image description here

这里Riemann表示一个简单的Riemann和,trapezoidal是使用梯形规则的Riemann算法的改进版本,scipy.signal.convolve是scipy函数,analytical是解析卷积。在

现在让g(x) = x^2 * exp(-x)得到的结果是:

enter image description here

这里的“比率”是从scipy获得的值与分析值的比率。上述结果表明,该问题不能通过重新规范化积分来解决。在

问题

是否可以使用scipy的速度,但保留梯形规则的更好结果,还是必须编写一个C扩展来获得所需的结果?在

一个例子

只需复制并粘贴下面的代码,以查看我遇到的问题。增加steps变量可以使这两个结果更接近一致。我认为这个问题是由于右Riemann和的伪影造成的,因为积分在增大时被高估了,当积分减小时又接近解析解。在

编辑:我现在将原始算法2作为比较,其结果与scipy.signal.convolve函数相同。在

import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import math

def convolveoriginal(x, y):
    '''
    The original algorithm from http://www.physics.rutgers.edu/~masud/computing/WPark_recipes_in_python.html.
    '''
    P, Q, N = len(x), len(y), len(x) + len(y) - 1
    z = []
    for k in range(N):
        t, lower, upper = 0, max(0, k - (Q - 1)), min(P - 1, k)
        for i in range(lower, upper + 1):
            t = t + x[i] * y[k - i]
        z.append(t)
    return np.array(z) #Modified to include conversion to numpy array

def convolve(y1, y2, dx = None):
    '''
    Compute the finite convolution of two signals of equal length.
    @param y1: First signal.
    @param y2: Second signal.
    @param dx: [optional] Integration step width.
    @note: Based on the algorithm at http://www.physics.rutgers.edu/~masud/computing/WPark_recipes_in_python.html.
    '''
    P = len(y1) #Determine the length of the signal
    z = [] #Create a list of convolution values
    for k in range(P):
        t = 0
        lower = max(0, k - (P - 1))
        upper = min(P - 1, k)
        for i in range(lower, upper):
            t += (y1[i] * y2[k - i] + y1[i + 1] * y2[k - (i + 1)]) / 2
        z.append(t)
    z = np.array(z) #Convert to a numpy array
    if dx != None: #Is a step width specified?
        z *= dx
    return z

steps = 50 #Number of integration steps
maxtime = 5 #Maximum time
dt = float(maxtime) / steps #Obtain the width of a time step
time = [dt * i for i in range (steps)] #Create an array of times
exp1 = [math.exp(-t) for t in time] #Create an array of function values
exp2 = [2 * math.exp(-2 * t) for t in time]
#Calculate the analytical expression
analytical = [2 * math.exp(-2 * t) * (-1 + math.exp(t)) for t in time]
#Calculate the trapezoidal convolution
trapezoidal = convolve(exp1, exp2, dt)
#Calculate the scipy convolution
sci = signal.convolve(exp1, exp2, mode = 'full')
#Slice the first half to obtain the causal convolution and multiply by dt
#to account for the step width
sci = sci[0:steps] * dt
#Calculate the convolution using the original Riemann sum algorithm
riemann = convolveoriginal(exp1, exp2)
riemann = riemann[0:steps] * dt

#Plot
plt.plot(time, analytical, label = 'analytical')
plt.plot(time, trapezoidal, 'o', label = 'trapezoidal')
plt.plot(time, riemann, 'o', label = 'Riemann')
plt.plot(time, sci, '.', label = 'scipy.signal.convolve')
plt.legend()
plt.show()

感谢您抽出时间!在


Tags: ofthe函数inforsignaltimerange
2条回答

简答:用C写!在

冗长的回答

使用关于numpy arrays的食谱,我用C重写了梯形卷积方法

  • C代码(performancemodule.C)。在
  • 用于构建代码并使其可从python(pe)调用的设置文件rformancemodulesetup.py). 在
  • 使用C扩展名的python文件(性能测试.py)在

代码应该在下载时通过执行以下操作来运行

  • 调整performancemodule.c中的include路径。在
  • 运行以下命令

    python performancemodulesetup.py建造 python性能测试.py

您可能需要将库文件performancemodule.soperformancemodule.dll复制到与performancetest.py相同的目录中。在

结果和绩效

结果完全一致,如下所示:

Comparison of methods

C方法的性能甚至优于scipy的卷积方法。运行长度为50的10k卷积需要

convolve (seconds, microseconds) 81 349969
scipy.signal.convolve (seconds, microseconds) 1 962599
convolve in C (seconds, microseconds) 0 87024

当然,实现速度比实现快1000倍。在

编辑:这并不能完全解决最初的问题,但对我来说已经足够了。在

或者,对于那些喜欢numpy而不是C的人来说,它将比C实现慢,但是它只是几行。在

>>> t = np.linspace(0, maxtime-dt, 50)
>>> fx = np.exp(-np.array(t))
>>> gx = 2*np.exp(-2*np.array(t))
>>> analytical = 2 * np.exp(-2 * t) * (-1 + np.exp(t))

这看起来像是梯形的(但我没有检查数学)

^{pr2}$

最大绝对误差:

>>> np.max(np.abs(s[:len(analytical)-1] - analytical[1:]))
0.00041657780840698155
>>> np.argmax(np.abs(s[:len(analytical)-1] - analytical[1:]))
6

相关问题 更多 >