|
125 | 125 | "outputs": [], |
126 | 126 | "source": [ |
127 | 127 | "from scpn_control.control.gain_scheduled_controller import (\n", |
128 | | - " GainScheduledController,\n", |
129 | 128 | " RegimeDetector,\n", |
130 | | - " RegimeController,\n", |
131 | 129 | " OperatingRegime,\n", |
132 | 130 | ")\n", |
133 | 131 | "\n", |
|
227 | 225 | "\n", |
228 | 226 | "# Check stabilization at beta_N = 3.5\n", |
229 | 227 | "rwm_test = RWMPhysics(3.5, beta_nowall, beta_wall, tau_wall)\n", |
230 | | - "print(f\"beta_N=3.5: unstable={rwm_test.is_unstable()}, \"\n", |
231 | | - " f\"gamma_open={rwm_test.growth_rate():.1f} s^-1, \"\n", |
232 | | - " f\"stabilized={ctrl_rwm.is_stabilized(rwm_test)}\")" |
| 228 | + "print(\n", |
| 229 | + " f\"beta_N=3.5: unstable={rwm_test.is_unstable()}, \"\n", |
| 230 | + " f\"gamma_open={rwm_test.growth_rate():.1f} s^-1, \"\n", |
| 231 | + " f\"stabilized={ctrl_rwm.is_stabilized(rwm_test)}\"\n", |
| 232 | + ")" |
233 | 233 | ] |
234 | 234 | }, |
235 | 235 | { |
|
258 | 258 | ")\n", |
259 | 259 | "\n", |
260 | 260 | "# Define uncertainty blocks\n", |
261 | | - "uncertainty = StructuredUncertainty([\n", |
262 | | - " UncertaintyBlock(\"plasma_current\", size=1, bound=0.1, block_type=\"real\"),\n", |
263 | | - " UncertaintyBlock(\"wall_position\", size=1, bound=0.2, block_type=\"complex\"),\n", |
264 | | - "])\n", |
| 261 | + "uncertainty = StructuredUncertainty(\n", |
| 262 | + " [\n", |
| 263 | + " UncertaintyBlock(\"plasma_current\", size=1, bound=0.1, block_type=\"real\"),\n", |
| 264 | + " UncertaintyBlock(\"wall_position\", size=1, bound=0.2, block_type=\"complex\"),\n", |
| 265 | + " ]\n", |
| 266 | + ")\n", |
265 | 267 | "\n", |
266 | 268 | "# Compute mu upper bound for a sample transfer matrix\n", |
267 | 269 | "n = uncertainty.total_size()\n", |
|
273 | 275 | "for omega in freqs:\n", |
274 | 276 | " # Frequency-dependent transfer matrix (simplified)\n", |
275 | 277 | " s = 1j * omega\n", |
276 | | - " M = np.array([\n", |
277 | | - " [1.0 / (s + 10), 0.5 / (s + 20)],\n", |
278 | | - " [0.3 / (s + 5), 1.0 / (s + 15)],\n", |
279 | | - " ])\n", |
| 278 | + " M = np.array(\n", |
| 279 | + " [\n", |
| 280 | + " [1.0 / (s + 10), 0.5 / (s + 20)],\n", |
| 281 | + " [0.3 / (s + 5), 1.0 / (s + 15)],\n", |
| 282 | + " ]\n", |
| 283 | + " )\n", |
280 | 284 | " delta_struct = uncertainty.build_Delta_structure()\n", |
281 | 285 | " mu = compute_mu_upper_bound(M, delta_struct)\n", |
282 | 286 | " mu_vals.append(mu)\n", |
|
313 | 317 | "metadata": {}, |
314 | 318 | "outputs": [], |
315 | 319 | "source": [ |
316 | | - "from scpn_control.control.fault_tolerant_control import FDIMonitor, FaultType\n", |
| 320 | + "from scpn_control.control.fault_tolerant_control import FDIMonitor\n", |
317 | 321 | "\n", |
318 | 322 | "fdi = FDIMonitor(n_sensors=4, n_actuators=3, threshold_sigma=3.0, n_alert=3)\n", |
319 | 323 | "\n", |
|
376 | 380 | "id": "g2", |
377 | 381 | "metadata": {}, |
378 | 382 | "outputs": [], |
379 | | - "source": "from scpn_control.control.shape_controller import (\n PlasmaShapeController,\n ShapeTarget,\n CoilSet,\n)\n\ntarget = ShapeTarget(\n isoflux_points=[(8.2, 0.0), (7.8, 1.5), (6.5, 3.0),\n (5.0, 2.5), (4.5, 0.0), (5.0, -2.5),\n (6.5, -3.0), (7.8, -1.5)],\n gap_points=[(8.5, 0.0, 1.0, 0.0), (4.2, 0.0, -1.0, 0.0)],\n gap_targets=[0.1, 0.08],\n)\n\ncoils = CoilSet(n_coils=6)\n# kernel=None works — ShapeJacobian uses a mock Jacobian for the demo\nshape_ctrl = PlasmaShapeController(target=target, coil_set=coils, kernel=None)\n\n# Simulate shape correction over several iterations\npsi = np.ones((33, 33)) * 0.5 # mock flux grid\ncoil_currents = np.zeros(6)\n\ncorrections = []\nfor i in range(10):\n delta_I = shape_ctrl.step(psi, coil_currents)\n coil_currents = np.clip(coil_currents + delta_I, -coils.max_currents, coils.max_currents)\n corrections.append(np.linalg.norm(delta_I))\n\nplt.figure(figsize=(8, 4))\nplt.semilogy(corrections, \"bo-\", lw=2)\nplt.xlabel(\"Iteration\")\nplt.ylabel(\"|delta_I| [A]\")\nplt.title(\"Shape controller convergence\")\nplt.grid(True, alpha=0.3)\nplt.show()\n\nprint(f\"Final coil currents: {np.round(coil_currents, 1)}\")" |
| 383 | + "source": [ |
| 384 | + "from scpn_control.control.shape_controller import (\n", |
| 385 | + " PlasmaShapeController,\n", |
| 386 | + " ShapeTarget,\n", |
| 387 | + " CoilSet,\n", |
| 388 | + ")\n", |
| 389 | + "\n", |
| 390 | + "target = ShapeTarget(\n", |
| 391 | + " isoflux_points=[(8.2, 0.0), (7.8, 1.5), (6.5, 3.0), (5.0, 2.5), (4.5, 0.0), (5.0, -2.5), (6.5, -3.0), (7.8, -1.5)],\n", |
| 392 | + " gap_points=[(8.5, 0.0, 1.0, 0.0), (4.2, 0.0, -1.0, 0.0)],\n", |
| 393 | + " gap_targets=[0.1, 0.08],\n", |
| 394 | + ")\n", |
| 395 | + "\n", |
| 396 | + "coils = CoilSet(n_coils=6)\n", |
| 397 | + "# kernel=None works — ShapeJacobian uses a mock Jacobian for the demo\n", |
| 398 | + "shape_ctrl = PlasmaShapeController(target=target, coil_set=coils, kernel=None)\n", |
| 399 | + "\n", |
| 400 | + "# Simulate shape correction over several iterations\n", |
| 401 | + "psi = np.ones((33, 33)) * 0.5 # mock flux grid\n", |
| 402 | + "coil_currents = np.zeros(6)\n", |
| 403 | + "\n", |
| 404 | + "corrections = []\n", |
| 405 | + "for i in range(10):\n", |
| 406 | + " delta_I = shape_ctrl.step(psi, coil_currents)\n", |
| 407 | + " coil_currents = np.clip(coil_currents + delta_I, -coils.max_currents, coils.max_currents)\n", |
| 408 | + " corrections.append(np.linalg.norm(delta_I))\n", |
| 409 | + "\n", |
| 410 | + "plt.figure(figsize=(8, 4))\n", |
| 411 | + "plt.semilogy(corrections, \"bo-\", lw=2)\n", |
| 412 | + "plt.xlabel(\"Iteration\")\n", |
| 413 | + "plt.ylabel(\"|delta_I| [A]\")\n", |
| 414 | + "plt.title(\"Shape controller convergence\")\n", |
| 415 | + "plt.grid(True, alpha=0.3)\n", |
| 416 | + "plt.show()\n", |
| 417 | + "\n", |
| 418 | + "print(f\"Final coil currents: {np.round(coil_currents, 1)}\")" |
| 419 | + ] |
380 | 420 | }, |
381 | 421 | { |
382 | 422 | "cell_type": "markdown", |
|
0 commit comments