Python:如何解决带有积分项的常微分方程

时间:2017-08-08 06:25:00

标签: python ode differential-equations numerical-integration

我不知道之前是否已经问过这个问题,我会继续在这里发布,我试图解决一个带有PID控制器的简单系统,下面给出了我的微分方程系统。我基本上试图编写非常基本的PID算法。我的控制结构取决于误差项的导数和积分。我对衍生术语没有任何问题,它是在我的代码中创建问题的积分术语。当我在开头指定s = 0时,问题就出现了 并在我的函数中使用它,如下面的代码所述。有没有办法绕过它?我尝试分配s并告诉全局变量,但它没有解决我的问题。简而言之,我正在做的是 - 我每次都添加状态x1并乘以dt(用t-tell表示)。

enter image description here

请帮助我解决这个问题,PFA我的代码附在下面。

import numpy as np
from scipy.integrate import ode
import matplotlib.pyplot as plt
plt.style.use('bmh')

t0=0
y0=[0.1,0.2]
kp,kd,ki=2,0.5,0.8
s,told=0,0
def pid(t,Y):
    x1,x2=Y[0],Y[1]
    e=x1-1
    de=x2
    s=(x1+s)
    integral=s*(t-told)
    told=t
    #ie=
    u=kp*e+kd*de+ki*integral
    x1dot=x2
    x2dot=u-5*x1-2*x2
    return[x1dot,x2dot]

solver=ode(pid).set_integrator('dopri5',rtol=1e-6,method='bdf',nsteps=1e5,max_step=1e-3)
solver.set_initial_value(y0,t0)
t1=10
dt=5e-3
sol = [ [yy] for yy in y0 ]
t=[t0]
while solver.successful() and solver.t<t1:
    solver.integrate(solver.t+dt)
    for k in range(2): sol[k].append(solver.y[k]);
    t.append(solver.t)
    print(len(sol[0]))
    print(len(t))
x1=np.array(sol[0])
x2=np.array(sol[1])
e=x1-1
de=x2
u=kp*e+kd*de
for k in range(2):
    if k==0:
        plt.subplot(2,1,k+1)
        plt.plot(t,sol[k],label='x1')
        plt.plot(t,sol[k+1],label='x2')
        plt.legend(loc='lower right')
    else:
        plt.subplot(2,1,k+1)
        plt.plot(t,u)
plt.show()

4 个答案:

答案 0 :(得分:0)

首先,您需要在pid函数中包含“s”变量。

”      def pid(s,t,Y):... “

答案 1 :(得分:0)

我现在能看到的最简单的解决方案是创建一个以stold作为此类属性的类:

class PIDSolver:
    def __init__(self)
        self.t0=0
        self.y0=[0.1,0.2]
        self.kp,self.kd,self.ki=2,0.5,0.8
        self.s,self.told=0,0

    def pid(t,Y):
        x1,x2=Y[0],Y[1]
        e=x1-1
        de=x2
        self.s=(x1+self.s)
        integral=self.s*(t-self.told)
        self.told=t
        #ie=
        u=self.kp*e+self.kd*de+self.ki*integral
        x1dot=x2
        x2dot=u-5*x1-2*x2
        return[x1dot,x2dot]

问题的第一部分。在解决方案的下一部分中使用pidsolver = PIDSolver()

答案 2 :(得分:0)

我自己通过使用set_f_params()方法并在itz参数中传递列表来解决此问题。我还在pid()中传递了第3个参数,即pid(t,Y,arg)。最后我分配了s,told=arg[0],arg[1]

答案 3 :(得分:0)

您正在假设解算器及其访问的时间步骤是不合理的。随着你对积分的破解,即使它在数学上是合理的(它应该看起来像integral = integral + e*(t-told),它提供了一个1阶积分方法),你减少了任何积分方法的顺序,可能降到1,如果你是幸运只能订购2.

实现此系统的数学上正确的方法是为x3的积分引入第三个变量e,即x3的导数为e。正确的订单1系统必须是维度3,可以读取(消除e)您的系统具有3个区分/集成操作的事实。随之而来的是你的系统

def pid(t,Y):
    x1, x2, x3 =Y
    e=x1-1
    x1dot = x2
    edot = x1dot
    x3dot = e
    u=kp*e+kd*edot+ki*x3
    x2dot=u-5*x1-2*x2
    return[x1dot, x2dot, x3dot]

请注意,没有必要的全局动态变量,只有常量(也可以作为参数传递,无论看起来更有效还是可读)。

现在您还需要x3的初始值,系统无法看到集成变量必须是什么,您的代码似乎建议0

相关问题