简体   繁体   English

scipy.odeint奇怪的行为

[英]scipy.odeint strange behavior

Here is my code to solve differential equation dy / dt = 2 / sqrt(pi) * exp(-x * x) to plot erf(x). 这是我的代码,用于求解微分方程dy / dt = 2 / sqrt(pi)* exp(-x * x)以绘制erf(x)。

import matplotlib.pyplot as plt
from scipy.integrate import odeint
import numpy as np
import math


def euler(df, f0, x):
    h = x[1] - x[0]
    y = [f0]
    for i in xrange(len(x) - 1):
        y.append(y[i] + h * df(y[i], x[i]))
    return y


def i(df, f0, x):
    h = x[1] - x[0]
    y = [f0]
    y.append(y[0] + h * df(y[0], x[0]))
    for i in xrange(1, len(x) - 1):
        fn = df(y[i], x[i])
        fn1 = df(y[i - 1], x[i - 1])
        y.append(y[i] + (3 * fn - fn1) * h / 2)
    return y


if __name__ == "__main__":
    df = lambda y, x: 2.0 / math.sqrt(math.pi) * math.exp(-x * x)
    f0 = 0.0
    x = np.linspace(-10.0, 10.0, 10000)

    y1 = euler(df, f0, x)
    y2 = i(df, f0, x)
    y3 = odeint(df, f0, x)

    plt.plot(x, y1, x, y2, x, y3)
    plt.legend(["euler", "modified", "odeint"], loc='best')
    plt.grid(True)
    plt.show()

And here is a plot: 这是一个情节:

情节

Am I using odeint in a wrong way or it's a bug? 我是以错误的方式使用odeint还是错误?

Notice that if you change x to x = np.linspace(-5.0, 5.0, 10000) , then your code works. 请注意,如果将x更改为x = np.linspace(-5.0, 5.0, 10000) ,则代码可以正常工作。 Therefore, I suspect the problem has something to do with exp(-x*x) being too small when x is very small or very large. 因此,我怀疑当x非常小或非常大时,问题与exp(-x*x)太小有关。 [Total speculation: Perhaps the odeint (lsoda) algorithm adapts its stepsize based on values sampled around x = -10 and increases the stepsize in such a way that values around x = 0 are missed?] [总推测:也许odeint(lsoda)算法根据围绕x = -10采样的值调整其步长,并以这样的方式增加步长,使x = 0左右的值丢失?]

The code can be fixed by using the tcrit parameter, which tells odeint to pay special attention around certain critical points. 可以使用tcrit参数修复代码,该参数告诉odeint在某些关键点周围要特别注意。

So, by setting 所以,通过设置

y3 = integrate.odeint(df, f0, x, tcrit = [0])

we tell odeint to sample more carefully around 0. 我们告诉odeint在0附近更仔细地采样。

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


def euler(df, f0, x):
    h = x[1] - x[0]
    y = [f0]
    for i in xrange(len(x) - 1):
        y.append(y[i] + h * df(y[i], x[i]))
    return y


def i(df, f0, x):
    h = x[1] - x[0]
    y = [f0]
    y.append(y[0] + h * df(y[0], x[0]))
    for i in xrange(1, len(x) - 1):
        fn = df(y[i], x[i])
        fn1 = df(y[i - 1], x[i - 1])
        y.append(y[i] + (3 * fn - fn1) * h / 2)
    return y

def df(y, x):
   return 2.0 / np.sqrt(np.pi) * np.exp(-x * x)

if __name__ == "__main__":
    f0 = 0.0
    x = np.linspace(-10.0, 10.0, 10000)

    y1 = euler(df, f0, x)
    y2 = i(df, f0, x)
    y3 = integrate.odeint(df, f0, x, tcrit = [0])

    plt.plot(x, y1)
    plt.plot(x, y2)
    plt.plot(x, y3)
    plt.legend(["euler", "modified", "odeint"], loc='best')
    plt.grid(True)
    plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM