La cycloide¶
On s'intéresse à la trajectoire suivie par un point matériel situé sur la périphérie d'une roue qui roule sans glisser.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import Image
from tqdm import tqdm
Image("Cycloid.png")
Le but est de tracer les coordonnées du point $P$ comme fonction paramétrique du temps.
Le dessin est fait pour une roue qui se déplace de gauche à droite. C'est plus intuitif mais rajoute une petite diffuculté avec les signes!
Le mouvement de $P$ est la superposition d'un movement de translation horizontale à la vitesse $v_c=R\omega$, si $\omega > 0$ est la norme de la vitesse angulaire, et d'un mouvement de rotation, qui se fait dans le sens contraire du sens trigonométrique. Le point $P$ est donc repéré, dans la rotation par $\alpha =- \omega t +\alpha_0$.
De plus on choisit le temps $t=0$ tel que $P$ soit en $O$, origine du repère. Donc $\alpha (t=0)=\alpha_0=-\pi/2$
Le point $P$ a donc pour coordonnées
$$\vec{OP} = \vec{OC} + \vec{CP} = \begin{pmatrix} R \omega t \\R \end{pmatrix} + \begin{pmatrix} R \cos (-\omega t-\pi/2) \\R \sin (-\omega t -\pi/2) \end{pmatrix} = \begin{pmatrix} R \omega t - R \sin (\omega t) \\R - R \cos (\omega t) \end{pmatrix} $$
en appelant $\theta = \omega t$
$$\vec{OP} = \begin{pmatrix} R \theta - R \sin (\theta) \\R - R \cos (\theta) \end{pmatrix} $$
Le centre du cercle $C$ est donné par
$$\vec{OC} = \begin{pmatrix} R \theta \\R \end{pmatrix} $$
Le vecteur vitesse instantanée du point $P$ est obtenu par $\vec v_P= d \vec{OP}/dt$
$$\vec{v}_P = \begin{pmatrix} R \omega - R \omega \cos (\omega t) \\ R \omega \sin (\omega t) \end{pmatrix}= \begin{pmatrix} R \omega (1 - \cos (\theta) \\ R \omega \sin (\theta) \end{pmatrix} $$
# Définition du cercle pour son tracé. Il est composé de T segments
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments for drawing the circle
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Fonction qui calcule :
# P_x; P_y, C_x, vP_x et vP_x
# pour 100 valeurs de theta entre 0 et 9 pi
def gen():
for theta in tqdm(np.linspace(0,9*np.pi,100)):
yield R*(theta-np.sin(theta)), R*(1-np.cos(theta)), R*theta, R*(1 - np.cos(theta)), R*np.sin(theta), theta
def init():
axes[0].set_ylim(0, 20)
axes[0].set_xlim(0, 80)
axes[0].set_xlabel('x')
axes[0].set_ylabel('y')
axes[0].set_aspect('equal')
axes[0].grid()
axes[1].set_ylim(0, 10)
axes[1].set_xlim(0, 80)
#axes[1].set_xlabel('theta / $\pi$')
axes[1].set_xlabel('x')
axes[1].set_ylabel('vitesse x / $\\omega$')
axes[1].grid()
axes[2].set_ylim(-5, 5)
axes[2].set_xlim(0, 80)
#axes[2].set_xlabel('theta / $\pi$')
axes[2].set_xlabel('x')
axes[2].set_ylabel('vitesse y / $\\omega$')
axes[2].grid()
axes[1].legend()
axes[2].legend()
return
def func(data):
x, y, Rt, vx, vy, th = data
time_text.set_text(r'$\theta$ = %.2f $\pi$' % (th/np.pi))
xx.append(x)
yy.append(y)
vx_.append(vx)
vy_.append(vy)
ang.append(th/np.pi)
cx, cy = circle(Rt, R, R)
cycloid.set_data(xx, yy)
line.set_data([x, Rt], [y, R]) # Ensure using lists
circle_line.set_data(cx, cy)
point.set_data([x], [y]) # Ensure using lists
velx.set_data(xx, vx_)
vely.set_data(xx, vy_)
return
fig, axes = plt.subplots(3,1, figsize=(12,12))
time_text = axes[0].text(0.05, 0.8, '', transform=axes[0].transAxes)
#Plot layout setup
R = 3
cycloid, = axes[0].plot([], [], 'r-', lw=3)
line, = axes[0].plot([], [], 'y-', lw=3)
circle_line, = axes[0].plot([], [], 'g', lw=3)
point, = axes[0].plot([], [], 'bo', ms=5)
velx, = axes[1].plot([], [], 'b-', lw=3, label='vitesse x')
vely, = axes[2].plot([], [], 'b-', lw=3, label='vitesse y')
xx, yy = [], []
vx_, vy_ = [], []
ang = []
plt.ioff()
plt.rcParams['animation.html'] = 'html5'
animation = FuncAnimation(fig, func, gen, init_func=init, blit=False, interval=1./36*2500, save_count=100)
animation
99%|█████████▉| 99/100 [00:32<00:00, 3.08it/s]