이중 진자 시뮬레이션

Beginner

This tutorial is from open-source community. Access the source code

소개

이중 진자는 물리학과 수학에서 고전적인 문제입니다. 두 개의 진자가 서로 연결되어 있으며, 두 번째 진자의 움직임은 첫 번째 진자의 움직임에 영향을 받습니다. 이 랩에서는 Python 과 Matplotlib 을 사용하여 이중 진자의 움직임을 시뮬레이션합니다.

VM 팁

VM 시작이 완료되면, 왼쪽 상단 모서리를 클릭하여 Notebook 탭으로 전환하여 실습을 위해 Jupyter Notebook에 접근하십시오.

때로는 Jupyter Notebook 이 로딩을 완료하는 데 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한으로 인해 작업의 유효성 검사는 자동화될 수 없습니다.

학습 중에 문제가 발생하면 언제든지 Labby 에게 문의하십시오. 세션 후 피드백을 제공해주시면 문제를 신속하게 해결해 드리겠습니다.

필요한 라이브러리 가져오기

시뮬레이션을 위해 필요한 라이브러리를 먼저 가져오겠습니다.

from collections import deque
import matplotlib.pyplot as plt
import numpy as np
from numpy import cos, sin
import matplotlib.animation as animation

매개변수 설정

다음으로, 시뮬레이션을 위한 매개변수를 정의합니다. 이러한 매개변수에는 중력 가속도, 각 진자의 길이와 질량, 그리고 시뮬레이션의 시간 간격이 포함됩니다.

G = 9.8  ## 중력 가속도, m/s^2 단위
L1 = 1.0  ## 진자 1 의 길이, m 단위
L2 = 1.0  ## 진자 2 의 길이, m 단위
L = L1 + L2  ## 결합된 진자의 최대 길이
M1 = 1.0  ## 진자 1 의 질량, kg 단위
M2 = 1.0  ## 진자 2 의 질량, kg 단위
t_stop = 2.5  ## 시뮬레이션할 시간 (초)
history_len = 500  ## 표시할 궤적 점의 수

미분 함수 정의

어떤 주어진 시점에서 시스템의 미분을 계산하는 함수를 정의합니다. 이 함수는 시스템의 현재 상태 (각 진자의 각도 및 각속도) 를 입력으로 받아 해당 값의 미분을 반환합니다.

def derivs(t, state):
    dydx = np.zeros_like(state)

    dydx[0] = state[1]

    delta = state[2] - state[0]
    den1 = (M1+M2) * L1 - M2 * L1 * cos(delta) * cos(delta)
    dydx[1] = ((M2 * L1 * state[1] * state[1] * sin(delta) * cos(delta)
                + M2 * G * sin(state[2]) * cos(delta)
                + M2 * L2 * state[3] * state[3] * sin(delta)
                - (M1+M2) * G * sin(state[0]))
               / den1)

    dydx[2] = state[3]

    den2 = (L2/L1) * den1
    dydx[3] = ((- M2 * L2 * state[3] * state[3] * sin(delta) * cos(delta)
                + (M1+M2) * G * sin(state[0]) * cos(delta)
                - (M1+M2) * L1 * state[1] * state[1] * sin(delta)
                - (M1+M2) * G * sin(state[2]))
               / den2)

    return dydx

초기 조건 설정 및 ODE (상미분 방정식) 적분

이제 시뮬레이션을 위한 초기 조건을 설정합니다. 각 진자의 초기 각도와 각속도, 그리고 시뮬레이션의 시간 간격을 설정합니다. 그런 다음 오일러 방법 (Euler's method) 을 사용하여 ODE 를 적분하여 각 시간 단계에서 각 진자의 위치와 속도를 구합니다.

## 0..t_stop 에서 0.02 초 간격으로 샘플링된 시간 배열 생성
dt = 0.01
t = np.arange(0, t_stop, dt)

## th1 과 th2 는 초기 각도 (도)
## w10 과 w20 은 초기 각속도 (초당 도)
th1 = 120.0
w1 = 0.0
th2 = -10.0
w2 = 0.0

## 초기 상태
state = np.radians([th1, w1, th2, w2])

## 오일러 방법을 사용하여 ODE 적분
y = np.empty((len(t), 4))
y[0] = state
for i in range(1, len(t)):
    y[i] = y[i - 1] + derivs(t[i - 1], y[i - 1]) * dt

각 진자의 위치 계산

이제 각 시간 단계에서 각 진자의 위치와 속도를 사용하여 각 진자의 x 및 y 좌표를 계산합니다.

x1 = L1*sin(y[:, 0])
y1 = -L1*cos(y[:, 0])

x2 = L2*sin(y[:, 2]) + x1
y2 = -L2*cos(y[:, 2]) + y1

플롯 설정

이제 시뮬레이션을 위한 플롯을 설정합니다. 진자의 최대 길이에 해당하는 x 및 y 제한이 있는 그림을 만들고, 종횡비를 동일하게 설정하고, 그리드를 추가합니다.

fig = plt.figure(figsize=(5, 4))
ax = fig.add_subplot(autoscale_on=False, xlim=(-L, L), ylim=(-L, 1.))
ax.set_aspect('equal')
ax.grid()

애니메이션 함수 정의

이중 진자의 움직임을 애니메이션화하는 함수를 정의합니다. 이 함수는 현재 시간 단계를 입력으로 받아 각 진자의 위치를 업데이트하는 데 사용합니다. 또한 두 번째 진자의 궤적도 업데이트합니다.

line, = ax.plot([], [], 'o-', lw=2)
trace, = ax.plot([], [], '.-', lw=1, ms=2)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
history_x, history_y = deque(maxlen=history_len), deque(maxlen=history_len)

def animate(i):
    thisx = [0, x1[i], x2[i]]
    thisy = [0, y1[i], y2[i]]

    if i == 0:
        history_x.clear()
        history_y.clear()

    history_x.appendleft(thisx[2])
    history_y.appendleft(thisy[2])

    line.set_data(thisx, thisy)
    trace.set_data(history_x, history_y)
    time_text.set_text(time_template % (i*dt))
    return line, trace, time_text

애니메이션 생성

이제 Matplotlib 의 FuncAnimation 함수를 사용하여 애니메이션을 생성합니다.

ani = animation.FuncAnimation(
    fig, animate, len(y), interval=dt*1000, blit=True)
plt.show()

요약

이 랩에서는 Python 과 Matplotlib 을 사용하여 이중 진자의 움직임을 시뮬레이션했습니다. 시뮬레이션에 대한 매개변수를 설정하고, 시스템의 도함수를 계산하는 함수를 정의했으며, 오일러 방법 (Euler's method) 을 사용하여 ODE 를 적분하고, 각 시간 단계에서 각 진자의 위치를 계산했으며, 이중 진자의 움직임에 대한 애니메이션을 생성했습니다.