简体   繁体   中英

Python: How to solve an ordinary differential equation with integral term in it

I dont know if this question has been asked before in SO, I will go ahead and post it here, I am attempting to solve a simple system with a PID controller, my system of differential equations are given below. I am basically attempting to code very basic PID algorithm. The structure of my control u depends on both derivative and integral of error term. I dont have any problem with the derivative term, it is the integral term that is creating problem in my code. The problem crops up when I assign s=0 in the beginning and use it in my function as described in my code below. Is there a way to bypass it? I tried assigning s and told as global variables, but it didnt solve my problem. In a nutshell what I am doing is- I am adding state x1 every time and multiplying by dt(which is denoted by t-told).

在此处输入图片说明

Kindly help me iron out this issue, PFA my code attached below.

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()

First of all you need to include "s" Variable into the pid function.

' def pid(s, t, Y): ... '

Easiest solution I can see right now is to create a class with s and told as properties of this class:

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]

For the first part of your problem. Use pidsolver = PIDSolver() in the next part of your solution.

I solved this problem myself by using set_f_params() method and passing a list in itz argument. Also I passed a 3rd argument in pid() ie pid(t,Y,arg) . And lastly I assigned s,told=arg[0],arg[1] .

You are making assumptions on the solver and the time steps that it visits that are not justified. With your hacking of the integral, even if it were mathematically sound (it should look like integral = integral + e*(t-told) , which gives an order 1 integration method), you reduce the order of any integration method, probably down to 1, if you are lucky only to order 2.

A mathematically correct method to implement this system is to introduce a third variable x3 for the integral of e , that is, the derivative of x3 is e . That the correct order 1 system has to be of dimension 3 can be read of the fact that (eliminating e ) your system has 3 differentiation/integration operations. With that your system becomes

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]

Note that there are no global dynamic variables necessary, only the constants (which could also be passed as parameters, whatever seems more efficient or readable).

Now you will also need an initial value for x3 , it was not visible from the system what the integration variable would have to be, your code seems to suggest 0 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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