Sympy二阶常微分方程求解

6

我有一个简单二阶常微分方程的齐次解,尝试使用 Sympy 求解初始值时,返回相同的解。应该将其代入 y(0) 和 y'(0) 并得到没有常数的解,但实际上并不是这样。以下是建立方程的代码(这是弹簧平衡方程,k=弹簧常数,m=质量)。抱歉使用了一些其他地方也用到的冗余符号。

%matplotlib inline
from sympy import *
m,k, x,t,s,T, omega,A,B = symbols('m k x t s T omega A B',float=True)
a = symbols('a', positive=True)
f,y,g,H,delta,S=symbols('f y g H delta S',cls=Function)
Eq1 = Eq(m*diff(y(t),t,2)+k*y(t))
Eq1

结果是(正确的): $y{\left (t \right )} = C_{1} e^{- t \sqrt{- \frac{k}{m}}} + C_{2} e^{t \sqrt{- \frac{k}{m}}}$
其中 y(t)=C1e^(−t√(−k/m))+C2e^(t√(−km)),也可以写成y_n = c1.cos(√(−k/m)t)+c2.sin(√(−k/m)t)。
当此方程被解析求解,并转换为使用正弦和余弦函数的解时,其中 omega = sqrt(-k/m),那么 c1 = y(0),c2 = y'(0)/omega。因此,尽管该解的一部分涉及复数,但 dsolve 仅返回原始齐次方程如上所述。我计算 ODE 在 y(0) 和 y'(0) 处的代码为:
Eq1_soln_IVP =dsolve(Eq1,y(t),x0=0, ics={y(0): a, y(t).diff(t).subs(t, 0): a})

我理解dsolve可能无法对此IVP进行解析处理,但基于它的其他能力,如果它真的做不到,我会感到惊讶。如果有任何帮助来解决这个问题以及其他解析二阶问题,将不胜感激。问题的核心在于:

ics={y(0): a, y(t).diff(t).subs(t, 0): a}

所以我尝试的解决方案,Dietrich 也确认了,是:
 #Create IVP for y(0)
 expr = Eq(Eq1_soln_IVP.rhs.subs(sqrt(-k/m),I*omega),y(0))
 #Create IVP for y'(0)
 expr2 = Eq(diff(y(t),t).subs(t,0),expr.lhs.diff(t))
 #Maps all free variables and solves for each where t = 0.
 solve([expr.subs(t,0),expr2.subs(t,0)])

虽然这是一种解决方案,但似乎这是一种非常复杂的找到y(t) = y(0)cos(omega*t - phi)的方法......这回答了关于此求解器某些限制的隐含问题以及有关如何解决ics arg的直接问题。谢谢。
1个回答

4
dsolve()的参数ics并不能正常工作(Issue 4720),因此您需要手动进行替换。您可以尝试:
from IPython.display import display
import sympy as sy

sy.init_printing()  # LaTeX-like pretty printing for IPython

t = sy.Symbol("t", real=True)
m, k = sy.symbols('m k', real=True)  # gives C_1 Exp() + C_2 Exp() solution
# m, k = sy.symbols('m k', positive=True)  # gives C_1 sin() + C_2 cos() sol.
a0, b0 = sy.symbols('a0, b0', real=True)
y = sy.Function('y')

Eq1 = sy.Eq(m*sy.diff(y(t), t, 2) + k*y(t))
print("ODE:")
display(Eq1)

print("Generic solution:")
y_sl0 = sy.dsolve(Eq1, y(t)).rhs  # take only right hand side
display(sy.Eq(y(t), y_sl0))

# Initial conditions:
cnd0 = sy.Eq(y_sl0.subs(t, 0), a0)  # y(0) = a0
cnd1 = sy.Eq(y_sl0.diff(t).subs(t, 0), b0)  # y'(0) = b0

#  Solve for C1, C2:
C1, C2 = sy.symbols("C1, C2")  # generic constants
C1C2_sl = sy.solve([cnd0, cnd1], (C1, C2))

# Substitute back into solution:
y_sl1 = sy.simplify(y_sl0.subs(C1C2_sl))
print("Solution with initial conditions:")
display(sy.Eq(y(t), y_sl1))

感谢Dietrich注意到4720问题,并独立确认了我能构建的唯一解决方法。回复表示感激。 - Time Lord
因此,这里的数学问题是求解器没有利用欧拉方程进行替换。将解中的 e^{\pm i \omega t} 项转化为 m.cos(\omega t) + n.i sin(\omega t) 的形式对于找到这些方程的真实和物理意义至关重要,在这种情况下,一个悬挂有重物的弹簧,其中 y(t) 是一种振荡位移。Sympy.plot 可以处理三角形式,但不能有效地处理复杂形式,从而排除了有效的可视化。 - Time Lord
这取决于 mk 的符号。如果你写成 m, k = sy.symbols('m k', positive=True),你将得到实际(物理)解。有相当多的应用程序使用复杂解。顺便说一句,如果你使用Mathematica或Maple,你也将面临同样的问题。 - Dietrich
查看Sympy的能力是一项有用的练习。我想,没有特别深入的思考,求解器需要有一种将复杂形式转换为三角形式的方法来处理某些解决方案。当然,在工程应用中的问题是,m和k系数通常代表相反的力量,必须其中一个为负,因此会出现复杂的解决方案。很高兴知道Maple和Mathematica也是如此。感谢您的意见。 - Time Lord

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接