代码之家  ›  专栏  ›  技术社区  ›  MaximeJaccon

优化Odint

  •  0
  • MaximeJaccon  · 技术社区  · 1 年前

    我正在使用scipy.odint()模拟双摆翻转时间。我的代码是结构化的,scipy在给定的时间内解决了整个系统;那么我必须检查阵列,看看是否发生了翻转。我想检查,在解决每个步骤后,是否满足条件,然后不需要解决数组的其余部分。

    这是我当前的代码:

    from matplotlib.colors import LogNorm, Normalize
    from scipy.integrate import odeint
    import matplotlib.pyplot as plt
    from tqdm import tqdm
    import seaborn as sns
    import numpy as np
    
    def ode(y, t, length_1, length_2, mass_1, mass_2, gravity):
        angle_1, angle_1_d, angle_2, angle_2_d = y
        angle_1_dd = (-gravity * (2 * mass_1 + mass_2) * np.sin(angle_1) - mass_2 * gravity * np.sin(angle_1 - 2 * angle_2) - 2 * np.sin(angle_1 - angle_2) * mass_2 * (angle_2_d ** 2 * length_2 + angle_1_d ** 2 * length_1 * np.cos(angle_1 - angle_2))) / (length_1 * (2 * mass_1 + mass_2 - mass_2 * np.cos(2 * angle_1 - 2 * angle_2)))
        angle_2_dd = (2 * np.sin(angle_1 - angle_2) * (angle_1_d ** 2 * length_1 * (mass_1 + mass_2) + gravity * (mass_1 + mass_2) * np.cos(angle_1) + angle_2_d ** 2 * length_2 * mass_2 * np.cos(angle_1 - angle_2))) / (length_2 * (2 * mass_1 + mass_2 - mass_2 * np.cos(2 * angle_1 - 2 * angle_2)))
    
        return [angle_1_d, angle_1_dd, angle_2_d, angle_2_dd]
    
    def double_pendulum(length_1, length_2, mass_1, mass_2, angle_1_init, angle_2_init, angle_1_d_init, angle_2_d_init, gravity, dt, num_steps):
        time_span = np.linspace(0, dt*num_steps, num_steps)
        y0 = [np.deg2rad(angle_1_init), np.deg2rad(angle_1_d_init), np.deg2rad(angle_2_init), np.deg2rad(angle_2_d_init)]
        sol = odeint(ode, y0, time_span, args=(length_1, length_2, mass_1, mass_2, gravity))
    
        return sol 
    
    def flip(length_1, length_2, mass_1, mass_2, angle_1_init, angle_2_init, angle_1_d_init, angle_2_d_init, gravity, dt, num_steps):
        solution = double_pendulum(length_1, length_2, mass_1, mass_2, angle_1_init, angle_2_init, angle_1_d_init, angle_2_d_init, gravity, dt, num_steps)
        #angle_1 = solution[:, 0]
        angle_2 = solution[:, 2]
        for index, angle2 in enumerate(angle_2):
            if abs(angle2 - angle_2_init) >= 2*np.pi:
                return index*dt
        return dt*num_steps
    
    angle_1_range = np.arange(-172, 172, 1)
    angle_2_range = np.arange(-172, 172, 1)
    
    fliptime_matrix = np.zeros((len(angle_1_range), len(angle_2_range)))
    
    for i, angle_1 in tqdm(enumerate(angle_1_range), desc='angle_1'):
        for j, angle_2 in tqdm(enumerate(angle_2_range), desc='angle_2', leave=False):
            fliptime = flip(1, 1, 1, 1, angle_1, angle_2, 0, 0, 9.81, 0.01, 10000)
            fliptime_matrix[i, j] = fliptime
    
    sns.heatmap(fliptime_matrix, square=True, cbar_kws={'label': 'Divergence'}, norm=LogNorm())
    plt.xlabel('Angle 2 (degrees)')
    plt.ylabel('Angle 1 (degrees)')
    plt.title('Fliptime Heatmap')
    plt.gca().invert_yaxis()
    plt.show()
    

    我想在每个状态求解后检查翻转条件(差值大于2*pi),而不是在整个系统(在给定时间内)求解后。我需要指导的主要函数是double_pendulum()和flip()。

    谢谢

    1 回复  |  直到 1 年前
        1
  •  2
  •   Matt Haberland    1 年前

    在初始值问题的语言中,您希望检测一个“事件”。 scipy.integrate.odeint 没有为此提供接口。这是文件中提出的原因之一:

    对于新代码,请使用 scipy.integrate.solve_ivp 以求解微分方程。

    一旦您将代码转换为使用 solve_ivp ,您可以使用 events 一旦检测到事件就终止集成的参数。事件函数看起来如下所示:

    def event(t, y):
        angle2 = y[2]
        return abs(angle2 - angle_2_init) - 2*np.pi
    event.terminal = True