Python:使用odeint求解二阶线性微分方程

Python:使用odeint求解二阶线性微分方程,python,math,differential-equations,Python,Math,Differential Equations,我有两个这样的微分方程: al=arctan(ri') ri'=(vz-C_-alz(ri,al))*(1+ri'**2)/C_-aln(ri,al) 初始值为:ri(l=0)=2.5,ri'(l=0)=0 vz是关于l和C_alz的函数,C_aln是关于ri和al的两个函数。这3个复杂的数学表达式是通过代码1计算出来的,结果是正确的,ri的轨迹可以作为代码2结果的参考 # -*- coding: utf-8 -*- """ Created on Fri Dec 18 14:41:07 2015

我有两个这样的微分方程:

  • al=arctan(ri')
  • ri'=(vz-C_-alz(ri,al))*(1+ri'**2)/C_-aln(ri,al)
  • 初始值为:
    ri(l=0)=2.5,ri'(l=0)=0

    vz
    是关于l和
    C_alz
    的函数,
    C_aln
    是关于
    ri
    al
    的两个函数。这3个复杂的数学表达式是通过代码1计算出来的,结果是正确的,
    ri
    的轨迹可以作为代码2结果的参考

    # -*- coding: utf-8 -*-
    """
    Created on Fri Dec 18 14:41:07 2015
    @author: marswang
    code 1
    """
    
    from numpy.linalg import inv
    from sympy import sqrt, sin, cos, tan, atan, diff
    from numpy import array
    import sympy as sp
    import matplotlib.pyplot as pl
    import numpy as np
    def r_trajektor (L,R):  
        B= np.array([[1, L[0], L[0]**2,L[0]**3 ], [0, 1, 2*L[0], 3*L[0]**2], [1, L[1], L[1]**2, L[1]**3], [0, 1, 2*L[1], 3*L[1]**2]])
        X= np.array([[R[0]], [0], [R[1]], [0]])
        A=np.dot(inv(B), X)
        return A    
    
    a=7.6
    rh_s=2420                          
    rh_m=2285                          
    the_0=11                           
    Rc=49                              
    vc= 0                             
    vp=10
    
    # two points in the r-trajektory and 1. derivative:
    # point1 l0=0,r(l0)=2.5 and r'(l0)=0 
    # point2 l1=36,r(l1)=22.5 and r'(l1)=0
    L= array([[0], [36]])
    R= array([[2.5], [22.5]])
    # A symbolic derivation expression of vg
    ri=sp.Symbol('ri') 
    al=sp.Symbol('al')
    l=sp.Symbol('l')  
    A=r_trajektor(L,R)
    # convert 'list' to 'float'
    rir=float(A[0])+float(A[1])*l+float(A[2])*l**2+float(A[3])*l**3
    dri=diff(rir,l)
    alr=atan(diff(rir,l))
    dal=diff(alr,l)
    hi=a*sqrt((1-sin(the_0+al))/(1+a/(sqrt(2)*ri)))
    hir=hi.subs([(al,alr),(ri,rir)])
    C_aln=(1-ri**2/(Rc**2))*diff(hi,al)+(a**2)*ri/(Rc**2)*sin(the_0+al)
    print C_aln
    C_alz=1-(rh_s*ri**2)/(rh_m*Rc**2)+((1-(ri**2)/(Rc**2))*diff(hi,ri)-2*ri*hi/(Rc**2)-(a**2)/(Rc**2)*cos(the_0+al))*tan(al)
    print C_alz
    vg=((vp-vc)/(diff(al,l)*C_aln+C_alz)).subs([(al,alr),(ri,rir)])
    vz=10/vg
    print vz
    
    
    # the function has to be worked with the arrays from numpy too.
    # Thus have to lambdify the expression
    
    l_val = np.linspace(0.0,36.0,100.0)
    
    fr=sp.lambdify(l,rir,"numpy")
    r_val=fr(l_val)
    ## plot
    pl.figure(figsize=(10,10),dpi=98)
    p1 =pl.subplot(2, 1, 1)
    p1.plot(l_val,r_val,"g-",label="ri",)
    p1.axis([0.0, 40.0,0.0,25.0])
    p1.set_ylabel("ri in mm",fontsize=14)
    p1.set_xlabel("l in mm",fontsize=14)
    p1.legend(loc=4)
    
    现在我想求解这两个微分方程,并使用代码2从代码1的计算出的
    vz
    反向得到
    ri
    相对于
    l
    的图形(轨迹)

    # -*- coding: utf-8 -*-
    """
    Created on Sat Jan 02 13:15:19 2016
    @author: marswang
    code 2
    """
    from sympy import sqrt, sin, cos, tan, atan
    import matplotlib.pyplot as pl
    import numpy as np
    from scipy.integrate import odeint
    a=7.6                              
    rh_s=2420                          
    rh_m=2285                          
    the_0=11                           
    Rc=49                              
    vc= 0                             
    vp=10
    
    def func(ri,l):
        vz=((-0.00257201646090535*l**2 + 0.0925925925925926*l + 9.25185853854297e-17)*(-0.00633069554352353*sqrt((-sin(atan(-0.00257201646090535*l**2 + 0.0925925925925926*l + 9.25185853854297e-17) + 11) + 1)/(1 + 3.8*sqrt(2)/(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5)))*(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5) + 14.44*sqrt(2)*sqrt((-sin(atan(-0.00257201646090535*l**2 + 0.0925925925925926*l + 9.25185853854297e-17) + 11) + 1)/(1 + 3.8*sqrt(2)/(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5)))*(-(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5)**2/2401 + 1)/((1 + 3.8*sqrt(2)/(-0.000857338820301783*l**3 +
        0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5))*(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 + 9.25185853854297e-17*l + 2.5)**2) - 0.0240566430653894*cos(atan(-0.00257201646090535*l**2 + 0.0925925925925926*l + 9.25185853854297e-17) + 11)) - 484*(-0.000857338820301783*l**3 + 0.0462962962962963*l**2 +
        9.25185853854297e-17*l + 2.5)**2/1097257 + 1)    
        ri0=ri[0]
        ri1=ri[1]       
        C_aln=0.0240566430653894*ri0*sin(atan(ri1) + 11) - 3.8*sqrt((-sin(atan(ri1) + 11) + 1)/(1 + 3.8*sqrt(2)/ri0))*(-ri0**2/2401 + 1)*cos(atan(ri1) + 11)/(-sin(atan(ri1) + 11) + 1)
        C_alz=-484*ri0**2/1097257 + (-0.00633069554352353*ri0*sqrt((-sin(atan(ri1) + 11) + 1)/(1 +
        3.8*sqrt(2)/ri0)) - 0.0240566430653894*cos(atan(ri1) + 11) + 14.44*sqrt(2)*sqrt((-sin(atan(ri1) + 11) + 1)/(1 + 3.8*sqrt(2)/ri0))*(-ri0**2/2401 + 1)/(ri0**2*(1 + 3.8*sqrt(2)/ri0)))*tan(atan(ri1)) + 1    
        ri2=(vz-C_alz)*(1+ri1**2)/C_aln/
        return [ri1, ri2]
    
    init = np.array([2.5, 0.1])
    l = np.linspace(0.0,36.0,100.0)
    sol=odeint(func, init, l)
    pl.plot(l, sol[:,0], color='b')
    pl.legend()
    pl.xlabel(" l in mm ", fontsize=14)
    pl.ylabel(" ri in mm ", fontsize=14)
    pl.show()
    
    我已经多次检查了
    vz
    C_aln
    C_alz
    的表达式。这些表达式直接来自代码1。但代码2的结果是不正确的,我得到的总是和参考不一样。
    ri
    的参考结果应与第一个图形类似:

    但代码2中‘ri’的计算结果如下:

    我不确定在这种情况下是否正确使用了
    odeint
    ,这两个图形之间出现此错误的原因是什么


    我是Python世界的新手,非常感谢您的帮助。谢谢。

    对于维度2和阶数1的系统,ODE函数应该返回维度2的向量

    对于ODE
    u'=f(t,u,u')
    ODE函数应遵循以下方案

    def odefunc(t,y):
        u , v = y
        # Computations
        return [ v, f(t,u,v) ]
    

    维数为2且阶数为1的系统的ODE函数应返回维数为2的向量

    对于ODE
    u'=f(t,u,u')
    ODE函数应遵循以下方案

    def odefunc(t,y):
        u , v = y
        # Computations
        return [ v, f(t,u,v) ]
    

    我是否应该编辑代码2中的返回值,比如:
    return[ri1,ri2]
    ,然后编辑
    pl.plot(l,sol[:,0],color='b')
    。那么我可以得到ri2的返回值,也就是ri“”?是的,这似乎是正确的方法
    odeint
    似乎负责矢量化,所以即使像
    return ri1,ri2
    中那样返回一个隐式列表也足够了。@LutzL谢谢。我还有一个关于奥丁的问题。我应该如何使用odeint?我曾经这样写过:
    init=[2.5,0.0]
    l=np.linspace(0,36100)sol=odeint(func,init,l)
    我发现,也许我在初始条件中犯了一个错误,我想定义ini。像ri[0]=2.5,ri'[0]=0这样的条件。格式正确吗?索尔应该是一个ri1和ri2的数组?我试过了。程序运行良好。但是结果更糟。那么恐怕你得回到数学上来。你能不能,无论是在这个问题上,还是在数学上,用更抽象的术语来描述你的前向和后向问题?我认为它们并不完全相反。我是否应该在代码2中编辑我的返回值,比如:
    return[ri1,ri2]
    ,然后
    pl.plot(l,sol[:,0],color='b')
    。那么我可以得到ri2的返回值,也就是ri“”?是的,这似乎是正确的方法
    odeint
    似乎负责矢量化,所以即使像
    return ri1,ri2
    中那样返回一个隐式列表也足够了。@LutzL谢谢。我还有一个关于奥丁的问题。我应该如何使用odeint?我曾经这样写过:
    init=[2.5,0.0]
    l=np.linspace(0,36100)sol=odeint(func,init,l)
    我发现,也许我在初始条件中犯了一个错误,我想定义ini。像ri[0]=2.5,ri'[0]=0这样的条件。格式正确吗?索尔应该是一个ri1和ri2的数组?我试过了。程序运行良好。但是结果更糟。那么恐怕你得回到数学上来。你能不能,无论是在这个问题上,还是在数学上,用更抽象的术语来描述你的前向和后向问题?我认为它们并不完全相反。