如何在python中求解一组ODE,其中其中一个包含dirac delta函数(或逐步增量)?

时间:2019-07-11 12:39:03

标签: python increment ode differential-equations odeint

我正在尝试以python可视化振荡器系统。只要其中一个变量没有累积(使用狄拉克-德尔塔函数),系统就可以工作。但是,当我尝试包含它时,系统没有任何变化。您可以在下面找到我所经历的过程以及遇到的一些问题。

我已经在python中编写了一些代码,能够正确可视化常规的振荡器行为。但是,在其中一个变量中包含逐步增量时,系统不会对此做出反应。在下面,您可以找到包含增量的版本。该代码运行,但给出的输出就像没有增量一样。在代码下,您可以找到正确解决方案的问题。

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

a4 = 5.68
aAPD = 9.09
deltaZ = 0.41
gamma = 1.33
negV = 1
n=500

def f(V):
    if V<=-60:
        return V/20 + 4
    elif V>=20:
        return V/20 - 1
    else:
        return -V/80 + 1/4

def alpha(V):
    if V<0:
        return a4
    else:
        return -aAPD

def g(q):
    return q/(q+1)

def step(V):
    global negV
    if V>0 and negV == 1:
        negV = 0
        return deltaZ
    elif V<=0 and negV == 0:
        negV = 1
        return 0
    else:
        return 0

# function that returns dz/dt
def model(z,t):
    V = z[0]
    y = z[1]
    q = z[2]
    dVdt = 25000*(y - f(V))
    dydt = alpha(V) - a4*g(q)
    dqdt = -gamma*g(q) + step(V)
    dzdt = [dVdt,dydt,dqdt]
    return dzdt

# initial condition
z0 = [0,0,0]

# time points
t = np.linspace(0,0.5,n)

# solve ODE
z = odeint(model,z0,t)

# plot results
plt.plot(t,z[:,0],label='Voltage')
plt.plot(t,z[:,1],label='y')
plt.plot(t,z[:,2],label='Z')
plt.ylabel('response')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()

问题出在函数step(V)上。振荡器在某个时刻越过值V = 0。此时,q的值应增加deltaZ。

我不了解或不知道如何获取正确值的python的odesolver中有几点。因此,这里有问题/问题的简短列表:

  • 要找到V越过0的点,我使用了一个全局值negV。但是,如果我能够像if V[i]>0 and V[i-1]<0: return deltaZ那样包含一条语句,那就更好了。由于您最终绘制了V的值,因此该信息应该在某个地方可用,但是我看不到如何访问V的先前值。
  • q值的增加应立即发生。因此,一种解决方案可能是先求解dqdt,然后将q增加值delZ。我不知道如何实现这一目标。有没有一种方法可以直接访问V,y和q的值?稍后,我也想手动更改V的值,所以这将很有用。
  • 另一种解决方案可能是将deltaZ值保持在dqdt中,但随后我应该知道求解微分方程的时间步长,这样我就可以将deltaZ = 0.41除以该时间步长,从而q的增量为deltaZ = 0.41。但是,在查看odeint信息时,我看到时间步长是可变的,所以也许这不是解决方案的好方法...

最好我会解决所有这三个问题,但是如果您能够提供其中一项的答案,那么我也将得到很多帮助。

1 个答案:

答案 0 :(得分:0)

我强烈建议您在事件中使用solve_ivp函数来检测V=0交叉。参见here

如果使用终端事件,则解决方案将恰好在V=0处停止。然后,您可以使用您的瞬时更改在ODE集成器之外更新解决方案,并将其用作第二次调用solve_ivp的初始条件以完成集成。我假设V=0的交叉仅发生一次,但是您可以构建逻辑以处理事件的多个交叉。