{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# TP ECE — Étude cinématique d'un tir au basket-ball\n", "## Terminale spécialité Physique-Chimie\n", "\n", "**Objectif :** À partir du pointage vidéo d'un tir au basket, calculer les vecteurs vitesse et accélération par la méthode des points encadrants, puis comparer $a_y$ à la valeur théorique de $-g$.\n", "\n", "**Durée :** 1h · **Format :** Google Colab, zéro installation\n", "\n", "---\n", "### 📋 Compétences ECE évaluées\n", "- Exploiter des données de pointage vidéo\n", "- Calculer des vecteurs vitesse et accélération (méthode des points encadrants)\n", "- Tracer une trajectoire et représenter les vecteurs\n", "- Rédiger une conclusion chiffrée avec écart relatif" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 📚 Rappels théoriques\n", "\n", "### Méthode des points encadrants\n", "\n", "Pour un enregistrement vidéo à $f$ images/s, la durée entre deux images consécutives est $\\tau = 1/f$.\n", "\n", "Le vecteur vitesse au point $M_i$ est approximé par :\n", "$$\\vec{v}(M_i) \\approx \\frac{\\overrightarrow{M_{i-1}M_{i+1}}}{2\\tau}$$\n", "\n", "soit en coordonnées :\n", "$$v_x(i) = \\frac{x_{i+1} - x_{i-1}}{2\\tau} \\qquad v_y(i) = \\frac{y_{i+1} - y_{i-1}}{2\\tau}$$\n", "\n", "De même pour l'accélération :\n", "$$a_x(i) = \\frac{v_x(i+1) - v_x(i-1)}{2\\tau} \\qquad a_y(i) = \\frac{v_y(i+1) - v_y(i-1)}{2\\tau}$$\n", "\n", "### Chute libre\n", "En l'absence de frottements, seule la pesanteur agit : $\\vec{a} = -g\\,\\vec{j}$ avec $g = 9{,}8$ m/s².\n", "On s'attend donc à $a_x \\approx 0$ et $a_y \\approx -9{,}8$ m/s²." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ── Bibliothèques ──────────────────────────────────────────────────\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import matplotlib.patches as mpatches\n", "\n", "plt.rcParams.update({\n", " 'figure.dpi': 130,\n", " 'font.family': 'DejaVu Sans',\n", " 'axes.grid': True,\n", " 'grid.alpha': 0.4,\n", " 'grid.linestyle': ':'\n", "})\n", "print('✓ Bibliothèques chargées.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 1️⃣ DONNÉES DE POINTAGE\n", "\n", "Remplacez les valeurs ci-dessous par vos propres mesures de pointage.\n", "\n", "**Données exemple fournies** (vidéo à 25 images/s, tir réaliste) — à remplacer par les vôtres.\n", "\n", "⚠️ **Important :** toutes les coordonnées sont en **mètres**, dans le repère de la vidéo (origine en bas à gauche)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ══════════════════════════════════════════════════\n# À COMPLÉTER AVEC VOS DONNÉES DE POINTAGE\n# ══════════════════════════════════════════════════\n\n# Fréquence d'images de la vidéo (images par seconde)\nfps = 25 # ← modifier si votre vidéo est à 30 ou 50 images/s\ntau = 1 / fps # durée entre deux images successives (s)\n\n# Coordonnées du centre du ballon (en mètres), image par image\nx = np.array([\n 0.30, 0.48, 0.67, 0.87, 1.04,\n 1.22, 1.42, 1.60, 1.77, 1.97,\n 2.14, 2.33, 2.52, 2.69, 2.87\n]) # ← remplacer par vos valeurs x (en mètres)\n\ny = np.array([\n 1.00, 1.22, 1.44, 1.63, 1.81,\n 2.00, 2.13, 2.27, 2.38, 2.49,\n 2.58, 2.64, 2.71, 2.74, 2.77\n]) # ← remplacer par vos valeurs y (en mètres)\n\n# ══════════════════════════════════════════════════\n\n# Vérification\nif len(x) != len(y):\n raise ValueError(\"❌ x et y n'ont pas le même nombre de valeurs !\")\nif len(x) < 5:\n raise ValueError(\"❌ Il faut au moins 5 points pour calculer v et a.\")\n\nn = len(x)\nt = np.arange(n) * tau\n\nprint(f\"✓ {n} points de pointage chargés.\")\nprint(f\" τ = {tau:.4f} s (vidéo à {fps} images/s)\")\nprint(f\" Durée totale couverte : {t[-1]:.3f} s\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 2️⃣ CALCUL DES VECTEURS VITESSE ET ACCÉLÉRATION" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Vecteur vitesse — méthode des points encadrants\n", "vx = np.full(n, np.nan)\n", "vy = np.full(n, np.nan)\n", "for i in range(1, n - 1):\n", " vx[i] = (x[i+1] - x[i-1]) / (2 * tau)\n", " vy[i] = (y[i+1] - y[i-1]) / (2 * tau)\n", "\n", "# Vecteur accélération — méthode des points encadrants sur les vitesses\n", "ax_arr = np.full(n, np.nan)\n", "ay_arr = np.full(n, np.nan)\n", "for i in range(2, n - 2):\n", " ax_arr[i] = (vx[i+1] - vx[i-1]) / (2 * tau)\n", " ay_arr[i] = (vy[i+1] - vy[i-1]) / (2 * tau)\n", "\n", "# Norme de la vitesse\n", "v_norme = np.sqrt(np.where(np.isnan(vx), np.nan, vx**2 + vy**2))\n", "\n", "print(\"✓ Calculs effectués.\")\n", "print(f\" Points avec vitesse calculée : {np.sum(~np.isnan(vx))}\")\n", "print(f\" Points avec accélération calculée : {np.sum(~np.isnan(ax_arr))}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 3️⃣ TABLEAU RÉCAPITULATIF" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def fmt(val, decimals=2):\n", " return f\"{val:{10}.{decimals}f}\" if not np.isnan(val) else \" \" * 10\n", "\n", "print(f\"{'i':>3} {'t (s)':>8} {'x (m)':>8} {'y (m)':>8} \"\n", " f\"{'vx (m/s)':>11} {'vy (m/s)':>11} {'|v| (m/s)':>11} \"\n", " f\"{'ax (m/s²)':>11} {'ay (m/s²)':>11}\")\n", "print(\"-\" * 100)\n", "\n", "for i in range(n):\n", " print(f\"{i:>3} {t[i]:>8.3f} {x[i]:>8.2f} {y[i]:>8.2f} \"\n", " f\"{fmt(vx[i])} {fmt(vy[i])} {fmt(v_norme[i])} \"\n", " f\"{fmt(ax_arr[i])} {fmt(ay_arr[i])}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 4️⃣ GRAPHIQUE — Trajectoire + vecteurs vitesse et accélération" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Échelles d'affichage — à ajuster si les flèches sont trop grandes ou trop petites\n", "echelle_v = 0.12 # facteur de mise à l'échelle du vecteur vitesse\n", "echelle_a = 0.015 # facteur de mise à l'échelle du vecteur accélération\n", "\n", "fig, ax_plot = plt.subplots(figsize=(9, 6))\n", "\n", "# Trajectoire\n", "ax_plot.plot(x, y, 'o-', color='#1E3A5F', markersize=5, linewidth=1.2,\n", " label='Trajectoire (points pointés)', zorder=3)\n", "\n", "# Numérotation des points\n", "for i in range(n):\n", " ax_plot.annotate(str(i), (x[i], y[i]),\n", " textcoords='offset points', xytext=(5, 5),\n", " fontsize=7, color='#1E3A5F')\n", "\n", "# Vecteurs vitesse (rouge)\n", "for i in range(n):\n", " if not np.isnan(vx[i]):\n", " ax_plot.quiver(x[i], y[i],\n", " vx[i] * echelle_v, vy[i] * echelle_v,\n", " angles='xy', scale_units='xy', scale=1,\n", " color='#EC5F2A', width=0.005, zorder=4)\n", "\n", "# Vecteurs accélération (violet)\n", "for i in range(n):\n", " if not np.isnan(ax_arr[i]):\n", " ax_plot.quiver(x[i], y[i],\n", " ax_arr[i] * echelle_a, ay_arr[i] * echelle_a,\n", " angles='xy', scale_units='xy', scale=1,\n", " color='#6B3FA0', width=0.005, zorder=4)\n", "\n", "# Légende manuelle\n", "legend_handles = [\n", " mpatches.Patch(color='#1E3A5F', label='Trajectoire'),\n", " mpatches.Patch(color='#EC5F2A', label=f'Vecteur vitesse (×{echelle_v})'),\n", " mpatches.Patch(color='#6B3FA0', label=f'Vecteur accélération (×{echelle_a})')\n", "]\n", "ax_plot.legend(handles=legend_handles, fontsize=9, loc='upper left')\n", "\n", "ax_plot.set_xlabel('x (m)', fontsize=11)\n", "ax_plot.set_ylabel('y (m)', fontsize=11)\n", "ax_plot.set_title('Tir au basket — vecteurs vitesse et accélération', fontsize=12, fontweight='bold')\n", "ax_plot.set_aspect('equal')\n", "plt.tight_layout()\n", "plt.savefig('trajectoire_basket.png', dpi=150, bbox_inches='tight')\n", "plt.show()\n", "print('✓ Graphique sauvegardé : trajectoire_basket.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 5️⃣ EXPLOITATION — Comparaison à $-g$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g_theorique = 9.8 # m/s²\n", "\n", "# Valeurs valides de ax et ay\n", "ax_valides = ax_arr[~np.isnan(ax_arr)]\n", "ay_valides = ay_arr[~np.isnan(ay_arr)]\n", "\n", "ax_moyen = np.mean(ax_valides)\n", "ay_moyen = np.mean(ay_valides)\n", "\n", "ecart_ax = abs(ax_moyen - 0) / g_theorique * 100 # attendu : 0\n", "ecart_ay = abs(ay_moyen - (-g_theorique)) / g_theorique * 100\n", "\n", "print(\"=\" * 55)\n", "print(\"RÉSULTATS\")\n", "print(\"=\" * 55)\n", "print(f\" ax moyen = {ax_moyen:+.2f} m/s² (attendu : 0 m/s²)\")\n", "print(f\" Écart relatif sur ax : {ecart_ax:.1f} %\")\n", "print()\n", "print(f\" ay moyen = {ay_moyen:+.2f} m/s² (attendu : −{g_theorique} m/s²)\")\n", "print(f\" Écart relatif sur ay : {ecart_ay:.1f} %\")\n", "print(\"=\" * 55)\n", "\n", "# Appréciation\n", "if ecart_ay < 5:\n", " appreciation = \"Excellent — accord très satisfaisant avec la théorie.\"\n", "elif ecart_ay < 15:\n", " appreciation = \"Bon accord — écart compatible avec les incertitudes de pointage.\"\n", "else:\n", " appreciation = \"Écart important — vérifier le pointage ou l'étalonnage de l'échelle.\"\n", "print(f\" → {appreciation}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 6️⃣ RÉDACTION DE LA CONCLUSION\n", "\n", "Complétez les pointillés à partir de vos résultats numériques." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Génération automatique d'un modèle de conclusion\n", "conclusion = f\"\"\"\n", "─────────────────────────────────────────────────────────\n", "MODÈLE DE CONCLUSION (à reformuler avec vos propres mots)\n", "─────────────────────────────────────────────────────────\n", "\n", "La valeur moyenne de ay obtenue par la méthode des points encadrants\n", "est ay = {ay_moyen:.2f} m/s².\n", "\n", "La valeur théorique attendue, en l'absence de frottements, est −g = −{g_theorique} m/s².\n", "\n", "L'écart relatif vaut :\n", " E = |ay − (−g)| / g × 100 = |{ay_moyen:.2f} − (−{g_theorique})| / {g_theorique} × 100\n", " = {ecart_ay:.1f} %\n", "\n", "Cet écart {\"est inférieur à 5 %, ce qui indique un très bon accord\" if ecart_ay < 5\n", " else \"est inférieur à 15 %, compatible avec les incertitudes de pointage\" if ecart_ay < 15\n", " else \"est supérieur à 15 % : il convient de vérifier le pointage\"} avec le modèle\n", "de la chute libre sans frottement.\n", "\n", "On peut conclure que le mouvement du ballon est {\"compatible\" if ecart_ay < 15 else \"partiellement compatible\"}\n", "avec celui d'un projectile soumis uniquement à la pesanteur (g = {g_theorique} m/s²).\n", "─────────────────────────────────────────────────────────\n", "\"\"\"\n", "print(conclusion)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 7️⃣ QUESTIONS DE SYNTHÈSE\n", "\n", "Répondez dans les cellules de texte ci-dessous." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q1.** Pourquoi ne peut-on pas calculer $\\vec{v}$ pour les points $M_0$ et $M_{n-1}$ (premier et dernier points) ?\n", "\n", "*(Votre réponse ici)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q2.** Pourquoi les vecteurs $\\vec{a}$ semblent-ils tous pointer dans la même direction ? Quelle est cette direction ?\n", "\n", "*(Votre réponse ici)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q3.** Quelle source d'incertitude explique principalement l'écart entre $a_y$ mesuré et $-g$ théorique ?\n", "\n", "*(Votre réponse ici)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q4.** Si la vidéo avait été enregistrée à 50 images/s au lieu de 25, comment cela aurait-il affecté la précision des calculs ? Justifiez.\n", "\n", "*(Votre réponse ici)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## 📖 Fiche méthode — Rédaction compte-rendu ECE\n", "\n", "| Ce que le jury attend | Formulation type |\n", "|---|---|\n", "| Valeur mesurée avec unité | `ay = −9,6 m/s²` |\n", "| Valeur théorique | `−g = −9,8 m/s²` |\n", "| Calcul de l'écart relatif | `E = |ay − (−g)| / g × 100 = X %` |\n", "| Conclusion de compatibilité | `L'écart est inférieur à 10 %, compatible avec les incertitudes de pointage.` |\n", "| Hypothèse physique testée | `Le ballon est assimilé à un projectile soumis uniquement à la pesanteur.` |\n", "\n", "---\n", "*TP réalisé dans le cadre de la préparation ECE — Terminale spécialité Physique-Chimie.* \n", "*Contact : [prof-prive.com](https://prof-prive.com) — Instagram : @profprive.kom*" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.9.0" }, "colab": { "name": "TP_Basket_ECE_Colab.ipynb", "provenance": [] } }, "nbformat": 4, "nbformat_minor": 4 }