简体   繁体   English

用 Python 数值求解 ODE

[英]Solving ODE numerically with Python

I am solving an ODE for an harmonic oscillator numerically with Python.我正在用 Python 数值求解谐波振荡器的 ODE。 When I add a driving force it makes no difference, so I'm guessing something is wrong with the code.当我添加驱动力时,它没有任何区别,所以我猜代码有问题。 Can anyone see the problem?任何人都可以看到问题吗? The (h/m)*f0*np.cos(wd*i) part is the driving force. (h/m)*f0*np.cos(wd*i)部分是驱动力。

import numpy as np
import matplotlib.pyplot as plt

# This code solves the ODE mx'' + bx' + kx = F0*cos(Wd*t)
# m is the mass of the object in kg, b is the damping constant in Ns/m
# k is the spring constant in N/m, F0 is the driving force in N,
# Wd is the frequency of the driving force and x is the position 

# Setting up

timeFinal= 16.0   # This is how far the graph will go in seconds
steps = 10000     # Number of steps
dT = timeFinal/steps      # Step length 
time = np.linspace(0, timeFinal, steps+1)   
# Creates an array with steps+1 values from 0 to timeFinal

# Allocating arrays for velocity and position
vel = np.zeros(steps+1)
pos = np.zeros(steps+1)

# Setting constants and initial values for vel. and pos.
k = 0.1
m = 0.01
vel0 = 0.05
pos0 = 0.01
freqNatural = 10.0**0.5
b = 0.0
F0 = 0.01
Wd = 7.0
vel[0] = vel0    #Sets the initial velocity
pos[0] = pos0    #Sets the initial position



# Numerical solution using Euler's
# Splitting the ODE into two first order ones
# v'(t) = -(k/m)*x(t) - (b/m)*v(t) + (F0/m)*cos(Wd*t)
# x'(t) = v(t)
# Using the definition of the derivative we get
# (v(t+dT) - v(t))/dT on the left side of the first equation
# (x(t+dT) - x(t))/dT on the left side of the second 
# In the for loop t and dT will be replaced by i and 1

for i in range(0, steps):
    vel[i+1] = (-k/m)*dT*pos[i] + vel[i]*(1-dT*b/m) + (dT/m)*F0*np.cos(Wd*i)
    pos[i+1] = dT*vel[i] + pos[i]

# Ploting
#----------------
# With no damping
plt.plot(time, pos, 'g-', label='Undampened')

# Damping set to 10% of critical damping
b = (freqNatural/50)*0.1

# Using Euler's again to compute new values for new damping
for i in range(0, steps):
    vel[i+1] = (-k/m)*dT*pos[i] + vel[i]*(1-(dT*(b/m))) + (F0*dT/m)*np.cos(Wd*i)
    pos[i+1] = dT*vel[i] + pos[i]

plt.plot(time, pos, 'b-', label = '10% of crit. damping')
plt.plot(time, 0*time, 'k-')      # This plots the x-axis
plt.legend(loc = 'upper right')

#---------------
plt.show()

The problem here is with the term np.cos(Wd*i) .这里的问题在于术语np.cos(Wd*i) It should be np.cos(Wd*i*dT) , that is note that dT has been added into the correct equation, since t = i*dT .它应该是np.cos(Wd*i*dT) ,注意dT已添加到正确的方程中,因为t = i*dT

If this correction is made, the simulation looks reasonable.如果进行了此更正,则模拟看起来是合理的。 Here's a version with F0=0.001 .这是F0=0.001的版本。 Note that the driving force is clear in the continued oscillations in the damped condition.请注意,在阻尼条件下的持续振荡中,驱动力是明确的。

在此处输入图片说明

The problem with the original equation is that np.cos(Wd*i) just jumps randomly around the circle, rather than smoothly moving around the circle, causing no net effect in the end.原方程的问题是np.cos(Wd*i)只是绕着圆随机跳跃,而不是平滑地绕着圆移动,最终没有造成任何净效应。 This can be best seen by plotting it directly, but the easiest thing to do is run the original form with F0 very large.通过直接绘制可以最好地看到这一点,但最简单的方法是运行带有非常大的F0的原始表单。 Below is F0 = 10 (ie, 10000x the value used in the correct equation), but using the incorrect form of the equation, and it's clear that the driving force here just adds noise as it randomly moves around the circle.下面是F0 = 10 (即正确方程中使用的值的 10000 倍),但使用了不正确的方程形式,很明显,这里的驱动力只是在它绕圆随机移动时增加了噪音。

在此处输入图片说明

Note that your ODE is well behaved and has an analytical solution.请注意,您的 ODE 表现良好并且具有解析解。 So you could utilize sympy for an alternate approach:因此,您可以将 sympy 用于替代方法:

import sympy as sy    
sy.init_printing()  # Pretty printer for IPython

t,k,m,b,F0,Wd = sy.symbols('t,k,m,b,F0,Wd', real=True)  # constants

consts = {k:  0.1, # values
          m:  0.01,
          b:  0.0,
          F0: 0.01,
          Wd: 7.0}

x = sy.Function('x')(t)  # declare variables
dx = sy.Derivative(x, t)
d2x = sy.Derivative(x, t, 2)

# the ODE:
ode1 = sy.Eq(m*d2x + b*dx + k*x, F0*sy.cos(Wd*t))

sl1 = sy.dsolve(ode1, x) # solve ODE
xs1 = sy.simplify(sl1.subs(consts)).rhs # substitute constants


# Examining the solution, we note C3 and C4 are superfluous
xs2 = xs1.subs({'C3':0, 'C4':0})
dxs2 = xs2.diff(t)

print("Solution x(t) = ")
print(xs2)
print("Solution x'(t) = ")
print(dxs2)

gives

Solution x(t) = 
C1*sin(3.16227766016838*t) + C2*cos(3.16227766016838*t) - 0.0256410256410256*cos(7.0*t)
Solution x'(t) = 
3.16227766016838*C1*cos(3.16227766016838*t) - 3.16227766016838*C2*sin(3.16227766016838*t) + 0.179487179487179*sin(7.0*t)

The constants C1,C2 can be determined by evaluating x(0),x'(0) for the initial conditions.常数C1,C2可以通过评估初始条件的x(0),x'(0)来确定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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