我需要(数字地)计算函数的一阶和二阶导数,我试图同时使用splrep
和UnivariateSpline
来创建样条函数,以便插入函数衍生物。
然而,对于大小为10 ^ -1或更低且(快速)振荡的函数,样条曲线表示本身似乎存在固有问题。
作为示例,请考虑以下代码在区间(0,6 * pi)上创建正弦函数的样条线表示(因此函数仅振荡三次):
import scipy
from scipy import interpolate
import numpy
from numpy import linspace
import math
from math import sin
k = linspace(0, 6.*pi, num=10000) #interval (0,6*pi) in 10'000 steps
y=[]
A = 1.e0 # Amplitude of sine function
for i in range(len(k)):
y.append(A*sin(k[i]))
tck =interpolate.UnivariateSpline(x, y, w=None, bbox=[None, None], k=5, s=2)
M=tck(k)
以下是M = A = 1.e0且A = 1.e-2
的结果http://i.imgur.com/uEIxq.png幅度= 1
http://i.imgur.com/zFfK0.png幅度= 1/100
显然,样条线创建的插值函数完全不正确!第二张图甚至没有振荡正确的频率。
有没有人对此问题有任何见解?或者知道在numpy / scipy中创建样条曲线的另一种方法?
干杯, 罗里
答案 0 :(得分:8)
<击> 我猜你的问题是由于别名造成的。 击>
你的例子中x
是什么? 击>
如果您插入的x
值的间距小于原始点,则您将固有地丢失频率信息。这完全独立于任何类型的插值。它是下采样中固有的。
击>
没关系上面的别名。它不适用于这种情况(虽然我仍然不知道你的例子中有x
...
我刚刚意识到,当您使用非零平滑因子(s
)时,您正在评估原始输入点的点。
根据定义,平滑不会完全符合数据。请尝试改为s=0
。
作为一个简单的例子:
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
x = np.linspace(0, 6.*np.pi, num=100) #interval (0,6*pi) in 10'000 steps
A = 1.e-4 # Amplitude of sine function
y = A*np.sin(x)
fig, axes = plt.subplots(nrows=2)
for ax, s, title in zip(axes, [2, 0], ['With', 'Without']):
yinterp = interpolate.UnivariateSpline(x, y, s=s)(x)
ax.plot(x, yinterp, label='Interpolated')
ax.plot(x, y, 'bo',label='Original')
ax.legend()
ax.set_title(title + ' Smoothing')
plt.show()
您只清楚地看到低幅度平滑效果的原因是由于平滑因子的定义方式。有关详细信息,请参阅scipy.interpolate.UnivariateSpline
的文档。
即使幅度较高,如果使用平滑,插值数据也不会与原始数据匹配。
例如,如果我们只是在上面的代码示例中将幅度(A
)更改为1.0
,我们仍然会看到平滑效果......
答案 1 :(得分:4)
问题在于为s
参数选择合适的值。它的值取决于数据的缩放。
仔细阅读文档,可以推断出应该在s = len(y) * np.var(y)
附近选择参数,即数据点数*方差。以s = 0.05 * len(y) * np.var(y)
为例,给出了一个平滑样条曲线,它不依赖于数据的缩放或数据点的数量。
编辑:s
的合理值当然也取决于数据中的噪音水平。文档似乎建议在s
范围内选择(m - sqrt(2*m)) * std**2 <= s <= (m + sqrt(2*m)) * std**2
,其中std
是与您想要平滑的“噪音”相关联的标准偏差。