Python 3.x 在python中尝试模拟双摆时遇到问题。运行代码会给我错误消息

Python 3.x 在python中尝试模拟双摆时遇到问题。运行代码会给我错误消息,python-3.x,matplotlib,simulation,numerical-integration,runge-kutta,Python 3.x,Matplotlib,Simulation,Numerical Integration,Runge Kutta,我想用python模拟一个双钟摆,我写了下面的代码,但现在我完全被卡住了。我每次运行代码时都会出错,我已经看了好几个小时了,但我不明白为什么会出错,模拟也不起作用 我希望有人能帮我解决这个问题。提前谢谢 您是否尝试过使用调试器分析此问题?你能准备一个复制错误的文件的小版本吗?你可以从哈密顿量准自动地转到系统,正如我在中所探讨的。另请参阅Symphy的物理模块,该模块为该任务准备了程序。您在dHdp_1中的导数中有一个输入错误,它应该是(p_1-p_2*cos(q_1-q_2))。(为什么这些导数

我想用python模拟一个双钟摆,我写了下面的代码,但现在我完全被卡住了。我每次运行代码时都会出错,我已经看了好几个小时了,但我不明白为什么会出错,模拟也不起作用


我希望有人能帮我解决这个问题。提前谢谢

您是否尝试过使用调试器分析此问题?你能准备一个复制错误的文件的小版本吗?你可以从哈密顿量准自动地转到系统,正如我在中所探讨的。另请参阅Symphy的物理模块,该模块为该任务准备了程序。您在
dHdp_1
中的导数中有一个输入错误,它应该是
(p_1-p_2*cos(q_1-q_2))
。(为什么这些导数不是类方法?)!这就解决了问题
from matplotlib import animation
from pylab import *
from scipy import optimize

G = 9.8  # gravitational acceleration


# Kinetic energy
def Ekin(osc):
    return 1 / (2.0 * osc.m * osc.L * osc.L) * (
        osc.p1 * osc.p1 + 2.0 * osc.p2 * osc.p2 - 2.0 * osc.p1 * osc.p2 * cos(osc.q1 - osc.q2)) / (
               1 + (sin(osc.q1 - osc.q2)) ** 2)


# Potential energy
def Epot(osc):
    return osc.m * G * osc.L * (3 - 2 * math.cos(osc.q1) - math.cos(osc.q2))


# Class that holds the parameter and state of a double pendulum
class Oscillator:
    m = 1  # mass of the pendulum bob
    L = 1  # arm length
    t = 0  # the time
    E = 15
    q1 = 0
    q2 = np.pi/2
    p1=0
    p2 = math.sqrt((E-G*(3-2*cos(q1)-cos(q2)))*(1+(sin(q1-q2))**2)*m*L**2)


class Observables:
    def __init__(self):
        self.time = []  # list to store time
        self.q1list = []  # list to store q1
        self.q2list = []  # list to store q2
        self.p1list = []  # list to store p1
        self.p2list = []  # list to store p2
        self.epot = []  # list to store potential energy
        self.ekin = []  # list to store kinetic energy
        self.etot = []  # list to store total energy
        self.poincare_q1 = []  # list to store q1 for Poincare plot
        self.poincare_p1 = []  # list to store p1 for Poincare plot


# Derivate of H with respect to p1
def dHdp1(q1, q2, p1, p2, m, L):
    return (p1-p2)*cos(q1-q2)/(m*L**2*(1+(sin(q1-q2))**2))

# Derivate of H with respect to p2
def dHdp2(q1, q2, p1, p2, m, L):
    return (2*p2-p1*cos(q1-q2))/(m*L**2*(1+(sin(q1-q2))**2))

# Derivate of H with respect to q1
def dHdq1(q1, q2, p1, p2, m, L):
    return 1 / (2.0 * m * L * L) * (
        -2 * (p1 * p1 + 2 * p2 * p2) * cos(q1 - q2) + p1 * p2 * (4 + 2 * (cos(q1 - q2)) ** 2)) * sin(
    q1 - q2) / (1 + (sin(q1 - q2)) ** 2) ** 2 + m * G * L * 2.0 * sin(q1)


# Derivate of H with respect to q2
def dHdq2(q1, q2, p1, p2, m, L):
    return 1 / (2.0 * m * L * L) * (
        2 * (p1 * p1 + 2 * p2 * p2) * cos(q1 - q2) - p1 * p2 * (4 + 2 * (cos(q1 - q2)) ** 2)) * sin(q1 - q2) / (
               1 + (sin(q1 - q2)) ** 2) ** 2 + m * G * L * sin(q2)


class BaseIntegrator:
    dt = 0.01  # time step

    def integrate(self,
              osc,
              obs,
              ):
    """ Perform a single integration step """
        self.timestep(osc, obs)

    """ Append observables to their lists """
        obs.time.append(osc.t)
        obs.q1list.append(osc.q1)
        obs.q2list.append(osc.q2)
        obs.p1list.append(osc.p1)
        obs.p2list.append(osc.p2)
        obs.epot.append(Epot(osc))
        obs.ekin.append(Ekin(osc))
        obs.etot.append(Epot(osc) + Ekin(osc))

    def timestep(self, osc, obs):
    """ Implemented by the child classes """
        pass




# Runge-Kutta 4 integrator
class RK4Integrator(BaseIntegrator):
    def timestep(self, osc, obs):
        dt = self.dt
        dp1dt = -dHdq1(osc.q1, osc.q2, osc.p1, osc.p2, osc.m, osc.L); dp2dt = -dHdq2(osc.q1, osc.q2, osc.p1, osc.p2, osc.m, osc.L); dq1dt = dHdp1(osc.q1, osc.q2, osc.p1, osc.p2, osc.m, osc.L); dq2dt = dHdp2(osc.q1, osc.q2, osc.p1, osc.p2, osc.m, osc.L)
        k1p1 = dt*dp1dt; k1p2 = dt*dp2dt; k1q1 = dq1dt * dt; k1q2 = dq2dt * dt
        k2p1 = dt * (-dHdq1(osc.q1+k1q1/2, osc.q2+k1q2/2, osc.p1+k1p1/2, osc.p2+k1p2/2, osc.m, osc.L))
        k2p2 = dt * (-dHdq2(osc.q1+k1q1/2, osc.q2+k1q2/2, osc.p1+k1p1/2, osc.p2+k1p2/2, osc.m, osc.L))
        k2q1 = dt * dHdp1(osc.q1+k1q1/2, osc.q2+k1q2/2, osc.p1+k1p1/2, osc.p2+k1p2/2, osc.m, osc.L)
        k2q2 = dt * dHdp2(osc.q1+k1q1/2, osc.q2+k1q2/2, osc.p1+k1p1/2, osc.p2+k1p2/2, osc.m, osc.L)
        k3p1 = dt * (-dHdq1(osc.q1+k2q1/2, osc.q2+k2q2/2, osc.p1+k2p1/2, osc.p2+k2p2/2, osc.m, osc.L))
        k3p2 = dt * (-dHdq2(osc.q1+k2q1/2, osc.q2+k2q2/2, osc.p1+k2p1/2, osc.p2+k2p2/2, osc.m, osc.L))
        k3q1 = dt * dHdp1(osc.q1+k2q1/2, osc.q2+k2q2/2, osc.p1+k2p1/2, osc.p2+k2p2/2, osc.m, osc.L)
        k3q2 = dt * dHdp2(osc.q1+k2q1/2, osc.q2+k2q2/2, osc.p1+k2p1/2, osc.p2+k2p2/2, osc.m, osc.L)
        k4p1 = dt * (-dHdq1(osc.q1+k3q1, osc.q2+k3q2, osc.p1+k3p1, osc.p2+k3p2, osc.m, osc.L))
        k4p2 = dt * (-dHdq2(osc.q1+k3q1, osc.q2+k3q2, osc.p1+k3p1, osc.p2+k3p2, osc.m, osc.L))
        k4q1 = dt * dHdp1(osc.q1+k3q1, osc.q2+k3q2, osc.p1+k3p1, osc.p2+k3p2, osc.m, osc.L)
        k4q2 = dt * dHdp2(osc.q1+k3q1, osc.q2+k3q2, osc.p1+k3p1, osc.p2+k3p2, osc.m, osc.L)
        osc.p1 = osc.p1 + 1/6*(k1p1+2*k2p1+2*k3p1+k4p1)
        osc.p2 = osc.p2 + 1/6*(k1p2+2*k2p2+2*k3p2+k4p2)
        osc.q1 = osc.q1 + 1/6*(k1q1+2*k2q1+2*k3q1+k4q1)
        osc.q2 = osc.q2 + 1/6*(k1q2+2*k2q2+2*k3q2+k4q2)
    


# Animation function which integrates a few steps and return a line for the pendulum
def animate(framenr, osc, obs, integrator, pendulum_lines, stepsperframe):
    for it in range(stepsperframe):
        integrator.integrate(osc, obs)

    x1 = math.sin(osc.q1);
    y1 = -math.cos(osc.q1);
    x2 = x1 + math.sin(osc.q2);
    y2 = y1 - math.cos(osc.q2)
    pendulum_lines.set_data([0, x1, x2], [0, y1, y2])
    return pendulum_lines,


class Simulation:

    def run(self,
        integrator,
        tmax=30.,  # final time
        stepsperframe=5,  # how many integration steps between visualising frames
        outfile='energy1.pdf'
        ):
        numframes = int(tmax / (stepsperframe * integrator.dt))

        plt.clf()
        fig = plt.figure()
        ax = plt.subplot(xlim=(-2.2, 2.2), ylim=(-2.2, 2.2))
        plt.axhline(y=0)  # draw a default hline at y=1 that spans the xrange
        plt.axvline(x=0)  # draw a default vline at x=1 that spans the yrange
        pendulum_lines, = ax.plot([], [], lw=5)

        oscillator = Oscillator()
        obs = Observables()
        # Call the animator, blit=True means only re-draw parts that have changed
        anim = animation.FuncAnimation(fig, animate,  # init_func=init,
                                   fargs=[oscillator, obs, integrator, pendulum_lines, stepsperframe],
                                   frames=numframes, interval=25, blit=True, repeat=False)
        plt.show()

        # If you experience problems visualizing the animation and/or
        # the following figures comment out the next line
        plt.waitforbuttonpress(30)

        plt.figure()
        plt.xlabel('q1')
        plt.ylabel('p1')
        plt.plot(obs.q1list, obs.p1list)
        plt.tight_layout()  # adapt the plot area tot the text with larger fonts

        plt.figure()
        plt.xlabel('q2')
        plt.ylabel('p2')
        plt.plot(obs.q2list, obs.p2list)
        plt.tight_layout()  # adapt the plot area tot the text with larger fonts

        plt.figure()
        plt.xlabel('q1')
        plt.ylabel('p1')
        plt.plot(obs.poincare_q1, obs.poincare_p1, 'ro')
        plt.tight_layout()  # adapt the plot area tot the text with larger fonts

        plt.figure()
        plt.xlabel('time')
        plt.ylabel('energy')
        plt.plot(obs.time, obs.epot, obs.time, obs.ekin, obs.time, obs.etot)
        plt.legend(('Epot', 'Ekin', 'Etot'))
        plt.tight_layout()  # adapt the plot area tot the text with larger fonts
        plt.show()


simulation = Simulation()
simulation.run(integrator=RK4Integrator())