import matplotlib.pyplot as plt
G = 9.80665 # 重力加速度
h = 0.01 # 時間刻み幅
def f_v(t, y, v):
"""dv/dt"""
return -G
def f_y(t, y, v):
"""dy/dt"""
return v
def calc_euler_method(t, y, v):
"""オイラー法により次ステップのv, yを計算する"""
v_next = v + f_v(t, y, v) * h
y_next = y + f_y(t, y, v) * h
return v_next, y_next
def calc_runge_kutta_method(t, y, v):
"""4次のルンゲ・クッタ法により次ステップのv, yを計算する
速度vを計算する時の係数をk1〜k4、位置yを計算する時の係数をl1〜l4とする
"""
k1 = f_v(t, y, v) * h
l1 = f_y(t, y, v) * h
k2 = f_v(t + h / 2, y + l1 / 2, v + k1 / 2) * h
l2 = f_y(t + h / 2, y + l1 / 2, v + k1 / 2) * h
k3 = f_v(t + h / 2, y + l2 / 2, v + k2 / 2) * h
l3 = f_y(t + h / 2, y + l2 / 2, v + k2 / 2) * h
k4 = f_v(t + h, y + l3, v + k3) * h
l4 = f_y(t + h, y + l3, v + k3) * h
v_next = v + (k1 + 2 * k2 + 2 * k3 + k4) / 6
y_next = y + (l1 + 2 * l2 + 2 * l3 + l4) / 6
return v_next, y_next
def calc_theoretical_solution(t, y0, v0):
"""理論解を計算する"""
v = -G * t + v0
y = -G * t ** 2 / 2 + v0 * t + y0
return v, y
def freefall(y0, v0):
"""自由落下の計算"""
t = 0.0 # 時刻
t_list = [t]
ve = vr = vt = v0
ye = yr = yt = y0
ye_list = [ye] # yの数値解(オイラー法)
yr_list = [yr] # yの数値解(ルンゲ・クッタ法)
yt_list = [yt] # yの理論解
while ye > 0 and yr > 0 and yt > 0:
t += h
ve, ye = calc_euler_method(t, ye, ve)
vr, yr = calc_runge_kutta_method(t, yr, vr)
vt, yt = calc_theoretical_solution(t, y0, v0)
t_list.append(t)
ye_list.append(ye)
yr_list.append(yr)
yt_list.append(yt)
return t_list, ye_list, yr_list, yt_list
if __name__ == '__main__':
y0 = float(input('初期高度y0:'))
v0 = float(input('初速度v0:'))
# 各種方法で自由落下を計算
t_list, ye_list, yr_list, yt_list = freefall(y0, v0)
# 位置のプロット
plt.title('Freefall (time interval: {}s)'.format(h))
plt.plot(t_list, yt_list, label='theoretical',
color='green', linestyle='None', marker='o', markersize=1.5)
plt.plot(t_list, ye_list, label='Euler', color='blue', linewidth=1)
plt.plot(t_list, yr_list, label='Runge-Kutta', color='red', linewidth=1)
plt.xlabel("time [s]")
plt.ylabel("y [m]")
plt.legend()
plt.show()