.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/control_systems/stability/plot_01_maxwell_on_governors.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_control_systems_stability_plot_01_maxwell_on_governors.py: Maxwell's "On Governors": stability from characteristic roots ============================================================= Governors fitted with integral action to remove droop sometimes "hunted", oscillating with growing amplitude. James Clerk Maxwell (1868) linearised the engine-governor equations and showed that motion is stable exactly when every root of the characteristic polynomial has a negative real part (:func:`~engineeringkit.control_systems.poles`). For the cubic :math:`s^3 + a_1 s^2 + a_2 s + a_3` he found the condition :math:`a_1 a_2 > a_3`: too much integral gain destabilises the governor. .. GENERATED FROM PYTHON SOURCE LINES 15-22 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from engineeringkit.control_systems import feedback, poles, step_response, transfer_function a1, a2 = 2.0, 3.0 # engine damping and governor stiffness .. GENERATED FROM PYTHON SOURCE LINES 23-29 Sweep the integral gain ----------------------- Unity feedback around :math:`k/(s(s^2 + a_1 s + a_2))` gives the cubic above with :math:`a_3 = k`; Maxwell predicts instability for :math:`k > a_1 a_2 = 6`. .. GENERATED FROM PYTHON SOURCE LINES 29-43 .. code-block:: Python gains = np.linspace(0.5, 12, 231) growth = np.array([poles(feedback(transfer_function([k], [1, a1, a2, 0]))).real.max() for k in gains]) critical = gains[np.argmax(growth > 0)] print(f"first unstable gain on the grid: {critical:.2f} (Maxwell: {a1 * a2:.2f})") assert np.all(growth[gains < a1 * a2 - 0.05] < 0) and np.all(growth[gains > a1 * a2 + 0.05] > 0) fig, axes = plt.subplots(1, 2, figsize=(10, 3.8)) axes[0].plot(gains, growth) axes[0].axhline(0, color="k", lw=0.8) axes[0].axvline(a1 * a2, color="C3", ls="--", label="$a_1 a_2$") axes[0].set(xlabel="integral gain $k$", ylabel="largest real part of a root [1/s]") axes[0].legend() .. image-sg:: /api/gallery/control_systems/stability/images/sphx_glr_plot_01_maxwell_on_governors_001.png :alt: plot 01 maxwell on governors :srcset: /api/gallery/control_systems/stability/images/sphx_glr_plot_01_maxwell_on_governors_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none first unstable gain on the grid: 6.00 (Maxwell: 6.00) .. GENERATED FROM PYTHON SOURCE LINES 44-46 Hunting appears past the limit ------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 46-56 .. code-block:: Python t = np.linspace(0, 30, 1501) for k in [3.0, 6.0, 7.0]: _, y = step_response(feedback(transfer_function([k], [1, a1, a2, 0])), t) axes[1].plot(t, y, label=f"$k$ = {k:g}") axes[1].set(xlabel="time [s]", ylabel="speed response", ylim=(-1, 3)) axes[1].legend() fig.tight_layout() plt.show() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.290 seconds) .. _sphx_glr_download_api_gallery_control_systems_stability_plot_01_maxwell_on_governors.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/control_systems/stability/plot_01_maxwell_on_governors.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_maxwell_on_governors.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_maxwell_on_governors.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_maxwell_on_governors.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_