2026-05-12 12:18:14 +02:00
|
|
|
{
|
|
|
|
|
"cells": [
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "d555a3fc",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"# 12 — Stochastic control (Pontryagin LQR)\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"Doc page: [stochastic_control.rst](../../docs/source/algorithms/stochastic_control.rst).\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": 1,
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "630ebe94",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {
|
|
|
|
|
"execution": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"iopub.execute_input": "2026-05-12T14:05:29.702153Z",
|
|
|
|
|
"iopub.status.busy": "2026-05-12T14:05:29.701881Z",
|
|
|
|
|
"iopub.status.idle": "2026-05-12T14:05:30.298994Z",
|
|
|
|
|
"shell.execute_reply": "2026-05-12T14:05:30.297851Z"
|
2026-05-12 12:18:14 +02:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"import numpy as np\n",
|
|
|
|
|
"import matplotlib.pyplot as plt\n",
|
|
|
|
|
"from optimizr import _core as opt\n",
|
2026-05-12 16:07:42 +02:00
|
|
|
"plt.rcParams['figure.figsize'] = (8.5, 4.5)\n",
|
|
|
|
|
"plt.rcParams['figure.dpi'] = 110\n",
|
|
|
|
|
"plt.rcParams['axes.grid'] = True\n",
|
|
|
|
|
"plt.rcParams['grid.alpha'] = 0.3\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "3ece7571",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"## Cellule 1 — LQR scalaire et équation de Riccati\n",
|
2026-05-12 12:18:14 +02:00
|
|
|
"\n",
|
2026-05-12 16:07:42 +02:00
|
|
|
"**Théorème (Kalman, LQR).** Pour le système $\\dot x = ax + bu$ et le\n",
|
|
|
|
|
"coût\n",
|
|
|
|
|
"$$J = \\int_0^T (q x^2 + r u^2)\\,dt + s\\,x(T)^2,$$\n",
|
|
|
|
|
"le contrôle optimal est $u^*(t) = -(b/r)\\,P(t)\\,x(t)$ où $P(t)$\n",
|
|
|
|
|
"satisfait la Riccati rétrograde\n",
|
|
|
|
|
"$$-\\dot P = 2aP - (b^2/r) P^2 + q,\\qquad P(T) = s.$$\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Équation pivot (cas $a = b = q = r = 1$).** Le point fixe\n",
|
|
|
|
|
"stationnaire est $P^* = 1 + \\sqrt{2} \\approx 2.414$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Ce que la cellule vérifie.** Le primitive `pontryagin_lqr` retourne\n",
|
|
|
|
|
"$P(0)$ proche du point fixe pour $T = 5$.\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": 2,
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "b3ac43bf",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {
|
|
|
|
|
"execution": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"iopub.execute_input": "2026-05-12T14:05:30.302507Z",
|
|
|
|
|
"iopub.status.busy": "2026-05-12T14:05:30.302154Z",
|
|
|
|
|
"iopub.status.idle": "2026-05-12T14:05:30.867738Z",
|
|
|
|
|
"shell.execute_reply": "2026-05-12T14:05:30.866267Z"
|
2026-05-12 12:18:14 +02:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [
|
|
|
|
|
{
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
"text": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"P(0) numérique = 2.7321\n",
|
|
|
|
|
"P* analytique = 2.4142\n",
|
|
|
|
|
"P(T) (terminal) = 0.5000\n",
|
|
|
|
|
"Coût optimal = 2.4701\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
2026-05-12 16:07:42 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"data": {
|
|
|
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABYoAAAGXCAYAAAAd72TXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAC540lEQVR4nOzdd3xT5f4H8E+SpulMmw6gLdDBaoFScJQhewqyZIk4QMb9IXpVwIF6FdALKAJ6r4o4EByoCIJe2cOiInsIZbSstkAp0JEmnWmTnN8fpacNbTrTnrT5vF+vvjjPk+ecfPOl9JBvnzyPTBAEAURERERERERERETksORSB0BERERERERERERE0mKhmIiIiIiIiIiIiMjBsVBMRERERERERERE5OBYKCYiIiIiIiIiIiJycCwUExERERERERERETk4FoqJiIiIiIiIiIiIHBwLxUREREREREREREQOjoViIiIiIiIiIiIiIgfHQjERERERERERERGRg2OhmIiIiIiIiIiIiMjBsVBMRERERA3Gxx9/jM8//1zqMIiIiIiIGh0nqQMgIiIiIqqKBQsW4Msvv0RMTIzUoRARERERNTosFBMRERGR3UtLS4NMJsMff/yBkJAQqcMhIiIiImp0uPQEUSOzYMECyGQyJCYmSh1KlUyZMgUymUzqMIiIyM75+flh/vz5LBKXQyaTYcqUKVKHgb59+/Lvh4iIJGMv90NbsZf7akOrMVDtsFBMZOf27dsHmUxm8eXm5obIyEi89dZbyMvLkzrESn3wwQdYu3at1GEQEVEDU9498O6vuLg4cfzatWvxwQcf1Pp5ExMTsWDBAvz999+1vpYt2Fs8RERUMwaDAZ9++ikGDhwIf39/KJVK+Pj4oFevXli6dCm0Wq3UIVI9W7BgAX7++WepwyAScekJogZi3LhxGDVqFAAgNTUVP/74I+bPn48DBw5gx44d4rh//etfmDdvHlQqlVShlvHBBx8gJCSk3N/ufv7551i1alX9B0VERA1G6Xvg3QIDA8XjtWvXIjExES+88EKtni8xMRELFy5ESEgIOnfuXKtr2UJl8eTl5UGhUNR/YEREVGVXr17FiBEjcPr0afTs2ROzZ89GQEAAMjMzceDAAbzxxhv46aefcPjwYalDpXq0cOFCTJ48GaNHjy7z2K5duyAIQv0HRQ6NhWKiBiIqKgqP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
|
|
|
|
|
"text/plain": [
|
|
|
|
|
"<Figure size 1430x418 with 3 Axes>"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"output_type": "display_data"
|
2026-05-12 12:18:14 +02:00
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"res = opt.pontryagin_lqr(\n",
|
|
|
|
|
" a=1.0, b=1.0, q=1.0, r=1.0, s_terminal=0.5,\n",
|
|
|
|
|
" x0=1.0, t_horizon=5.0, n_steps=400,\n",
|
|
|
|
|
")\n",
|
|
|
|
|
"ts = np.array(res['time_grid'])\n",
|
|
|
|
|
"P = np.array(res['riccati'])\n",
|
|
|
|
|
"state = np.array(res['state'])\n",
|
|
|
|
|
"control = np.array(res['control'])\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"P_star = 1.0 + np.sqrt(2.0)\n",
|
|
|
|
|
"print(f\"P(0) numérique = {P[0]:.4f}\")\n",
|
|
|
|
|
"print(f\"P* analytique = {P_star:.4f}\")\n",
|
|
|
|
|
"print(f\"P(T) (terminal) = {P[-1]:.4f}\")\n",
|
|
|
|
|
"print(f\"Coût optimal = {res['cost']:.4f}\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"fig, axes = plt.subplots(1, 3, figsize=(13, 3.8))\n",
|
|
|
|
|
"axes[0].plot(ts, P, lw=2)\n",
|
|
|
|
|
"axes[0].axhline(P_star, ls='--', color='gray',\n",
|
|
|
|
|
" label=f'P* = {P_star:.3f}')\n",
|
|
|
|
|
"axes[0].set_xlabel('t'); axes[0].set_ylabel('P(t)')\n",
|
|
|
|
|
"axes[0].set_title(\"Riccati\"); axes[0].legend()\n",
|
|
|
|
|
"axes[1].plot(ts, state, lw=2, color='C2')\n",
|
|
|
|
|
"axes[1].set_xlabel('t'); axes[1].set_ylabel('x(t)')\n",
|
|
|
|
|
"axes[1].set_title(\"État optimal\")\n",
|
|
|
|
|
"ts_u = ts[:len(control)]\n",
|
|
|
|
|
"axes[2].plot(ts_u, control, lw=2, color='C3')\n",
|
|
|
|
|
"axes[2].set_xlabel('t'); axes[2].set_ylabel('u(t)')\n",
|
|
|
|
|
"axes[2].set_title(\"Commande optimale\")\n",
|
|
|
|
|
"fig.tight_layout(); plt.show()\n"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"id": "274eb1aa",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"**Résultat attendu.** $P(0) \\approx 1 + \\sqrt{2}$ ; l'état $x$\n",
|
|
|
|
|
"décroît rapidement vers $0$ ; la commande est proportionnelle à\n",
|
|
|
|
|
"$-P(t)\\,x(t)/r$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Lecture du graphique.** $P(t)$ plate sur $[0, T-\\epsilon]$ puis\n",
|
|
|
|
|
"descend vers $s = 0.5$ ; trajectoires d'état/commande lisses.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Conclusion.** Le LQR scalaire est validé contre le point fixe\n",
|
|
|
|
|
"analytique.\n"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"id": "790043ec",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## Cellule 2 — Étude paramétrique : sensibilité au coût terminal\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Théorème.** Lorsque $T \\to \\infty$, $P(0)$ tend vers le point fixe\n",
|
|
|
|
|
"indépendamment de $s$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Équation pivot.** $P^* = (a + \\sqrt{a^2 + b^2 q / r}) \\cdot r / b^2$.\n",
|
|
|
|
|
"Pour $a = b = q = r = 1$, $P^* = 1 + \\sqrt{2}$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Ce que la cellule vérifie.** Sweep sur plusieurs valeurs de $s$ et\n",
|
|
|
|
|
"de $T$ : $P(0)$ converge vers $P^*$.\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
"execution_count": 3,
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "0e6af886",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {
|
|
|
|
|
"execution": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"iopub.execute_input": "2026-05-12T14:05:30.870857Z",
|
|
|
|
|
"iopub.status.busy": "2026-05-12T14:05:30.870588Z",
|
|
|
|
|
"iopub.status.idle": "2026-05-12T14:05:31.158164Z",
|
|
|
|
|
"shell.execute_reply": "2026-05-12T14:05:31.155824Z"
|
2026-05-12 12:18:14 +02:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [
|
|
|
|
|
{
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
"text": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"s = 0.1 : P(0) à T=10 = 2.7321\n",
|
|
|
|
|
"s = 0.5 : P(0) à T=10 = 2.7321\n",
|
|
|
|
|
"s = 2.0 : P(0) à T=10 = 2.7321\n",
|
|
|
|
|
"s = 5.0 : P(0) à T=10 = 2.7321\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
2026-05-12 16:07:42 +02:00
|
|
|
},
|
2026-05-12 12:18:14 +02:00
|
|
|
{
|
|
|
|
|
"data": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA5sAAAHjCAYAAACthQuVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AACWU0lEQVR4nOzdd3hT5dsH8O9Juicd6aYTSouADAUHu4qCLSAiw8UQfBE3IFOEIooi1D1RRISfDAUUBEQREERAEQWhRQpldNHd0N0k5/0jNG1omqRt2py23891cZHznOeccyc8pb37LEEURRFEREREREREFiSzdgBERERERETU+jDZJCIiIiIiIotjsklEREREREQWx2STiIiIiIiILI7JJhEREREREVkck00iIiIiIiKyOCabREREREREZHFMNomIiIiIiMjimGwSERERERGRxTHZJCIiIiIiIotjsklERCRRa9asgSAI2L9/v7VDMdv+/fshCALWrFnT7M9OSUnByJEjoVAoIAgCJk6cCAB6r1uKgQMHIjQ01NphmC00NBQDBw60dhhEJDFMNomoTSovL8cnn3yCu+66CwqFAra2tvD09ES/fv2wfPly5OfnWztEojZr//79WLx4MQoKCup13cSJE3HgwAHMmTMHX331Ff7v//6vaQKsp8WLF0MQBN0fmUyGdu3aoV+/fvjqq6+sHZ5ZCgoKsHjx4hb1iw8isj4bawdARNTcLl++jLi4OJw8eRJ9+/bFCy+8AH9/fxQUFODw4cNYuHAhvv32Wxw9etTaoRK1OP3790dpaSlsbW0bfI/9+/cjPj4eEydORLt27cy6pry8HAcPHsTTTz+NWbNm6Z0rLS2FXC5vcDyWsnDhQkRGRkKtVuPy5cv47LPP8NhjjyEtLQ1z587Vq7tnzx6IomilSGsrKChAfHw8ABjswTx79iwEQWjmqIhI6phsElGbUl5ejtjYWJw5cwbr16/HQw89pHf+hRdeQGpqKt5//30rRdh0KioqoNFo4ODgYO1QWj21Wo3y8nI4OTlZO5RmJ5PJrNLGrl69ClEU4enpWeucVNr8kCFD0LdvX93x5MmTERkZiTfeeAMvvviiXkJsZ2dnjRAbzN7e3tohEJEEcRgtEbUpq1evxqlTp/D888/XSjSrBAUF4fXXX9crS0pKwrhx4+Dr6wt7e3uEh4dj1qxZUCqV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
|
2026-05-12 12:18:14 +02:00
|
|
|
"text/plain": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"<Figure size 935x495 with 1 Axes>"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"output_type": "display_data"
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"s_values = [0.1, 0.5, 2.0, 5.0]\n",
|
|
|
|
|
"T_values = [0.5, 1.0, 2.0, 5.0, 10.0]\n",
|
|
|
|
|
"P_star = 1.0 + np.sqrt(2.0)\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"fig, ax = plt.subplots()\n",
|
|
|
|
|
"for s in s_values:\n",
|
|
|
|
|
" p0s = []\n",
|
|
|
|
|
" for T_ in T_values:\n",
|
|
|
|
|
" r = opt.pontryagin_lqr(1.0, 1.0, 1.0, 1.0, s, 1.0, T_, 200)\n",
|
|
|
|
|
" p0s.append(r['riccati'][0])\n",
|
|
|
|
|
" ax.plot(T_values, p0s, 'o-', lw=2, label=f's = {s}')\n",
|
|
|
|
|
" print(f\"s = {s:4.1f} : P(0) à T=10 = {p0s[-1]:.4f}\")\n",
|
|
|
|
|
"ax.axhline(P_star, ls='--', color='black',\n",
|
|
|
|
|
" label=f'P* = {P_star:.3f}')\n",
|
|
|
|
|
"ax.set_xlabel('horizon T'); ax.set_ylabel('P(0)')\n",
|
|
|
|
|
"ax.set_title(\"Convergence vers le point fixe Riccati\")\n",
|
|
|
|
|
"ax.legend()\n",
|
2026-05-12 12:18:14 +02:00
|
|
|
"fig.tight_layout(); plt.show()\n"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "7cd43961",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"**Résultat attendu.** Toutes les courbes convergent vers\n",
|
|
|
|
|
"$P^* \\approx 2.414$ pour $T$ grand.\n",
|
2026-05-12 12:18:14 +02:00
|
|
|
"\n",
|
2026-05-12 16:07:42 +02:00
|
|
|
"**Lecture du graphique.** L'effet du terminal $s$ s'estompe quand $T$\n",
|
|
|
|
|
"augmente.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Conclusion.** En horizon long, le coût terminal devient négligeable.\n"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"id": "65d4c5e1",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"## Cellule 3 — Exemple concret : stabilisation d'un pendule inversé\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Modèle physique.** Pendule inversé linéarisé autour de la verticale\n",
|
|
|
|
|
"$\\ddot\\theta = (g/\\ell)\\theta + (1/m\\ell^2) u$. Pour le mode\n",
|
|
|
|
|
"sur-amorti $(\\dot\\theta \\equiv 0)$ on retient l'équation scalaire\n",
|
|
|
|
|
"$\\dot\\theta = a\\theta + bu$ avec $a = g/\\ell$, $b = 1/(m\\ell^2)$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Équation pivot (Riccati).** $P$ vérifie $-\\dot P = 2aP - (b^2/r)P^2 + q$.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Ce que la cellule vérifie.** Le contrôleur LQR ramène l'angle\n",
|
|
|
|
|
"initial $0.3$ rad vers $0$.\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
2026-05-12 16:07:42 +02:00
|
|
|
"execution_count": 4,
|
|
|
|
|
"id": "7aabb9b7",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {
|
|
|
|
|
"execution": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"iopub.execute_input": "2026-05-12T14:05:31.162225Z",
|
|
|
|
|
"iopub.status.busy": "2026-05-12T14:05:31.161917Z",
|
|
|
|
|
"iopub.status.idle": "2026-05-12T14:05:31.762984Z",
|
|
|
|
|
"shell.execute_reply": "2026-05-12T14:05:31.761885Z"
|
2026-05-12 12:18:14 +02:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"outputs": [
|
2026-05-12 16:07:42 +02:00
|
|
|
{
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
"text": [
|
|
|
|
|
"Angle initial : 0.300 rad (17.2°)\n",
|
|
|
|
|
"Angle final : 5.955e-25 rad\n",
|
|
|
|
|
"Effort max : 6.177\n"
|
|
|
|
|
]
|
|
|
|
|
},
|
2026-05-12 12:18:14 +02:00
|
|
|
{
|
|
|
|
|
"data": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABK4AAAGtCAYAAAA/Njx2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AACZcklEQVR4nOzdeXgTVdsG8Dt70n2ltBRa9rLvVVbZEUSpgii+KIhFKwIqsiurIoqCIojo+yGIImgR8BXZpIAKKAgKsrTsaynQfaFrkvn+gE4Tmu5JJ0nv33VxOTM5M3nmFMz0yTnPkQmCIICIiIiIiIiIiMjOyKUOgIiIiIiIiIiIyBImroiIiIiIiIiIyC4xcUVERERERERERHaJiSsiIiIiIiIiIrJLTFwREREREREREZFdYuKKiIiIiIiIiIjsEhNXRERERERERERkl5i4IiIiIiIiIiIiu8TEFRERERERERER2SUmroiIiIiIiIiIyC4xcUVERCSRc+fOYe7cuTh48KDUoRAREdE9RqMRS5YswYoVK6QOhYjAxBWRJPbt2weZTIY1a9aUq/3cuXMhk8lw+fJl8diaNWsgk8mwb9++Sl/XFi5fvgyZTIa5c+dKFkNZRo8eDZlMJnUYkrDGz8dW/Wfp77QzS01NxeDBg3HkyBF07NhR6nCIiMjOOMIzVVXZ6/PstGnT8O6776Jbt24VPnfMmDFo0aIFjEajDSKznq+//hpardbs9wsie8XEFdV4t2/fxvTp09GqVSt4eHjA3d0dDRo0wOOPP45Vq1aZtd2yZYtTPzyU17FjxzB37lx+0BFVkl6vx5NPPonQ0FD88MMPUKvVUodEROTU8vLy8Pnnn6Nv377w9/eHSqWCj48PunfvjkWLFiE1NVXqEMlOrF69GqtWrcIvv/yC1q1bV+jco0ePYs2aNXj77bchlxf9ql34pd/169fLdZ3r16/j9ddfR7NmzeDq6gp3d3e0adMGs2bNQkpKSrH2hUlO0z9arRZNmjTBG2+8YfHv93/+8x80bNgQU6ZMqdA9EklBKXUARFK6evUqwsPDkZSUhGHDhmHs2LFQq9W4ePEi9u/fj48//hgvvPCC2H7Lli346quvqj159dZbb2H69OnQaDSltuvRowdycnKgUqlsGs+xY8cwb9489OzZE6GhoWavhYSEICcnB0ol//dCFfPss8/i6aefrhFJnBMnTqBPnz547bXXyvx3TUREVXP16lU8+uij+Pfff9GtWze8/vrrCAwMRFpaGg4ePIhZs2bhhx9+wKFDh6QOlVB9z7OW5OXl4ebNm/jll1/Qrl27Cp8/b9481K9fH48//nilY9i+fTuGDx+OgoICjBw5Eq+99hoMBgMOHDiAhQsXYtWqVfj5558txtezZ0/xd5eUlBTs2LEDS5YswS+//IIjR46YPWPJ5XK89tprePHFF3Hy5Em0bNmy0jET2Rp/s6Qa7YMPPsCtW7fw8ccf49VXXy32+s2bNyWIqjilUlmuRJBcLodWq62GiEpW+A0PUUUpFAooFAqpwyi3/Px8GI3GSv19b9euXaUeiImIqGLy8vIwePBgnD59GuvWrcMzzzxj9vrrr7+O69evY/ny5RJFSPeT8nlWo9FgxowZlTr38uXL+PnnnzFnzpxKl1SIi4vDsGHD4O7ujpiYGLRo0UJ8bdy4cXj55ZcxcOBADB48GMePH4efn5/Z+Q0bNsTIkSPF/YkTJyIiIgI//vgjfvrpJwwdOtSs/fDhwzFx4kSsWLGC9bzIrnGqINVo586dAwD06dPH4uu1a9cWt0NDQ/HVV18BgNkw3ML59zdu3MDkyZPRvn17+Pj4QKPRoEmTJnjzzTeRk5NTYgyfffYZmjVrBq1Wi9DQUMydOxd6vd6sjaUaV5ZYqgkgCAKWLVuGdu3awdPTE25ubmjYsCGeeeYZJCQkiO0OHz6MMWPGoGnTpnB1dYWrqys6deqE1atXm73H6NGj8fzzzwMAevXqJfbD6NGjAZRcj8FoNOKTTz5BmzZtoNPp4OHhgd69e+OXX34pdh+hoaHo2bMnzp49iyFDhohxDxo0COfPny+1D0zdunULo0aNgq+vL1xdXdG1a1fs3bvXYtvC97xfRepLFNZp2L17N9555x3Ur18fGo0GTZs2xbJlyyyec+HCBYwePRpBQUFQq9UIDg7GuHHjkJSUZNau8O/A2bNnMXv2bISEhECj0aBZs2ZYt26dxWuvX78ebdq0gVarRZ06dTBp0iRkZ2eXGLel2lIVqWd169YtTJgwAaGhoVCr1QgICMDIkSPLPaXUUhyFx/bu3YuPP/4YTZo0gUajQf369bFkyRKz80eOHAmFQoFr164Vu3Z2djY8PT3RvXt3s+P//PMPhg0bhlq1akGtVqNBgwaYPn16sX4q7Ifk5GS8+OKLCAwMhE6nw59//gkA2LFjB3r37o1atWpBq9UiODgYAwcOxO+//252nczMTLz55pto2rQpNBoNfHx8EBERgX///bdcfURERBXz5Zdf4sSJE3jttdeKJa0KBQcH47333jM7FhcXh6effhoBAQHQaDRo0KABJk+ejIyMDLN2pT2jWRqZXvi8cfz4cfTv3x/u7u7w9PTEE088gQsXLpT7vn744Qc89NBD8PDwgE6nQ7t27fB///d/5T7/u+++Q0REBEJCQqDVauHj44OHH34Y+/fvL/E+rly5gqFDh8Lb2xuurq7o168f/v77b7O2ps9NGzduRPv27aHT6RAYGIjXXnsNWVlZZcZWUo2rzMxMvPrqq+JncPv27REdHW3xZ2Cp7wuZPreaqmqfbty4EUajEY888ki5z7nf7NmzkZ2djZUrV5olrQp169YN77zzDm7cuIEPP/ywXNfs27cvgKLfe0x5enqiW7duiI6OhiAIlY6byNY44opqtIYNGwK4O5f9/fffL3VU08cff4wlS5bg999/x9dffy0e79KlCwDg33//xcaNGxEREYExY8ZAEATs27cPCxcuxD///INt27YVu+by5ctx/fp1REVFwcfHBz/++CPmzZuHCxcumL1HVbz77rt46623MGjQIERGRkKtVuPq1avYsWMHbty4gcDAQADA5s2bcfLkSQwbNgwhISFIT0/H999/jzFjxiAxMRFTp04FALz00kvQaDT44osvMHPmTDRr1sysL0syevRofP311+jatSveffddZGVl4f/+7/8wYMAArF271uzbIQCIj49Hjx498Nhjj+H999/HuXPnsGzZMgwZMgQnTpwwqxtgSUZGBrp3747z589j1KhRCA8Px6lTpzB48OAyY62q6dOnIz09HWPHjoVGo8H69esxceJE3Lp1C++8847Y7tixY+jZsydcXFwwZswYhISE4Ny5c/jss88QExODw4cPw9PT0+zao0aNgkwmw8SJEyGXy7FixQqMHDkSDRs2xIMPPii2W7lyJV5++WU0btwYs2fPhlqtxrp16/Dbb7/Z5J6vXbuGLl26ICsrCy+88AKaNGmC+Ph4fPbZZ9i1axeOHDmCevXqVfr6M2fOREZGBp5//nm4ublh7dq1eOONNxAUFISnn34awN2/Y+vWrcPatWvx5ptvmp2/adMmZGRkmD2o7tixAxEREahbty4mTJiAgIAAHD9+HEuWLMGBAwewd+/eYv9P6Nu3L3x9fTF9+nQYjUbUrl0bv/32GwYPHozmzZtjypQp8PX1xc2bN3Hw4EH8888/YrIsIyMD3bp1E/9OtmnTBqmpqfjvf/+Lzp074/fff0f79u0r3UdERFTc999/DwCIiooq9znHjh1Djx49oNfrMW7cODRo0AD79+/H4sWLERMTgwMHDsDFxaXSMV2/fh29evXCY489hkWLFiE2NhYrV67EwYMHcfToUdSpU6fU8+fMmYP58+ejV69emDNnDnQ6HXbu3ImxY8fi/PnzxZJwlixfvhze3t6IjIxEYGAgrl27hlWrVqFXr1749ddfxefbQnfu3MFDDz2Edu3a4Z133sG1a9ewYsUK9OjRAwcOHECbNm3M2m/duhVLlizBuHHj8MILLyAmJgZLly7FsWPHEBMTU+ER1nq9HgMHDsS
|
2026-05-12 12:18:14 +02:00
|
|
|
"text/plain": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"<Figure size 1210x440 with 2 Axes>"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"output_type": "display_data"
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"g, ell, m = 9.81, 1.0, 1.0\n",
|
|
|
|
|
"a, b = g / ell, 1.0 / (m * ell ** 2)\n",
|
|
|
|
|
"res = opt.pontryagin_lqr(a, b, q=10.0, r=1.0, s_terminal=1.0,\n",
|
|
|
|
|
" x0=0.3, t_horizon=5.0, n_steps=500)\n",
|
|
|
|
|
"ts = np.array(res['time_grid'])\n",
|
|
|
|
|
"theta = np.array(res['state'])\n",
|
|
|
|
|
"u = np.array(res['control'])\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"print(f\"Angle initial : {theta[0]:.3f} rad ({np.degrees(theta[0]):.1f}°)\")\n",
|
|
|
|
|
"print(f\"Angle final : {theta[-1]:.3e} rad\")\n",
|
|
|
|
|
"print(f\"Effort max : {np.abs(u).max():.3f}\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"fig, axes = plt.subplots(1, 2, figsize=(11, 4))\n",
|
|
|
|
|
"axes[0].plot(ts, theta, lw=2, color='C3', label=r'$\\theta(t)$')\n",
|
|
|
|
|
"axes[0].axhline(0, ls='--', color='gray', alpha=0.6)\n",
|
|
|
|
|
"axes[0].set_xlabel('t (s)'); axes[0].set_ylabel(r'$\\theta$ (rad)')\n",
|
|
|
|
|
"axes[0].set_title(\"Stabilisation du pendule inversé\")\n",
|
|
|
|
|
"axes[0].legend()\n",
|
|
|
|
|
"ts_u = ts[:len(u)]\n",
|
|
|
|
|
"axes[1].plot(ts_u, u, lw=2, color='C2', label='u(t)')\n",
|
|
|
|
|
"axes[1].set_xlabel('t (s)'); axes[1].set_ylabel('u (couple)')\n",
|
|
|
|
|
"axes[1].set_title(\"Couple appliqué (LQR)\")\n",
|
|
|
|
|
"axes[1].legend()\n",
|
|
|
|
|
"fig.tight_layout(); plt.show()\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
2026-05-12 16:07:42 +02:00
|
|
|
"id": "f6c1b078",
|
2026-05-12 12:18:14 +02:00
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
2026-05-12 16:07:42 +02:00
|
|
|
"**Résultat attendu.** $\\theta \\to 0$ rapidement, effort borné.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Lecture du graphique.** Décroissance exponentielle de l'angle ;\n",
|
|
|
|
|
"couple initial fort puis amorti.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"**Conclusion.** Le primitive transforme un système naturellement\n",
|
|
|
|
|
"instable ($a = 9.81 > 0$) en système stable, illustration directe\n",
|
|
|
|
|
"du contrôle optimal.\n"
|
2026-05-12 12:18:14 +02:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"metadata": {
|
|
|
|
|
"kernelspec": {
|
2026-05-12 16:07:42 +02:00
|
|
|
"display_name": "rhftlab",
|
2026-05-12 12:18:14 +02:00
|
|
|
"language": "python",
|
2026-05-12 16:07:42 +02:00
|
|
|
"name": "rhftlab"
|
2026-05-12 12:18:14 +02:00
|
|
|
},
|
|
|
|
|
"language_info": {
|
|
|
|
|
"codemirror_mode": {
|
|
|
|
|
"name": "ipython",
|
|
|
|
|
"version": 3
|
|
|
|
|
},
|
|
|
|
|
"file_extension": ".py",
|
|
|
|
|
"mimetype": "text/x-python",
|
|
|
|
|
"name": "python",
|
|
|
|
|
"nbconvert_exporter": "python",
|
|
|
|
|
"pygments_lexer": "ipython3",
|
|
|
|
|
"version": "3.11.13"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"nbformat": 4,
|
|
|
|
|
"nbformat_minor": 5
|
|
|
|
|
}
|