我试图推导出任意曲线的长度。
我从一个简单的例子开始,一个半径为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)
有什么建议吗?
答案 0 :(得分:1)
derivative
的文档字符串表示"use a central difference formula with spacing
dx "
,dx
的默认值为1,这太大了,无法准确逼近导数你的职能。例如,尝试dx=1e-8
。
使用您的代码,但Dx
和Dy
已更改为
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
,请使用其cos
,sin
,pi
,sqrt
等版本。如果您这样做,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 = 1
和31.41592653589793
r = 5