解常微分方程
解常微分方程问题
例1:假设在平面内有一带电粒子q,质量为m。空间内存在匀强磁场B,方向垂直于平面向内即沿z轴负半轴,以及一个沿y轴负半轴的重力场。带电粒子从磁场内O点释放。
则可直接列出粒子的运动方程,将这个方程分解成x和y两个方向,联立即可求得该方程组的解。
sympy中的dsolve方法
Python例程
1 #导入 2 from sympy import * 3 import numpy as np 4 import matplotlib.pyplot as plt 5 init_printing() 6 7 ###首先声明符号x,y,q,m,B,g 8 #参量 9 q,m,B,t,g = symbols('q m B t g',real=True,nonzero=True,positive=True) 10 #函数 11 x,y = symbols('x y',real=True,nonzero=True,positive=True,cls=Function) 12 13 ###再将微分方程表示出来 14 eq1 = Eq(x(t).diff(t,t),-q*B*y(t).diff(t)/m) 15 eq2 = Eq(y(t).diff(t,t),-g+q*B*x(t).diff(t)/m) 16 sol = dsolve([eq1,eq2]) 17 print("微分方程:",sol) #现在打印出sol 18 19 ###这个式子非常冗杂,用trigsimp()方法化简 20 x = trigsimp(sol[0].rhs) 21 y = trigsimp(sol[1].rhs) 22 print("化简:",x,y) 23 24 ###将里面的积分常数算出 25 #定义积分变量,避免报错,观察上式输出式子中有几个C这里就定义几个 26 var('C1 C2 C3 C4') 27 #x(0)=0 28 e1 = Eq(x.subs({t:0}),0) 29 #x'(0)=0,要将subs放在diff后面 30 e2 = Eq(x.diff(t).subs({t:0}),0) 31 #y(0)=0 32 e3 = Eq(y.subs({t:0}),0) 33 #y'(0)=0 34 e4 = Eq(y.diff(t).subs({t:0}),0) 35 l = solve([e1,e2,e3,e4],[C1,C2,C3,C4]) 36 print("积分常数:",l) 37 38 ###将积分常量替换到x和y里面,我们就得到了解的最终形式 39 x = x.subs(l) 40 y = y.subs(l) 41 print("最终形式:",x,y) 42 43 #作图 44 ts = np.linspace(0,15,1000) 45 consts = {q:1,B:1,g:9.8,m:1} 46 fx = lambdify(t,x.subs(consts),'numpy') 47 fy = lambdify(t,y.subs(consts),'numpy') 48 plt.plot(fx(ts),fy(ts)) 49 plt.grid() 50 plt.show()
解一阶常微分方程:dy/dx=y
Python例程
1 from sympy import * 2 f = symbols('f', cls=Function)#定义函数标识符 3 x = symbols('x')#定义变量 4 eq = Eq(diff(f(x),x,1),f(x))#构造等式,即dy/dx=y 5 #diff(函数,自变量,求导次数) 6 print(dsolve(eq, f(x))) 7 pprint(dsolve(eq, f(x)))#以"pretty"形式打印方程的解
解二阶常微分方程:y"+py'+qy=0
Python例程
1 from sympy import * 2 f = symbols('f', cls=Function)#定义函数标识符 3 x,p,q = symbols('x,p,q')#批量定义变量 4 eq = Eq(diff(f(x),x,2)+p*diff(f(x),x,1)+q*f(x),0) 5 #构造方程,即y"+py'+qy=0 6 #diff(函数,自变量,求导次数) 7 print(dsolve(eq, f(x))) 8 pprint(dsolve(eq, f(x)))#以"pretty"形式打印方程的解
常微分方程绘图
Python例程
1 #绘图 2 import numpy as np 3 import matplotlib.pyplot as plt 4 from scipy.integrate import odeint 5 6 def diff(y, x): 7 return np.array(1/x) 8 # 上面定义的函数在odeint里面体现的就是dy/dx =1/x #定义常微分方程 9 x = np.linspace(1, 10, 100) # 给出x范围,(起始,终值,分割段数) 10 y = odeint(diff, 0, x) # 设函数初值为0,即f(1)=0 11 plt.xlabel('x') 12 plt.ylabel('y') 13 plt.title("y=ln(x)") #定义图的标题 14 plt.grid()#绘制网格 15 plt.plot(x, y) # 将x,y两个数组进行绘图 16 plt.show()
单摆运动:y"+gsin(y)/l=0,g为重力加速度,l为摆长
Python例程
1 from scipy.integrate import odeint 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 g = 9.8 6 l = 1 7 #重力加速度为9.8m/s,摆长为1m,y"+gsin(y)/l=0,g为重力加速度,l为摆长 8 def diff(d_list, t):#我们可以将一个二阶常微分方程分解为含有两个方程的一阶常微分方程组 9 omega, theta = d_list 10 return np.array([-g/l*np.sin(theta), omega]) 11 ''' 12 深入剖析diff函数:diff的左边代表dω/dt和dθ/dt,由于函数返回的是数组类型,我们 13 可以用这种方式构建一个微分方程组:dθ/dt=ω,dω/dt=-gsin(θ)/l 14 ''' 15 t = np.linspace(0, 10, 1000) 16 result = odeint(diff, [0, 30/180*np.pi], t) 17 # odeint中第二个是初始单摆角度30度,无法采用小角近似 18 plt.xlabel('x') 19 plt.ylabel('y') 20 plt.title("dθ/dt=ω,dω/dt=-gsin(θ)/l") 21 plt.plot(t, result) # 输出ω和θ随时变化曲线,即方程解 22 plt.show()
洛伦兹曲线:
以下方程组代表曲线在xyz三个方向上的速度,给定一个初始点,可以画出相应的洛伦兹曲线。
Python例程
1 import numpy as np 2 from scipy.integrate import odeint 3 from mpl_toolkits.mplot3d import Axes3D 4 import matplotlib.pyplot as plt 5 6 def dmove(Point, t, sets): 7 """ 8 point:present location index 9 sets:super parameters 10 """ 11 p, r, b = sets 12 x, y, z = Point 13 return np.array([p * (y - x), x * (r - z), x * y - b * z]) 14 15 t = np.arange(0, 30, 0.001) 16 P1 = odeint(dmove, (0., 1., 0.), t, args=([10., 28., 3.],)) # 17 ## (0.,1.,0.) is the initial point; args is the set for super parameters 18 P2 = odeint(dmove, (0., 1.01, 0.), t, args=([10., 28., 3.],)) 19 ## slightly change the initial point from y = 1.0 to be y = 1.01 20 21 fig = plt.figure() 22 ax = Axes3D(fig) 23 ax.plot(P1[:, 0], P1[:, 1], P1[:, 2]) 24 ax.plot(P2[:, 0], P2[:, 1], P2[:, 2]) 25 plt.show()