使用scipy的弧长的错误结果

时间:2017-09-23 16:25:45

标签: python math scipy

我试图推导出任意曲线的长度。

我从一个简单的例子开始,一个半径为R的圆圈。我得到了错误的结果!

结果似乎与R的真实结果不同,这可能会给问题提供一些暗示。

以下代码:

from scipy.integrate import quad
from scipy.misc import derivative
import numpy as np

r = lambda t: 1
x = lambda t: r(t)*np.cos(t)
Dx = lambda t: derivative(x, t)
y = lambda t: r(t)*np.sin(t)
Dy = lambda t: derivative(y, t)

print(quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, 2*np.pi))

结果

(5.287118128162912, 5.869880279799524e-14)

对于R = 1,其应为2 * pi = 6.28 ...

对于R = 5,它是

(26.435590640814564, 2.9349401398997623e-13)

有什么建议吗?

5 个答案:

答案 0 :(得分:1)

derivative的文档字符串表示"use a central difference formula with spacing dx "dx的默认值为1,这太大了,无法准确逼近导数你的职能。例如,尝试dx=1e-8

使用您的代码,但DxDy已更改为

In [21]: Dx = lambda t: derivative(x, t, dx=1e-8)

In [22]: Dy = lambda t: derivative(y, t, dx=1e-8)

这是我得到的:

In [23]: print(quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, 2*np.pi))
(6.283185278344876, 1.7738885483822232e-08)

答案 1 :(得分:1)

如果您正确实施衍生工具,您将获得预期结果:

from scipy.integrate import quad
from scipy.misc import derivative
import numpy as np

r = lambda t: 1
x = lambda t: r(t)*np.cos(t)
Dx = lambda t: -r(t)*np.sin(t)
y = lambda t: r(t)*np.sin(t)
Dy = lambda t: r(t)*np.cos(t)

print(quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, 2*np.pi))

错误来自函数derivative,它使用中心有限差分公式,如文档this sample chapter of High-Performance Java Persistence所述,默认步长为1,这是很多。此步长的常用值应为1e-5 to 1e-8。如果您强制使用derivative(x, t, dx=1e-5),则代码会生成正确的结果

答案 2 :(得分:0)

我的记忆可能会误导我,但你不需要在你的np.sqrt()函数中输入+1吗?那就是:

print(quad(lambda t: np.sqrt(1 + Dx(t)**2 + Dy(t)**2), 0, 2*np.pi))

答案 3 :(得分:0)

scipy中的派生函数似乎不适用于np.cos()

测试derivative(np.cos, np.pi / 2)时,它在我的电脑上返回0.84147098480789639(实际值应为-1),但我不明白为什么

答案 4 :(得分:0)

您正在将sympy函数与numpy函数混合使用,但它们适用于不同的用途。要充分利用sympy,请使用其cossinpisqrt等版本。如果您这样做,sympy可以在需要下拉到数字工作之前进行更多分析。毕竟,sympy代表“符号Python”。

以下是获得所需内容的纯sympy方式:

from sympy import symbols, sqrt, pi, cos, sin, Derivative, integrate

r, t, x, y, Dx, Dy = symbols('r, t, x, y, Dx, Dy')
r = 1
x, y = r * cos(t), r * sin(t)
Dx, Dy = Derivative(x, t).doit(), Derivative(y, t).doit()
print(integrate(sqrt(Dx**2 + Dy**2), (t, 0, 2*pi)))

结果打印输出

2*pi

这是完全正确的。如果您改为使用r = 5,则打印输出为10*pi,再次完全正确。

如果您需要数字,近似结果,请在打印前将表达式包装在float()中,6.283185307179586 r = 131.41592653589793 r = 5