LoginSignup
119
62

玉が行ったり来たりしてるだけなのになぜか円が回っているように見える現象の数理

Posted at

X で見かけたこの映像。とても不思議。

コードで再現したものが以下。コマが回っているように見える。

vib_flat.gif

一方で、色をつけてかつ軌跡がわかるようにすると、振動しているだけだとはっきりわかる。不思議。

vib_rad.gif

この小さな円に見えるものは、式にすると以下のようになる。ここで $t$ は時間を表現した実数。

$$
\left(x- \frac12 \cos t \right)^2 + \left(y + \frac12 \sin t \right)^2 = \frac14.
$$

これはすなわち $(x, y) = (\frac12 \cos t, - \frac12 \sin t)$ を中心に持つ半径 $\frac12$ の円。

これを $x$ 軸で切り取った断面の様子を見る。すなわち $y=0$ を代入する。すると、 $x$ に関する簡単な2次方程式が出てきて、その解は

$$
x = 0, \cos t
$$

である。

特に $x = \cos t$ であることから、$x$ 軸だけに注目すると点が単振動していることがわかる。

この推論は原点を中心とした回転の操作に対して同様に成立する。 $x$ 軸から $\theta$ だけ回転した軸上の点は以下のように表現できる:

R_{\theta}
\begin{pmatrix}
\cos (t + \theta) \\
0
\end{pmatrix}

, ただし $R_{\theta}$ はベクトルを反時計回りに $\theta$ だけ回転させる回転行列。

実際代入してみるとわかるけれども、任意の $t$ と $\theta$ に対して、この点が上で示した小円の円周上に存在することがわかる。

上で作った gif は、 $\theta$ を 0 から $2 \pi$ の間で 8 ほどピックアップし、この式に基づいてプロットした点を $t$ を変化させながら作ったアニメーション。以下がそのコード。

# %%
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

SPLIT_NUM = 8


def rotation_matrix(theta):
    return np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])


def calculate_trajectory(t, theta):
    initial_vector = np.array([np.cos(t + theta), 0])
    rotated_vector = np.matmul(rotation_matrix(theta), initial_vector)
    return rotated_vector


fig, ax = plt.subplots(figsize=(6, 6))
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)

points = []

# Set initial values with t = 0
thetas = np.linspace(0, 2 * np.pi, SPLIT_NUM)
for i, theta in enumerate(thetas):
    (point,) = ax.plot(*calculate_trajectory(0, theta), "ro")
    points.append(point)

    # # Draw line through origin for each theta
    x_line = 1.5 * np.cos(theta)
    y_line = 1.5 * np.sin(theta)
    ax.plot([-x_line, x_line], [-y_line, y_line], color="black", lw=0.5)


ax.grid(False)
for spine in ax.spines.values():
    spine.set_visible(False)
ax.set_xticks([])
ax.set_yticks([])


def update(frame):
    t = frame / 20.0
    for i, theta in enumerate(thetas):
        color = "red" if i == 3 else "blue"
        color = "blue"
        x, y = calculate_trajectory(t, theta)
        points[i].set_data(x, y)
        points[i].set_color(color)


ani = FuncAnimation(fig, update, frames=range(1000), interval=20)
ani.save("vib_flat.gif", writer="pillow")

おわり。

119
62
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
119
62