![](/img/trans.png)
[英]solve an ODE function of a previous time step (delay differential equation)
[英]Solve an implicit ODE (differential algebraic equation DAE)
我正在嘗試使用scipy中的odeint解決二階ODE問題。 我遇到的問題是函數隱式耦合到二階項,如簡化片段中所示(請忽略示例的假裝物理):
import numpy as np
from scipy.integrate import odeint
def integral(y,t,F_l,mass):
dydt = np.zeros_like(y)
x, v = y
F_r = (((1-a)/3)**2 + (2*(1+a)/3)**2) * v # 'a' implicit
a = (F_l - F_r)/mass
dydt = [v, a]
return dydt
y0 = [0,5]
time = np.linspace(0.,10.,21)
F_lon = 100.
mass = 1000.
dydt = odeint(integral, y0, time, args=(F_lon,mass))
在這種情況下,我意識到可以用代數方式求解隱式變量,但是在我的實際場景中, F_r
之間存在很多邏輯,並且a
和代數操作的評估失敗。
我相信DAE可以使用MATLAB的ode15i函數來解決,但我試圖盡可能避免這種情況。
我的問題是 - 有沒有辦法在python中解決隱式ODE函數(DAE)(最好是scipy)? 是否有更好的方法來解決上述問題?
作為最后的手段,可以接受從前一個時間步驟傳遞a
。 我怎么能在每個時間步之后將dydt[1]
傳回函數?
相當老,但值得更新,所以它可能對任何人有用,誰偶然發現這個問題。 目前python中可用的包很少,可以解決隱式ODE。 GEKKO( https://github.com/BYU-PRISM/GEKKO )是一個軟件包,專門針對混合整數,非線性優化問題進行動態優化,但也可以用作通用DAE求解器。
上述“假裝物理”問題可以在GEKKO中解決,如下所述。
m= GEKKO()
m.time = np.linspace(0,100,101)
F_l = m.Param(value=1000)
mass = m.Param(value =1000)
m.options.IMODE=4
m.options.NODES=3
F_r = m.Var(value=0)
x = m.Var(value=0)
v = m.Var(value=0,lb=0)
a = m.Var(value=5,lb=0)
m.Equation(x.dt() == v)
m.Equation(v.dt() == a)
m.Equation (F_r == (((1-a)/3)**2 + (2*(1+a)/3)**2 * v))
m.Equation (a == (1000 - F_l)/mass)
m.solve(disp=False)
plt.plot(x)
如果代數操作失敗,你可以找到你的約束的數值解,在每個時間步運行例如fsolve
:
import sys
from numpy import linspace
from scipy.integrate import odeint
from scipy.optimize import fsolve
y0 = [0, 5]
time = linspace(0., 10., 1000)
F_lon = 10.
mass = 1000.
def F_r(a, v):
return (((1 - a) / 3) ** 2 + (2 * (1 + a) / 3) ** 2) * v
def constraint(a, v):
return (F_lon - F_r(a, v)) / mass - a
def integral(y, _):
v = y[1]
a, _, ier, mesg = fsolve(constraint, 0, args=[v, ], full_output=True)
if ier != 1:
print "I coudn't solve the algebraic constraint, error:\n\n", mesg
sys.stdout.flush()
return [v, a]
dydt = odeint(integral, y0, time)
顯然,這會減慢你的時間整合。 始終檢查fsolve
找到了一個好的解決方案,並刷新輸出,以便在發生時實現它並停止模擬。
關於如何在前一個時間步“緩存”變量的值,您可以利用默認參數僅在函數定義中計算的事實,
from numpy import linspace
from scipy.integrate import odeint
#you can choose a better guess using fsolve instead of 0
def integral(y, _, F_l, M, cache=[0]):
v, preva = y[1], cache[0]
#use value for 'a' from the previous timestep
F_r = (((1 - preva) / 3) ** 2 + (2 * (1 + preva) / 3) ** 2) * v
#calculate the new value
a = (F_l - F_r) / M
cache[0] = a
return [v, a]
y0 = [0, 5]
time = linspace(0., 10., 1000)
F_lon = 100.
mass = 1000.
dydt = odeint(integral, y0, time, args=(F_lon, mass))
請注意,為了使技巧工作, cache
參數必須是可變的,這就是我使用列表的原因。 如果您不熟悉默認參數的工作方式,請參閱此鏈接。
請注意,這兩個代碼不會產生相同的結果,您應該非常小心地使用前一個時間步的值,以確保數值穩定性和精度。 第二個顯然要快得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.