From 1f2a2520479b0509ac8bb60af13f4bd677d973a8 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 18 May 2019 23:48:59 -0700 Subject: [PATCH 01/12] Updated for Python 3 --- examples/pvtol-lqr-nested.ipynb | 588 +++++++++++++++++++++++++++++++- 1 file changed, 587 insertions(+), 1 deletion(-) diff --git a/examples/pvtol-lqr-nested.ipynb b/examples/pvtol-lqr-nested.ipynb index bb9a51b07..8b0f01676 100644 --- a/examples/pvtol-lqr-nested.ipynb +++ b/examples/pvtol-lqr-nested.ipynb @@ -1 +1,587 @@ -{"nbformat_minor": 0, "cells": [{"source": "#`python-control` Example: Vertical takeoff and landing aircraft\n\nhttp://www.cds.caltech.edu/~murray/wiki/index.php/Python-control/Example:_Vertical_takeoff_and_landing_aircraft\n\nThis page demonstrates the use of the python-control package for analysis and design of a controller for a vectored thrust aircraft model that is used as a running example through the text *Feedback Systems* by Astrom and Murray. This example makes use of MATLAB compatible commands. ", "cell_type": "markdown", "metadata": {}}, {"source": "##System Description\nThis example uses a simplified model for a (planar) vertical takeoff and landing aircraft (PVTOL), as shown below:\n \n\nThe position and orientation of the center of mass of the aircraft is denoted by $(x,y,\\theta)$, $m$ is the mass of the vehicle, $J$ the moment of inertia, $g$ the gravitational constant and $c$ the damping coefficient. The forces generated by the main downward thruster and the maneuvering thrusters are modeled as a pair of forces $F_1$ and $F_2$ acting at a distance $r$ below the aircraft (determined by the geometry of the thrusters).\n\nIt is convenient to redefine the inputs so that the origin is an equilibrium point of the system with zero input. Letting $u_1 =\nF_1$ and $u_2 = F_2 - mg$, the equations can be written in state space form as:\n\n\n##LQR state feedback controller\nThis section demonstrates the design of an LQR state feedback controller for the vectored thrust aircraft example. This example is pulled from Chapter 6 (State Feedback) of [http:www.cds.caltech.edu/~murray/amwiki Astrom and Murray]. The python code listed here are contained the the file pvtol-lqr.py.\n\nTo execute this example, we first import the libraries for SciPy, MATLAB plotting and the python-control package:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 1, "cell_type": "code", "source": "from numpy import * # Grab all of the NumPy functions\nfrom matplotlib.pyplot import * # Grab MATLAB plotting functions\nfrom control.matlab import * # MATLAB-like functions\n%matplotlib inline", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "The parameters for the system are given by", "cell_type": "markdown", "metadata": {}}, {"execution_count": 2, "cell_type": "code", "source": "m = 4; # mass of aircraft\nJ = 0.0475; # inertia around pitch axis\nr = 0.25; # distance to center of force\ng = 9.8; # gravitational constant\nc = 0.05; # damping factor (estimated)\nprint \"m = %f\" % m\nprint \"J = %f\" % J\nprint \"r = %f\" % r\nprint \"g = %f\" % g\nprint \"c = %f\" % c", "outputs": [{"output_type": "stream", "name": "stdout", "text": "m = 4.000000\nJ = 0.047500\nr = 0.250000\ng = 9.800000\nc = 0.050000\n"}], "metadata": {"collapsed": false, "trusted": true}}, {"source": "The linearization of the dynamics near the equilibrium point $x_e = (0, 0, 0, 0, 0, 0)$, $u_e = (0, mg)$ are given by", "cell_type": "markdown", "metadata": {}}, {"execution_count": 3, "cell_type": "code", "source": "# State space dynamics\nxe = [0, 0, 0, 0, 0, 0]; # equilibrium point of interest\nue = [0, m*g]; # (note these are lists, not matrices)", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 4, "cell_type": "code", "source": "# Dynamics matrix (use matrix type so that * works for multiplication)\nA = matrix(\n [[ 0, 0, 0, 1, 0, 0],\n [ 0, 0, 0, 0, 1, 0],\n [ 0, 0, 0, 0, 0, 1],\n [ 0, 0, (-ue[0]*sin(xe[2]) - ue[1]*cos(xe[2]))/m, -c/m, 0, 0],\n [ 0, 0, (ue[0]*cos(xe[2]) - ue[1]*sin(xe[2]))/m, 0, -c/m, 0],\n [ 0, 0, 0, 0, 0, 0 ]])\n\n# Input matrix\nB = matrix(\n [[0, 0], [0, 0], [0, 0],\n [cos(xe[2])/m, -sin(xe[2])/m],\n [sin(xe[2])/m, cos(xe[2])/m],\n [r/J, 0]])\n\n# Output matrix \nC = matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]])\nD = matrix([[0, 0], [0, 0]])", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "To compute a linear quadratic regulator for the system, we write the cost function as\n\n\nwhere $z = z - z_e$ and $v = u - u_e$ represent the local coordinates around the desired equilibrium point $(z_e, u_e)$. We begin with diagonal matrices for the state and input costs:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 5, "cell_type": "code", "source": "Qx1 = diag([1, 1, 1, 1, 1, 1]);\nQu1a = diag([1, 1]);\n(K, X, E) = lqr(A, B, Qx1, Qu1a); K1a = matrix(K);", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "This gives a control law of the form $v = -K z$, which can then be used to derive the control law in terms of the original variables:\n\n\n $$u = v + u_d = - K(z - z_d) + u_d.$$\nwhere $u_d = (0, mg)$ and $z_d = (x_d, y_d, 0, 0, 0, 0)$\n\nSince the `python-control` package only supports SISO systems, in order to compute the closed loop dynamics, we must extract the dynamics for the lateral and altitude dynamics as individual systems. In addition, we simulate the closed loop dynamics using the step command with $K x_d$ as the input vector (assumes that the \"input\" is unit size, with $xd$ corresponding to the desired steady state. The following code performs these operations:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 6, "cell_type": "code", "source": "xd = matrix([[1], [0], [0], [0], [0], [0]]); \nyd = matrix([[0], [1], [0], [0], [0], [0]]); ", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 7, "cell_type": "code", "source": "# Indices for the parts of the state that we want\nlat = (0,2,3,5);\nalt = (1,4);\n\n# Decoupled dynamics\nAx = (A[lat, :])[:, lat]; #! not sure why I have to do it this way\nBx = B[lat, 0]; Cx = C[0, lat]; Dx = D[0, 0];\n \nAy = (A[alt, :])[:, alt]; #! not sure why I have to do it this way\nBy = B[alt, 1]; Cy = C[1, alt]; Dy = D[1, 1];\n\n# Step response for the first input\nH1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx);\n(Tx, Yx) = step(H1ax, T=linspace(0,10,100));\n\n# Step response for the second input\nH1ay = ss(Ay - By*K1a[1,alt], By*K1a[1,alt]*yd[alt,:], Cy, Dy);\n(Ty, Yy) = step(H1ay, T=linspace(0,10,100));", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 8, "cell_type": "code", "source": "plot(Yx.T, Tx, '-', Yy.T, Ty, '--'); hold(True);\nplot([0, 10], [1, 1], 'k-'); hold(True);\nylabel('Position');\nxlabel('Time (s)');\ntitle('Step Response for Inputs');\nlegend(('Yx', 'Yy'), loc='lower right');", "outputs": [{"output_type": "display_data", "data": {"image/png": "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\n6v8DfENdKxw8Sq0AAAAASUVORK5CYII=\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"source": "The plot above shows the $x$ and $y$ positions of the aircraft when it is commanded to move 1 m in each direction. The following shows the $x$ motion for control weights $\\rho = 1, 10^2, 10^4$. A higher weight of the input term in the cost function causes a more sluggish response. It is created using the code:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 9, "cell_type": "code", "source": "# Look at different input weightings\nQu1a = diag([1, 1]); (K1a, X, E) = lqr(A, B, Qx1, Qu1a);\nH1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx);\n\nQu1b = (40**2)*diag([1, 1]); (K1b, X, E) = lqr(A, B, Qx1, Qu1b);\nH1bx = ss(Ax - Bx*K1b[0,lat], Bx*K1b[0,lat]*xd[lat,:],Cx, Dx);\n\nQu1c = (200**2)*diag([1, 1]); (K1c, X, E) = lqr(A, B, Qx1, Qu1c);\nH1cx = ss(Ax - Bx*K1c[0,lat], Bx*K1c[0,lat]*xd[lat,:],Cx, Dx);\n\n[T1, Y1] = step(H1ax, T=linspace(0,10,100));\n[T2, Y2] = step(H1bx, T=linspace(0,10,100));\n[T3, Y3] = step(H1cx, T=linspace(0,10,100));", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 10, "cell_type": "code", "source": "plot(Y1.T, T1, 'b-'); hold(True);\nplot(Y2.T, T2, 'r-'); hold(True);\nplot(Y3.T, T3, 'g-'); hold(True);\nplot([0 ,10], [1, 1], 'k-'); hold(True);\ntitle('Step Response for Inputs');\nylabel('Position');\nxlabel('Time (s)');\nlegend(('Y1','Y2','Y3'),loc='lower right');\naxis([0, 10, -0.1, 1.4]); ", "outputs": [{"output_type": "display_data", "data": {"image/png": "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\ni76yKeGdswAAAABJRU5ErkJggg==\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"source": "##Lateral control using inner/outer loop design\nThis section demonstrates the design of loop shaping controller for the vectored thrust aircraft example. This example is pulled from Chapter 11 [Frequency Domain Design](http:www.cds.caltech.edu/~murray/amwiki) of Astrom and Murray. \n\nTo design a controller for the lateral dynamics of the vectored thrust aircraft, we make use of a \"inner/outer\" loop design methodology. We begin by representing the dynamics using the block diagram\n\n\nwhere\n \nThe controller is constructed by splitting the process dynamics and controller into two components: an inner loop consisting of the roll dynamics $P_i$ and control $C_i$ and an outer loop consisting of the lateral position dynamics $P_o$ and controller $C_o$.\n\nThe closed inner loop dynamics $H_i$ control the roll angle of the aircraft using the vectored thrust while the outer loop controller $C_o$ commands the roll angle to regulate the lateral position.\n\nThe following code imports the libraries that are required and defines the dynamics:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 11, "cell_type": "code", "source": "from matplotlib.pyplot import * # Grab MATLAB plotting functions\nfrom control.matlab import * # MATLAB-like functions", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 12, "cell_type": "code", "source": "# System parameters\nm = 4; # mass of aircraft\nJ = 0.0475; # inertia around pitch axis\nr = 0.25; # distance to center of force\ng = 9.8; # gravitational constant\nc = 0.05; # damping factor (estimated)\nprint \"m = %f\" % m\nprint \"J = %f\" % J\nprint \"r = %f\" % r\nprint \"g = %f\" % g\nprint \"c = %f\" % c", "outputs": [{"output_type": "stream", "name": "stdout", "text": "m = 4.000000\nJ = 0.047500\nr = 0.250000\ng = 9.800000\nc = 0.050000\n"}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 13, "cell_type": "code", "source": "# Transfer functions for dynamics\nPi = tf([r], [J, 0, 0]); # inner loop (roll)\nPo = tf([1], [m, c, 0]); # outer loop (position)", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "For the inner loop, use a lead compensator", "cell_type": "markdown", "metadata": {}}, {"execution_count": 14, "cell_type": "code", "source": "k = 200; a = 2; b = 50\nCi = k*tf([1, a], [1, b]) # lead compensator\nLi = Pi*Ci", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "The closed loop dynamics of the inner loop, $H_i$, are given by", "cell_type": "markdown", "metadata": {}}, {"execution_count": 15, "cell_type": "code", "source": "Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1));", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "Finally, we design the lateral compensator using another lead compenstor", "cell_type": "markdown", "metadata": {}}, {"execution_count": 16, "cell_type": "code", "source": "# Now design the lateral control system\na = 0.02; b = 5; K = 2;\nCo = -K*tf([1, 0.3], [1, 10]); # another lead compensator\nLo = -m*g*Po*Co;", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"source": "The performance of the system can be characterized using the sensitivity function and the complementary sensitivity function:", "cell_type": "markdown", "metadata": {}}, {"execution_count": 17, "cell_type": "code", "source": "L = Co*Hi*Po;\nS = feedback(1, L);\nT = feedback(L, 1);", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 18, "cell_type": "code", "source": "t, y = step(T,T=linspace(0,10,100))\nplot(y, t)\ntitle(\"Step Response\")\ngrid()\nxlabel(\"time (s)\")\nylabel(\"y(t)\")", "outputs": [{"execution_count": 18, "output_type": "execute_result", "data": {"text/plain": ""}, "metadata": {}}, {"output_type": "display_data", "data": {"image/png": "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\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"source": "The frequency response and Nyquist plot for the loop transfer function are computed using the commands", "cell_type": "markdown", "metadata": {}}, {"execution_count": 19, "cell_type": "code", "source": "bode(L);", "outputs": [{"output_type": "display_data", "data": {"image/png": "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\nGZxzH3gVd6cS60xK0lf0tb1b+prkH3p91ekVdHIdxq3S1A1h6kzb30npS24MG78Tjh8DvB8u3A/m\nezOc+ReJC2HfZ2HazfbdF7Sir0l4VKwzyc6nqEPuVNp9M7lN0i8lrS9poqQjgNslzQ9tv5J2atHj\nCNOd3L7MbKNs0zIVX27u8tVlGoWr0mbWOW+HXOXL0Nfkmnnpir5a+UeTvgZaZ9bL0yZVtj36Epxw\nV/YmsyN8/Iuw17bwqW8Dr8C6n4Ffny5xlcS+sP27Yd6bG2nJEa55v/Xw+2uUp/C9x+t/jwfmtKkp\n7b6ZTAZ2A/bKwtcA/4/UkHyszToLr3wPgmA0cOsz2cyyi6Qtr4S3zw8PjQEmwXZfhe3fIHEucBEs\n/zT89d/l2jtKcMF50+0e/KdPrnmAe7L4+Uit5Ypt1OsO2DaxSJ56adXxjcJ5zrulrSx9RbV1U1+e\nuGHWV09rJ3+bndO3ybbgXcHngZ9Of390IHixdr+7Xuor8dniItraejORtDzwQ2AlYIEs2raXy1m+\nKyvfK+o/jvDNVTOct3xZ+gZ1TGHY9VWnV9CPvrneZnMI8Cvp3R+HHd4PK6wPzJbO/Cvc8wd479UN\n6hsVYyYV9ZXqm+sa4ADgIOCTpG6vsc4GzbqFpC1I61MWITU2l9bIY8fU4CAIqpBYCNiU5Jl8U5Lf\nv1OAM22eKtO2fqDos7PdxuRG22tJmuW560RutF1rMWPHkbQo8DPbu9RIi8YkCIKGSCwIfIK0lu1j\nwBWkhuU8m+fKtK0sij472x2Af0FpkeHdWdfUw8BCeQur4Ap4YH/S1r716j+Ogt1ctg9plH8krpXy\n9crWClfFVda3F23sHFkRzlW+DH3V+ftJX638o0lfA82v2TNI+rLwaZL+DiscDTt8GKbsApcfI11w\nJ/x8f+Ay0O4l6Gv0/KlZvo6+euHq5wmU6OhxHdLWvUsDxwFnAO9vofx6wJq8fgB+LHA3aQB+XrIB\neGB74GDg7YCAHwMbNKjb7WiqqmNikTz10qrjG4XznHdLW1n6imrrpr48ccOsr57WTv42e6mvvh6/\nFQ7+Bfg68KNw3Ong94HVK30lPltcRFtb3VydQP+5j8kHSL5hJmXhKZm6AyvK7AF8keRqZaazbYSr\n6rWjmysIgoJITAA+T9rt9VXgJOAkm3tKNaxL9LSbS9K5gElvCNXY9ifbNYR8K+APBQ7NYedxFFsB\n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\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 20, "cell_type": "code", "source": "nyquist(L, (0.0001, 1000));", "outputs": [{"output_type": "display_data", "data": {"image/png": "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\nLKv/D2ULb19b6nZgAAAAAElFTkSuQmCC\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 21, "cell_type": "code", "source": "gangof4(Hi*Po, Co);", "outputs": [{"output_type": "display_data", "data": {"image/png": "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\nAAAASUVORK5CYII=\n", "text/plain": ""}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}], "nbformat": 4, "metadata": {"kernelspec": {"display_name": "Python 2", "name": "python2", "language": "python"}, "language_info": {"mimetype": "text/x-python", "nbconvert_exporter": "python", "version": "2.7.6", "name": "python", "file_extension": ".py", "pygments_lexer": "ipython2", "codemirror_mode": {"version": 2, "name": "ipython"}}}} \ No newline at end of file +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# `python-control` Example: Vertical takeoff and landing aircraft\n", + "\n", + "http://www.cds.caltech.edu/~murray/wiki/index.php/Python-control/Example:_Vertical_takeoff_and_landing_aircraft\n", + "\n", + "This page demonstrates the use of the python-control package for analysis and design of a controller for a vectored thrust aircraft model that is used as a running example through the text *Feedback Systems* by Astrom and Murray. This example makes use of MATLAB compatible commands. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## System Description\n", + "This example uses a simplified model for a (planar) vertical takeoff and landing aircraft (PVTOL), as shown below:\n", + " \n", + "\n", + "The position and orientation of the center of mass of the aircraft is denoted by $(x,y,\\theta)$, $m$ is the mass of the vehicle, $J$ the moment of inertia, $g$ the gravitational constant and $c$ the damping coefficient. The forces generated by the main downward thruster and the maneuvering thrusters are modeled as a pair of forces $F_1$ and $F_2$ acting at a distance $r$ below the aircraft (determined by the geometry of the thrusters).\n", + "\n", + "It is convenient to redefine the inputs so that the origin is an equilibrium point of the system with zero input. Letting $u_1 =\n", + "F_1$ and $u_2 = F_2 - mg$, the equations can be written in state space form as:\n", + "\n", + "\n", + "## LQR state feedback controller\n", + "This section demonstrates the design of an LQR state feedback controller for the vectored thrust aircraft example. This example is pulled from Chapter 6 (State Feedback) of [http:www.cds.caltech.edu/~murray/amwiki Astrom and Murray]. The python code listed here are contained the the file pvtol-lqr.py.\n", + "\n", + "To execute this example, we first import the libraries for SciPy, MATLAB plotting and the python-control package:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from numpy import * # Grab all of the NumPy functions\n", + "from matplotlib.pyplot import * # Grab MATLAB plotting functions\n", + "from control.matlab import * # MATLAB-like functions\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The parameters for the system are given by" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m = 4.000000\n", + "J = 0.047500\n", + "r = 0.250000\n", + "g = 9.800000\n", + "c = 0.050000\n" + ] + } + ], + "source": [ + "m = 4 # mass of aircraft\n", + "J = 0.0475 # inertia around pitch axis\n", + "r = 0.25 # distance to center of force\n", + "g = 9.8 # gravitational constant\n", + "c = 0.05 # damping factor (estimated)\n", + "print(\"m = %f\" % m)\n", + "print(\"J = %f\" % J)\n", + "print(\"r = %f\" % r)\n", + "print(\"g = %f\" % g)\n", + "print(\"c = %f\" % c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The linearization of the dynamics near the equilibrium point $x_e = (0, 0, 0, 0, 0, 0)$, $u_e = (0, mg)$ are given by" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# State space dynamics\n", + "xe = [0, 0, 0, 0, 0, 0] # equilibrium point of interest\n", + "ue = [0, m*g] # (note these are lists, not matrices)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Dynamics matrix (use matrix type so that * works for multiplication)\n", + "A = matrix(\n", + " [[ 0, 0, 0, 1, 0, 0],\n", + " [ 0, 0, 0, 0, 1, 0],\n", + " [ 0, 0, 0, 0, 0, 1],\n", + " [ 0, 0, (-ue[0]*sin(xe[2]) - ue[1]*cos(xe[2]))/m, -c/m, 0, 0],\n", + " [ 0, 0, (ue[0]*cos(xe[2]) - ue[1]*sin(xe[2]))/m, 0, -c/m, 0],\n", + " [ 0, 0, 0, 0, 0, 0 ]])\n", + "\n", + "# Input matrix\n", + "B = matrix(\n", + " [[0, 0], [0, 0], [0, 0],\n", + " [cos(xe[2])/m, -sin(xe[2])/m],\n", + " [sin(xe[2])/m, cos(xe[2])/m],\n", + " [r/J, 0]])\n", + "\n", + "# Output matrix \n", + "C = matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]])\n", + "D = matrix([[0, 0], [0, 0]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To compute a linear quadratic regulator for the system, we write the cost function as\n", + "\n", + "\n", + "where $z = z - z_e$ and $v = u - u_e$ represent the local coordinates around the desired equilibrium point $(z_e, u_e)$. We begin with diagonal matrices for the state and input costs:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "Qx1 = diag([1, 1, 1, 1, 1, 1])\n", + "Qu1a = diag([1, 1])\n", + "(K, X, E) = lqr(A, B, Qx1, Qu1a); K1a = matrix(K)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This gives a control law of the form $v = -K z$, which can then be used to derive the control law in terms of the original variables:\n", + "\n", + "\n", + " $$u = v + u_d = - K(z - z_d) + u_d.$$\n", + "where $u_d = (0, mg)$ and $z_d = (x_d, y_d, 0, 0, 0, 0)$\n", + "\n", + "Since the `python-control` package only supports SISO systems, in order to compute the closed loop dynamics, we must extract the dynamics for the lateral and altitude dynamics as individual systems. In addition, we simulate the closed loop dynamics using the step command with $K x_d$ as the input vector (assumes that the \"input\" is unit size, with $xd$ corresponding to the desired steady state. The following code performs these operations:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "xd = matrix([[1], [0], [0], [0], [0], [0]]) \n", + "yd = matrix([[0], [1], [0], [0], [0], [0]]) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Indices for the parts of the state that we want\n", + "lat = (0,2,3,5)\n", + "alt = (1,4)\n", + "\n", + "# Decoupled dynamics\n", + "Ax = (A[lat, :])[:, lat] #! not sure why I have to do it this way\n", + "Bx, Cx, Dx = B[lat, 0], C[0, lat], D[0, 0]\n", + " \n", + "Ay = (A[alt, :])[:, alt] #! not sure why I have to do it this way\n", + "By, Cy, Dy = B[alt, 1], C[1, alt], D[1, 1]\n", + "\n", + "# Step response for the first input\n", + "H1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx)\n", + "(Tx, Yx) = step(H1ax, T=linspace(0,10,100))\n", + "\n", + "# Step response for the second input\n", + "H1ay = ss(Ay - By*K1a[1,alt], By*K1a[1,alt]*yd[alt,:], Cy, Dy)\n", + "(Ty, Yy) = step(H1ay, T=linspace(0,10,100))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot(Yx.T, Tx, '-', Yy.T, Ty, '--')\n", + "plot([0, 10], [1, 1], 'k-')\n", + "ylabel('Position')\n", + "xlabel('Time (s)')\n", + "title('Step Response for Inputs')\n", + "legend(('Yx', 'Yy'), loc='lower right')\n", + "show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The plot above shows the $x$ and $y$ positions of the aircraft when it is commanded to move 1 m in each direction. The following shows the $x$ motion for control weights $\\rho = 1, 10^2, 10^4$. A higher weight of the input term in the cost function causes a more sluggish response. It is created using the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Look at different input weightings\n", + "Qu1a = diag([1, 1])\n", + "K1a, X, E = lqr(A, B, Qx1, Qu1a)\n", + "H1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx)\n", + "\n", + "Qu1b = (40**2)*diag([1, 1])\n", + "K1b, X, E = lqr(A, B, Qx1, Qu1b)\n", + "H1bx = ss(Ax - Bx*K1b[0,lat], Bx*K1b[0,lat]*xd[lat,:],Cx, Dx)\n", + "\n", + "Qu1c = (200**2)*diag([1, 1])\n", + "K1c, X, E = lqr(A, B, Qx1, Qu1c)\n", + "H1cx = ss(Ax - Bx*K1c[0,lat], Bx*K1c[0,lat]*xd[lat,:],Cx, Dx)\n", + "\n", + "[T1, Y1] = step(H1ax, T=linspace(0,10,100))\n", + "[T2, Y2] = step(H1bx, T=linspace(0,10,100))\n", + "[T3, Y3] = step(H1cx, T=linspace(0,10,100))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot(Y1.T, T1, 'b-')\n", + "plot(Y2.T, T2, 'r-')\n", + "plot(Y3.T, T3, 'g-')\n", + "plot([0 ,10], [1, 1], 'k-')\n", + "title('Step Response for Inputs')\n", + "ylabel('Position')\n", + "xlabel('Time (s)')\n", + "legend(('Y1','Y2','Y3'),loc='lower right')\n", + "axis([0, 10, -0.1, 1.4])\n", + "show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lateral control using inner/outer loop design\n", + "This section demonstrates the design of loop shaping controller for the vectored thrust aircraft example. This example is pulled from Chapter 11 [Frequency Domain Design](http:www.cds.caltech.edu/~murray/amwiki) of Astrom and Murray. \n", + "\n", + "To design a controller for the lateral dynamics of the vectored thrust aircraft, we make use of a \"inner/outer\" loop design methodology. We begin by representing the dynamics using the block diagram\n", + "\n", + "\n", + "where\n", + " \n", + "The controller is constructed by splitting the process dynamics and controller into two components: an inner loop consisting of the roll dynamics $P_i$ and control $C_i$ and an outer loop consisting of the lateral position dynamics $P_o$ and controller $C_o$.\n", + "\n", + "The closed inner loop dynamics $H_i$ control the roll angle of the aircraft using the vectored thrust while the outer loop controller $C_o$ commands the roll angle to regulate the lateral position.\n", + "\n", + "The following code imports the libraries that are required and defines the dynamics:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.pyplot import * # Grab MATLAB plotting functions\n", + "from control.matlab import * # MATLAB-like functions" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m = 4.000000\n", + "J = 0.047500\n", + "r = 0.250000\n", + "g = 9.800000\n", + "c = 0.050000\n" + ] + } + ], + "source": [ + "# System parameters\n", + "m = 4 # mass of aircraft\n", + "J = 0.0475 # inertia around pitch axis\n", + "r = 0.25 # distance to center of force\n", + "g = 9.8 # gravitational constant\n", + "c = 0.05 # damping factor (estimated)\n", + "print(\"m = %f\" % m)\n", + "print(\"J = %f\" % J)\n", + "print(\"r = %f\" % r)\n", + "print(\"g = %f\" % g)\n", + "print(\"c = %f\" % c)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# Transfer functions for dynamics\n", + "Pi = tf([r], [J, 0, 0]) # inner loop (roll)\n", + "Po = tf([1], [m, c, 0]) # outer loop (position)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the inner loop, use a lead compensator" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "k = 200\n", + "a = 2\n", + "b = 50\n", + "Ci = k*tf([1, a], [1, b]) # lead compensator\n", + "Li = Pi*Ci" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The closed loop dynamics of the inner loop, $H_i$, are given by" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we design the lateral compensator using another lead compenstor" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# Now design the lateral control system\n", + "a = 0.02\n", + "b = 5\n", + "K = 2\n", + "Co = -K*tf([1, 0.3], [1, 10]) # another lead compensator\n", + "Lo = -m*g*Po*Co" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The performance of the system can be characterized using the sensitivity function and the complementary sensitivity function:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "L = Co*Hi*Po\n", + "S = feedback(1, L)\n", + "T = feedback(L, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "t, y = step(T, T=linspace(0,10,100))\n", + "plot(y, t)\n", + "title(\"Step Response\")\n", + "grid()\n", + "xlabel(\"time (s)\")\n", + "ylabel(\"y(t)\")\n", + "show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The frequency response and Nyquist plot for the loop transfer function are computed using the commands" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "bode(L)\n", + "show()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "nyquist(L, (0.0001, 1000))\n", + "show()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gangof4(Hi*Po, Co)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (pctest)", + "language": "python", + "name": "pctest" + }, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From bac4d87cf0883ef0740195fa99fde891fd47bfb2 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sun, 19 May 2019 00:06:25 -0700 Subject: [PATCH 02/12] Updated for Python 3 --- examples/secord-matlab.py | 10 +++++++--- examples/type2_type3.py | 20 +++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/secord-matlab.py b/examples/secord-matlab.py index c3cf08277..d11af6be9 100644 --- a/examples/secord-matlab.py +++ b/examples/secord-matlab.py @@ -1,4 +1,4 @@ -# secord.py - demonstrate some standard MATLAB commands +# secord.py - demonstrate some standard MATLAB commands # RMM, 25 May 09 from matplotlib.pyplot import * # Grab MATLAB plotting functions @@ -13,21 +13,25 @@ A = [[0, 1.], [-k/m, -b/m]] B = [[0], [1/m]] C = [[1., 0]] -sys = ss(A, B, C, 0); +sys = ss(A, B, C, 0) # Step response for the system figure(1) yout, T = step(sys) plot(T.T, yout.T) +show() # Bode plot for the system figure(2) -mag,phase,om = bode(sys, logspace(-2, 2),Plot=True) +mag, phase, om = bode(sys, logspace(-2, 2), Plot=True) +show() # Nyquist plot for the system figure(3) nyquist(sys, logspace(-2, 2)) +show() # Root lcous plut for the system figure(4) rlocus(sys) +show() \ No newline at end of file diff --git a/examples/type2_type3.py b/examples/type2_type3.py index 951e5df54..c8fe39155 100644 --- a/examples/type2_type3.py +++ b/examples/type2_type3.py @@ -5,7 +5,7 @@ from matplotlib.pyplot import * # Grab MATLAB plotting functions from control.matlab import * # MATLAB-like functions from scipy import pi -integrator = tf( [0, 1], [1, 0] ) # 1/s +integrator = tf([0, 1], [1, 0]) # 1/s # Parameters defining the system J = 1.0 @@ -28,16 +28,18 @@ # System Transfer Functions # tricky because the disturbance (base motion) is coupled in by friction -closed_loop_type2 = feedback(C_type2*feedback(P,friction),gyro) -disturbance_rejection_type2 = P*friction/(1.+P*friction+P*C_type2) -closed_loop_type3 = feedback(C_type3*feedback(P,friction),gyro) -disturbance_rejection_type3 = P*friction/(1.+P*friction+P*C_type3) +closed_loop_type2 = feedback(C_type2*feedback(P, friction), gyro) +disturbance_rejection_type2 = P*friction/(1. + P*friction+P*C_type2) +closed_loop_type3 = feedback(C_type3*feedback(P, friction), gyro) +disturbance_rejection_type3 = P*friction/(1. + P*friction + P*C_type3) # Bode plot for the system figure(1) -bode(closed_loop_type2, logspace(0,2)*2*pi, dB=True, Hz=True) # blue -bode(closed_loop_type3, logspace(0,2)*2*pi, dB=True, Hz=True) # green +bode(closed_loop_type2, logspace(0, 2)*2*pi, dB=True, Hz=True) # blue +bode(closed_loop_type3, logspace(0, 2)*2*pi, dB=True, Hz=True) # green +show() figure(2) -bode(disturbance_rejection_type2, logspace(0,2)*2*pi, Hz=True) # blue -bode(disturbance_rejection_type3, logspace(0,2)*2*pi, Hz=True) # green +bode(disturbance_rejection_type2, logspace(0, 2)*2*pi, Hz=True) # blue +bode(disturbance_rejection_type3, logspace(0, 2)*2*pi, Hz=True) # green +show() From fa311193ed2b44c6cd2501daa066e11ffb11491e Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 09:16:57 -0700 Subject: [PATCH 03/12] Tested in Python 3.7 --- examples/bode-and-nyquist-plots.ipynb | 123 ++++++++++++++++---------- 1 file changed, 78 insertions(+), 45 deletions(-) diff --git a/examples/bode-and-nyquist-plots.ipynb b/examples/bode-and-nyquist-plots.ipynb index 5a2e94ad0..8aa0df822 100644 --- a/examples/bode-and-nyquist-plots.ipynb +++ b/examples/bode-and-nyquist-plots.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -14,13 +14,13 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%matplotlib nbagg\n", "# only needed when developing python-control\n", - "%load_ext autoreload \n", + "%load_ext autoreload\n", "%autoreload 2" ] }, @@ -33,11 +33,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { + "text/latex": [ + "$$\\frac{1}{s + 1}$$" + ], "text/plain": [ "\n", " 1\n", @@ -50,6 +53,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{1}{0.1592 s + 1}$$" + ], "text/plain": [ "\n", " 1\n", @@ -62,6 +68,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{1}{0.02533 s^2 + 0.1592 s + 1}$$" + ], "text/plain": [ "\n", " 1\n", @@ -74,6 +83,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{s}{0.1592 s + 1}$$" + ], "text/plain": [ "\n", " s\n", @@ -86,6 +98,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{1}{1.021e-10 s^5 + 7.122e-08 s^4 + 4.519e-05 s^3 + 0.003067 s^2 + 0.1767 s + 1}$$" + ], "text/plain": [ "\n", " 1\n", @@ -131,7 +146,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -151,11 +166,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { + "text/latex": [ + "$$\\frac{0.0004998 z + 0.0004998}{z - 0.999}\\quad dt = 0.001$$" + ], "text/plain": [ "\n", "0.0004998 z + 0.0004998\n", @@ -170,6 +188,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{0.003132 z + 0.003132}{z - 0.9937}\\quad dt = 0.001$$" + ], "text/plain": [ "\n", "0.003132 z + 0.003132\n", @@ -184,6 +205,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{6.264 z - 6.264}{z - 0.9937}\\quad dt = 0.001$$" + ], "text/plain": [ "\n", "6.264 z - 6.264\n", @@ -198,6 +222,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{9.839e-06 z^2 + 1.968e-05 z + 9.839e-06}{z^2 - 1.994 z + 0.9937}\\quad dt = 0.001$$" + ], "text/plain": [ "\n", "9.839e-06 z^2 + 1.968e-05 z + 9.839e-06\n", @@ -212,6 +239,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{2.091e-07 z^5 + 1.046e-06 z^4 + 2.091e-06 z^3 + 2.091e-06 z^2 + 1.046e-06 z + 2.091e-07}{z^5 - 4.205 z^4 + 7.155 z^3 - 6.212 z^2 + 2.78 z - 0.5182}\\quad dt = 0.001$$" + ], "text/plain": [ "\n", "2.091e-07 z^5 + 1.046e-06 z^4 + 2.091e-06 z^3 + 2.091e-06 z^2 + 1.046e-06 z + 2.091e-07\n", @@ -226,6 +256,9 @@ }, { "data": { + "text/latex": [ + "$$\\frac{2.731e-10 z^5 + 1.366e-09 z^4 + 2.731e-09 z^3 + 2.731e-09 z^2 + 1.366e-09 z + 2.731e-10}{z^5 - 4.815 z^4 + 9.286 z^3 - 8.968 z^2 + 4.337 z - 0.8405}\\quad dt = 0.00025$$" + ], "text/plain": [ "\n", "2.731e-10 z^5 + 1.366e-09 z^4 + 2.731e-09 z^3 + 2.731e-09 z^2 + 1.366e-09 z + 2.731e-10\n", @@ -270,7 +303,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -830,7 +863,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -1056,7 +1089,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1080,7 +1113,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -1640,7 +1673,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -1866,7 +1899,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1890,7 +1923,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -2450,7 +2483,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -2676,7 +2709,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2700,7 +2733,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -3260,7 +3293,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -3486,7 +3519,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -3510,7 +3543,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -4070,7 +4103,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -4296,7 +4329,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -4321,7 +4354,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -4881,7 +4914,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -5107,7 +5140,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -5131,7 +5164,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -5691,7 +5724,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -5917,7 +5950,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -5943,7 +5976,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -6503,7 +6536,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -6729,7 +6762,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -6754,7 +6787,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -7314,7 +7347,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -7540,7 +7573,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -7564,7 +7597,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -8124,7 +8157,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -8350,7 +8383,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -8370,7 +8403,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -8930,7 +8963,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -9156,7 +9189,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -9181,7 +9214,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -9741,7 +9774,7 @@ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", " this.message.textContent = tooltip;\n", "};\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", "\n", "mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n", "\n", @@ -9967,7 +10000,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -9992,9 +10025,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python (pctest)", "language": "python", - "name": "python3" + "name": "pctest" }, "language_info": { "codemirror_mode": { @@ -10006,7 +10039,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.9" + "version": "3.7.3" } }, "nbformat": 4, From 0d3a65604ad4071c0e4acbae82f391bb89907762 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 12:49:01 -0700 Subject: [PATCH 04/12] Edited to comply with Python PEPs Removed MATLAB-like formatting such as semi-colons, syntax and indenting PEP compliant (using PyCharm), changed imports from `from ___ import *` to things like `import matplotlib.pyplot as plt` and `import numpy as np`, removed tabs --- examples/bdalg-matlab.py | 6 +- examples/genswitch.py | 89 +++++++-------- examples/phaseplots.py | 190 ++++++++++++++++++------------- examples/pvtol-lqr.py | 200 ++++++++++++++++++--------------- examples/pvtol-nested-ss.py | 152 +++++++++++++------------ examples/pvtol-nested.py | 152 +++++++++++++------------ examples/robust_mimo.py | 2 +- examples/robust_siso.py | 2 +- examples/rss-balred.py | 9 +- examples/secord-matlab.py | 26 +++-- examples/slycot-import-test.py | 5 +- examples/test-response.py | 14 ++- examples/tfvis.py | 32 +++--- examples/type2_type3.py | 31 ++--- 14 files changed, 504 insertions(+), 406 deletions(-) diff --git a/examples/bdalg-matlab.py b/examples/bdalg-matlab.py index c3b11b109..8911d6579 100644 --- a/examples/bdalg-matlab.py +++ b/examples/bdalg-matlab.py @@ -10,8 +10,8 @@ sys1ss = ss(A1, B1, C1, 0) sys1tf = ss2tf(sys1ss) -sys2tf = tf([1, 0.5], [1, 5]); -sys2ss = tf2ss(sys2tf); +sys2tf = tf([1, 0.5], [1, 5]) +sys2ss = tf2ss(sys2tf) # Series composition -series1 = sys1ss + sys2ss; +series1 = sys1ss + sys2ss diff --git a/examples/genswitch.py b/examples/genswitch.py index 11f79a36c..46513a36f 100644 --- a/examples/genswitch.py +++ b/examples/genswitch.py @@ -8,75 +8,76 @@ import os import numpy as np -import matplotlib.pyplot as mpl +import matplotlib.pyplot as plt from scipy.integrate import odeint from control import phase_plot, box_grid # Simple model of a genetic switch -# + # This function implements the basic model of the genetic switch # Parameters taken from Gardner, Cantor and Collins, Nature, 2000 def genswitch(y, t, mu=4, n=2): - return (mu / (1 + y[1]**n) - y[0], mu / (1 + y[0]**n) - y[1]) + return mu / (1 + y[1]**n) - y[0], mu / (1 + y[0]**n) - y[1] # Run a simulation from an initial condition tim1 = np.linspace(0, 10, 100) sol1 = odeint(genswitch, [1, 5], tim1) -# Extract the equlibirum points -mu = 4; n = 2; # switch parameters -eqpt = np.empty(3); -eqpt[0] = sol1[0,-1] -eqpt[1] = sol1[1,-1] -eqpt[2] = 0; # fzero(@(x) mu/(1+x^2) - x, 2); +# Extract the equilibrium points +mu = 4; n = 2 # switch parameters +eqpt = np.empty(3) +eqpt[0] = sol1[0, -1] +eqpt[1] = sol1[1, -1] +eqpt[2] = 0 # fzero(@(x) mu/(1+x^2) - x, 2) # Run another simulation showing switching behavior -tim2 = np.linspace(11, 25, 100); -sol2 = odeint(genswitch, sol1[-1,:] + [2, -2], tim2) +tim2 = np.linspace(11, 25, 100) +sol2 = odeint(genswitch, sol1[-1, :] + [2, -2], tim2) # First plot out the curves that define the equilibria u = np.linspace(0, 4.5, 46) -f = np.divide(mu, (1 + u**n)) # mu / (1 + u^n), elementwise +f = np.divide(mu, (1 + u**n)) # mu / (1 + u^n), element-wise -mpl.figure(1); mpl.clf(); -mpl.axis([0, 5, 0, 5]); # box on; -mpl.plot(u, f, '-', f, u, '--') # 'LineWidth', AM_data_linewidth); -mpl.legend(('z1, f(z1)', 'z2, f(z2)')) # legend(lgh, 'boxoff'); -mpl.plot([0, 3], [0, 3], 'k-') # 'LineWidth', AM_ref_linewidth); -mpl.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', - eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3); -mpl.xlabel('z1, f(z2)'); -mpl.ylabel('z2, f(z1)'); +plt.figure(1); plt.clf() +plt.axis([0, 5, 0, 5]) # box on; +plt.plot(u, f, '-', f, u, '--') # 'LineWidth', AM_data_linewidth) +plt.legend(('z1, f(z1)', 'z2, f(z2)')) # legend(lgh, 'boxoff') +plt.plot([0, 3], [0, 3], 'k-') # 'LineWidth', AM_ref_linewidth) +plt.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', + eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3) +plt.xlabel('z1, f(z2)') +plt.ylabel('z2, f(z1)') # Time traces -mpl.figure(3); mpl.clf(); # subplot(221); -mpl.plot(tim1, sol1[:,0], 'b-', tim1, sol1[:,1], 'g--'); -# set(pl, 'LineWidth', AM_data_linewidth); -mpl.plot([tim1[-1], tim1[-1]+1], - [sol1[-1,0], sol2[0,1]], 'ko:', - [tim1[-1], tim1[-1]+1], [sol1[-1,1], sol2[0,0]], 'ko:'); -# set(pl, 'LineWidth', AM_data_linewidth, 'MarkerSize', AM_data_markersize); -mpl.plot(tim2, sol2[:,0], 'b-', tim2, sol2[:,1], 'g--'); -# set(pl, 'LineWidth', AM_data_linewidth); -mpl.axis([0, 25, 0, 5]); +plt.figure(3); plt.clf() # subplot(221) +plt.plot(tim1, sol1[:, 0], 'b-', tim1, sol1[:, 1], 'g--') +# set(pl, 'LineWidth', AM_data_linewidth) +plt.plot([tim1[-1], tim1[-1] + 1], + [sol1[-1, 0], sol2[0, 1]], 'ko:', + [tim1[-1], tim1[-1] + 1], [sol1[-1, 1], sol2[0, 0]], 'ko:') +# set(pl, 'LineWidth', AM_data_linewidth, 'MarkerSize', AM_data_markersize) +plt.plot(tim2, sol2[:, 0], 'b-', tim2, sol2[:, 1], 'g--') +# set(pl, 'LineWidth', AM_data_linewidth) +plt.axis([0, 25, 0, 5]) -mpl.xlabel('Time {\itt} [scaled]'); -mpl.ylabel('Protein concentrations [scaled]'); -mpl.legend(('z1 (A)', 'z2 (B)')) # 'Orientation', 'horizontal'); -# legend(legh, 'boxoff'); +plt.xlabel('Time {\itt} [scaled]') +plt.ylabel('Protein concentrations [scaled]') +plt.legend(('z1 (A)', 'z2 (B)')) # 'Orientation', 'horizontal') +# legend(legh, 'boxoff') # Phase portrait -mpl.figure(2); mpl.clf(); # subplot(221); -mpl.axis([0, 5, 0, 5]); # set(gca, 'DataAspectRatio', [1, 1, 1]); -phase_plot(genswitch, X0 = box_grid([0, 5, 6], [0, 5, 6]), T = 10, - timepts = [0.2, 0.6, 1.2]) +plt.figure(2) +plt.clf() # subplot(221) +plt.axis([0, 5, 0, 5]) # set(gca, 'DataAspectRatio', [1, 1, 1]) +phase_plot(genswitch, X0=box_grid([0, 5, 6], [0, 5, 6]), T=10, + timepts=[0.2, 0.6, 1.2]) # Add the stable equilibrium points -mpl.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', - eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3); +plt.plot(eqpt[0], eqpt[1], 'k.', eqpt[1], eqpt[0], 'k.', + eqpt[2], eqpt[2], 'k.') # 'MarkerSize', AM_data_markersize*3) -mpl.xlabel('Protein A [scaled]'); -mpl.ylabel('Protein B [scaled]'); # 'Rotation', 90); +plt.xlabel('Protein A [scaled]') +plt.ylabel('Protein B [scaled]') # 'Rotation', 90) if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: - mpl.show() + plt.show() diff --git a/examples/phaseplots.py b/examples/phaseplots.py index 0c86522de..a71c029d7 100644 --- a/examples/phaseplots.py +++ b/examples/phaseplots.py @@ -7,12 +7,12 @@ import os import numpy as np -import matplotlib.pyplot as mpl +import matplotlib.pyplot as plt from control.phaseplot import phase_plot -from numpy import pi +from numpy import pi # Clear out any figures that are present -mpl.close('all') +plt.close('all') # # Inverted pendulum @@ -20,52 +20,65 @@ # Define the ODEs for a damped (inverted) pendulum def invpend_ode(x, t, m=1., l=1., b=0.2, g=1): - return (x[1], -b/m*x[1] + (g*l/m) * np.sin(x[0])) + return x[1], -b/m*x[1] + (g*l/m) * np.sin(x[0]) + # Set up the figure the way we want it to look -mpl.figure(); mpl.clf(); -mpl.axis([-2*pi, 2*pi, -2.1, 2.1]); -mpl.title('Inverted pendulum') +plt.figure() +plt.clf() +plt.axis([-2 * pi, 2 * pi, -2.1, 2.1]) +plt.title('Inverted pendulum') # Outer trajectories -phase_plot(invpend_ode, - X0 = [ [-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], - [-1, 2.1], [4.2, 2.1], [5, 2.1], - [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], - [1, -2.1], [-4.2, -2.1], [-5, -2.1] ], - T = np.linspace(0, 40, 200), - logtime = (3, 0.7) ) +phase_plot( + invpend_ode, + X0=[[-2*pi, 1.6], [-2*pi, 0.5], [-1.8, 2.1], + [-1, 2.1], [4.2, 2.1], [5, 2.1], + [2*pi, -1.6], [2*pi, -0.5], [1.8, -2.1], + [1, -2.1], [-4.2, -2.1], [-5, -2.1]], + T=np.linspace(0, 40, 200), + logtime=(3, 0.7) +) # Separatrices -phase_plot(invpend_ode, X0 = [[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0) +phase_plot(invpend_ode, X0=[[-2.3056, 2.1], [2.3056, -2.1]], T=6, lingrid=0) # # Systems of ODEs: damped oscillator example (simulation + phase portrait) # def oscillator_ode(x, t, m=1., b=1, k=1): - return (x[1], -k/m*x[0] - b/m*x[1]) + return x[1], -k/m*x[0] - b/m*x[1] + # Generate a vector plot for the damped oscillator -mpl.figure(); mpl.clf(); -phase_plot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15); -#mpl.plot([0], [0], '.'); -# a=gca; set(a,'FontSize',20); set(a,'DataAspectRatio',[1,1,1]); -mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$'); -mpl.title('Damped oscillator, vector field') +plt.figure() +plt.clf() +phase_plot(oscillator_ode, [-1, 1, 10], [-1, 1, 10], 0.15) +#plt.plot([0], [0], '.') +# a=gca; set(a,'FontSize',20); set(a,'DataAspectRatio',[1,1,1]) +plt.xlabel('$x_1$') +plt.ylabel('$x_2$') +plt.title('Damped oscillator, vector field') # Generate a phase plot for the damped oscillator -mpl.figure(); mpl.clf(); -mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1, 1, 1]); -phase_plot(oscillator_ode, - X0 = [ - [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], - [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] - ], T = np.linspace(0, 8, 80), timepts = [0.25, 0.8, 2, 3]) -mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); -# set(gca,'DataAspectRatio',[1,1,1]); -mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$'); -mpl.title('Damped oscillator, vector field and stream lines') +plt.figure() +plt.clf() +plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1, 1, 1]); +phase_plot( + oscillator_ode, + X0=[ + [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.75, 1], [1, 1], + [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.75, -1], [-1, -1] + ], + T=np.linspace(0, 8, 80), + timepts=[0.25, 0.8, 2, 3] +) +plt.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3) +# set(gca, 'DataAspectRatio', [1,1,1]) +plt.xlabel('$x_1$') +plt.ylabel('$x_2$') +plt.title('Damped oscillator, vector field and stream lines') # # Stability definitions @@ -73,54 +86,81 @@ def oscillator_ode(x, t, m=1., b=1, k=1): # This set of plots illustrates the various types of equilibrium points. # -# Saddle point vector field + def saddle_ode(x, t): - return (x[0] - 3*x[1], -3*x[0] + x[1]); + """Saddle point vector field""" + return x[0] - 3*x[1], -3*x[0] + x[1] + # Asy stable -m = 1; b = 1; k = 1; # default values -mpl.figure(); mpl.clf(); -mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -phase_plot(oscillator_ode, - X0 = [ - [-1,1], [-0.3,1], [0,1], [0.25,1], [0.5,1], [0.7,1], [1,1], [1.3,1], - [1,-1], [0.3,-1], [0,-1], [-0.25,-1], [-0.5,-1], [-0.7,-1], [-1,-1], - [-1.3,-1] - ], T = np.linspace(0, 10, 100), - timepts = [0.3, 1, 2, 3], parms = (m, b, k)); -mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); -# set(gca,'FontSize', 16); -mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$'); -mpl.title('Asymptotically stable point') +m = 1 +b = 1 +k = 1 # default values +plt.figure() +plt.clf() +plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1 1 1]); +phase_plot( + oscillator_ode, + X0=[ + [-1, 1], [-0.3, 1], [0, 1], [0.25, 1], [0.5, 1], [0.7, 1], [1, 1], [1.3, 1], + [1, -1], [0.3, -1], [0, -1], [-0.25, -1], [-0.5, -1], [-0.7, -1], [-1, -1], + [-1.3, -1] + ], + T=np.linspace(0, 10, 100), + timepts=[0.3, 1, 2, 3], + parms=(m, b, k) +) +plt.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3) +# plt.set(gca,'FontSize', 16) +plt.xlabel('$x_1$') +plt.ylabel('$x_2$') +plt.title('Asymptotically stable point') # Saddle -mpl.figure(); mpl.clf(); -mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -phase_plot(saddle_ode, scale = 2, timepts = [0.2, 0.5, 0.8], X0 = - [ [-1, -1], [1, 1], - [-1, -0.95], [-1, -0.9], [-1, -0.8], [-1, -0.6], [-1, -0.4], [-1, -0.2], - [-0.95, -1], [-0.9, -1], [-0.8, -1], [-0.6, -1], [-0.4, -1], [-0.2, -1], - [1, 0.95], [1, 0.9], [1, 0.8], [1, 0.6], [1, 0.4], [1, 0.2], - [0.95, 1], [0.9, 1], [0.8, 1], [0.6, 1], [0.4, 1], [0.2, 1], - [-0.5, -0.45], [-0.45, -0.5], [0.5, 0.45], [0.45, 0.5], - [-0.04, 0.04], [0.04, -0.04] ], T = np.linspace(0, 2, 20)); -mpl.plot([0], [0], 'k.'); # 'MarkerSize', AM_data_markersize*3); -# set(gca,'FontSize', 16); -mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$'); -mpl.title('Saddle point') +plt.figure() +plt.clf() +plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1 1 1]) +phase_plot( + saddle_ode, + scale=2, + timepts=[0.2, 0.5, 0.8], + X0=[ + [-1, -1], [1, 1], + [-1, -0.95], [-1, -0.9], [-1, -0.8], [-1, -0.6], [-1, -0.4], [-1, -0.2], + [-0.95, -1], [-0.9, -1], [-0.8, -1], [-0.6, -1], [-0.4, -1], [-0.2, -1], + [1, 0.95], [1, 0.9], [1, 0.8], [1, 0.6], [1, 0.4], [1, 0.2], + [0.95, 1], [0.9, 1], [0.8, 1], [0.6, 1], [0.4, 1], [0.2, 1], + [-0.5, -0.45], [-0.45, -0.5], [0.5, 0.45], [0.45, 0.5], + [-0.04, 0.04], [0.04, -0.04] + ], + T=np.linspace(0, 2, 20) +) +plt.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3) +# set(gca,'FontSize', 16) +plt.xlabel('$x_1$') +plt.ylabel('$x_2$') +plt.title('Saddle point') # Stable isL -m = 1; b = 0; k = 1; # zero damping -mpl.figure(); mpl.clf(); -mpl.axis([-1, 1, -1, 1]); # set(gca, 'DataAspectRatio', [1 1 1]); -phase_plot(oscillator_ode, timepts = - [pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], - X0 = [ [0.2,0], [0.4,0], [0.6,0], [0.8,0], [1,0], [1.2,0], [1.4,0] ], - T = np.linspace(0, 20, 200), parms = (m, b, k)); -mpl.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3); -# set(gca,'FontSize', 16); -mpl.xlabel('$x_1$'); mpl.ylabel('$x_2$'); -mpl.title('Undamped system\nLyapunov stable, not asympt. stable') +m = 1 +b = 0 +k = 1 # zero damping +plt.figure() +plt.clf() +plt.axis([-1, 1, -1, 1]) # set(gca, 'DataAspectRatio', [1 1 1]); +phase_plot( + oscillator_ode, + timepts=[pi/6, pi/3, pi/2, 2*pi/3, 5*pi/6, pi, 7*pi/6, + 4*pi/3, 9*pi/6, 5*pi/3, 11*pi/6, 2*pi], + X0=[[0.2, 0], [0.4, 0], [0.6, 0], [0.8, 0], [1, 0], [1.2, 0], [1.4, 0]], + T=np.linspace(0, 20, 200), + parms=(m, b, k) +) +plt.plot([0], [0], 'k.') # 'MarkerSize', AM_data_markersize*3) +# plt.set(gca,'FontSize', 16) +plt.xlabel('$x_1$') +plt.ylabel('$x_2$') +plt.title('Undamped system\nLyapunov stable, not asympt. stable') if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: - mpl.show() + plt.show() diff --git a/examples/pvtol-lqr.py b/examples/pvtol-lqr.py index 8412dc2ff..29ba7f4df 100644 --- a/examples/pvtol-lqr.py +++ b/examples/pvtol-lqr.py @@ -8,10 +8,9 @@ # import os - -from numpy import * # Grab all of the NumPy functions -from matplotlib.pyplot import * # Grab MATLAB plotting functions -from control.matlab import * # MATLAB-like functions +import numpy as np +import matplotlib.pyplot as plt # MATLAB plotting functions +from control.matlab import * # MATLAB-like functions # # System dynamics @@ -21,35 +20,37 @@ # # System parameters -m = 4; # mass of aircraft -J = 0.0475; # inertia around pitch axis -r = 0.25; # distance to center of force -g = 9.8; # gravitational constant -c = 0.05; # damping factor (estimated) +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # State space dynamics -xe = [0, 0, 0, 0, 0, 0]; # equilibrium point of interest -ue = [0, m*g]; # (note these are lists, not matrices) +xe = [0, 0, 0, 0, 0, 0] # equilibrium point of interest +ue = [0, m * g] # (note these are lists, not matrices) # Dynamics matrix (use matrix type so that * works for multiplication) -A = matrix( - [[ 0, 0, 0, 1, 0, 0], - [ 0, 0, 0, 0, 1, 0], - [ 0, 0, 0, 0, 0, 1], - [ 0, 0, (-ue[0]*sin(xe[2]) - ue[1]*cos(xe[2]))/m, -c/m, 0, 0], - [ 0, 0, (ue[0]*cos(xe[2]) - ue[1]*sin(xe[2]))/m, 0, -c/m, 0], - [ 0, 0, 0, 0, 0, 0 ]]) +A = np.matrix( + [[0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, (-ue[0] * np.sin(xe[2]) - ue[1] * np.cos(xe[2])) / m, -c / m, 0, 0], + [0, 0, (ue[0] * np.cos(xe[2]) - ue[1] * np.sin(xe[2])) / m, 0, -c / m, 0], + [0, 0, 0, 0, 0, 0]] +) # Input matrix -B = matrix( +B = np.matrix( [[0, 0], [0, 0], [0, 0], - [cos(xe[2])/m, -sin(xe[2])/m], - [sin(xe[2])/m, cos(xe[2])/m], - [r/J, 0]]) + [np.cos(xe[2]) / m, -np.sin(xe[2]) / m], + [np.sin(xe[2]) / m, np.cos(xe[2]) / m], + [r / J, 0]] +) # Output matrix -C = matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]]) -D = matrix([[0, 0], [0, 0]]) +C = np.matrix([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]]) +D = np.matrix([[0, 0], [0, 0]]) # # Construct inputs and outputs corresponding to steps in xy position @@ -69,8 +70,8 @@ # so that xd corresponds to the desired steady state. # -xd = matrix([[1], [0], [0], [0], [0], [0]]); -yd = matrix([[0], [1], [0], [0], [0], [0]]); +xd = np.matrix([[1], [0], [0], [0], [0], [0]]) +yd = np.matrix([[0], [1], [0], [0], [0], [0]]) # # Extract the relevant dynamics for use with SISO library @@ -83,91 +84,104 @@ # # Indices for the parts of the state that we want -lat = (0,2,3,5); -alt = (1,4); +lat = (0, 2, 3, 5) +alt = (1, 4) # Decoupled dynamics -Ax = (A[lat, :])[:, lat]; #! not sure why I have to do it this way -Bx = B[lat, 0]; Cx = C[0, lat]; Dx = D[0, 0]; +Ax = (A[lat, :])[:, lat] # ! not sure why I have to do it this way +Bx = B[lat, 0] +Cx = C[0, lat] +Dx = D[0, 0] -Ay = (A[alt, :])[:, alt]; #! not sure why I have to do it this way -By = B[alt, 1]; Cy = C[1, alt]; Dy = D[1, 1]; +Ay = (A[alt, :])[:, alt] # ! not sure why I have to do it this way +By = B[alt, 1] +Cy = C[1, alt] +Dy = D[1, 1] # Label the plot -clf(); -suptitle("LQR controllers for vectored thrust aircraft (pvtol-lqr)") +plt.clf() +plt.suptitle("LQR controllers for vectored thrust aircraft (pvtol-lqr)") # # LQR design # # Start with a diagonal weighting -Qx1 = diag([1, 1, 1, 1, 1, 1]); -Qu1a = diag([1, 1]); -(K, X, E) = lqr(A, B, Qx1, Qu1a); K1a = matrix(K); +Qx1 = np.diag([1, 1, 1, 1, 1, 1]) +Qu1a = np.diag([1, 1]) +K, X, E = lqr(A, B, Qx1, Qu1a) +K1a = np.matrix(K) # Close the loop: xdot = Ax - B K (x-xd) # Note: python-control requires we do this 1 input at a time # H1a = ss(A-B*K1a, B*K1a*concatenate((xd, yd), axis=1), C, D); -# (T, Y) = step(H1a, T=linspace(0,10,100)); +# (T, Y) = step(H1a, T=np.linspace(0,10,100)); # Step response for the first input -H1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx); -(Yx, Tx) = step(H1ax, T=linspace(0,10,100)); +H1ax = ss(Ax - Bx * K1a[0, lat], Bx * K1a[0, lat] * xd[lat, :], Cx, Dx) +Yx, Tx = step(H1ax, T=np.linspace(0, 10, 100)) # Step response for the second input -H1ay = ss(Ay - By*K1a[1,alt], By*K1a[1,alt]*yd[alt,:], Cy, Dy); -(Yy, Ty) = step(H1ay, T=linspace(0,10,100)); +H1ay = ss(Ay - By * K1a[1, alt], By * K1a[1, alt] * yd[alt, :], Cy, Dy) +Yy, Ty = step(H1ay, T=np.linspace(0, 10, 100)) -subplot(221); title("Identity weights") -# plot(T, Y[:,1, 1], '-', T, Y[:,2, 2], '--'); -plot(Tx.T, Yx.T, '-', Ty.T, Yy.T, '--'); -plot([0, 10], [1, 1], 'k-'); +plt.subplot(221) +plt.title("Identity weights") +# plt.plot(T, Y[:,1, 1], '-', T, Y[:,2, 2], '--') +plt.plot(Tx.T, Yx.T, '-', Ty.T, Yy.T, '--') +plt.plot([0, 10], [1, 1], 'k-') -axis([0, 10, -0.1, 1.4]); -ylabel('position'); -legend(('x', 'y'), loc='lower right'); +plt.axis([0, 10, -0.1, 1.4]) +plt.ylabel('position') +plt.legend(('x', 'y'), loc='lower right') # Look at different input weightings -Qu1a = diag([1, 1]); (K1a, X, E) = lqr(A, B, Qx1, Qu1a); -H1ax = ss(Ax - Bx*K1a[0,lat], Bx*K1a[0,lat]*xd[lat,:], Cx, Dx); +Qu1a = np.diag([1, 1]) +K1a, X, E = lqr(A, B, Qx1, Qu1a) +H1ax = ss(Ax - Bx * K1a[0, lat], Bx * K1a[0, lat] * xd[lat, :], Cx, Dx) -Qu1b = (40**2)*diag([1, 1]); (K1b, X, E) = lqr(A, B, Qx1, Qu1b); -H1bx = ss(Ax - Bx*K1b[0,lat], Bx*K1b[0,lat]*xd[lat,:],Cx, Dx); +Qu1b = (40 ** 2) * np.diag([1, 1]) +K1b, X, E = lqr(A, B, Qx1, Qu1b) +H1bx = ss(Ax - Bx * K1b[0, lat], Bx * K1b[0, lat] * xd[lat, :], Cx, Dx) -Qu1c = (200**2)*diag([1, 1]); (K1c, X, E) = lqr(A, B, Qx1, Qu1c); -H1cx = ss(Ax - Bx*K1c[0,lat], Bx*K1c[0,lat]*xd[lat,:],Cx, Dx); +Qu1c = (200 ** 2) * np.diag([1, 1]) +K1c, X, E = lqr(A, B, Qx1, Qu1c) +H1cx = ss(Ax - Bx * K1c[0, lat], Bx * K1c[0, lat] * xd[lat, :], Cx, Dx) -[Y1, T1] = step(H1ax, T=linspace(0,10,100)); -[Y2, T2] = step(H1bx, T=linspace(0,10,100)); -[Y3, T3] = step(H1cx, T=linspace(0,10,100)); +[Y1, T1] = step(H1ax, T=np.linspace(0, 10, 100)) +[Y2, T2] = step(H1bx, T=np.linspace(0, 10, 100)) +[Y3, T3] = step(H1cx, T=np.linspace(0, 10, 100)) -subplot(222); title("Effect of input weights") -plot(T1.T, Y1.T, 'b-'); -plot(T2.T, Y2.T, 'b-'); -plot(T3.T, Y3.T, 'b-'); -plot([0 ,10], [1, 1], 'k-'); +plt.subplot(222) +plt.title("Effect of input weights") +plt.plot(T1.T, Y1.T, 'b-') +plt.plot(T2.T, Y2.T, 'b-') +plt.plot(T3.T, Y3.T, 'b-') +plt.plot([0, 10], [1, 1], 'k-') -axis([0, 10, -0.1, 1.4]); +plt.axis([0, 10, -0.1, 1.4]) -# arcarrow([1.3, 0.8], [5, 0.45], -6); -text(5.3, 0.4, 'rho'); +# arcarrow([1.3, 0.8], [5, 0.45], -6) +plt.text(5.3, 0.4, 'rho') # Output weighting - change Qx to use outputs -Qx2 = C.T * C; -Qu2 = 0.1 * diag([1, 1]); -(K, X, E) = lqr(A, B, Qx2, Qu2); K2 = matrix(K) +Qx2 = C.T * C +Qu2 = 0.1 * np.diag([1, 1]) +K, X, E = lqr(A, B, Qx2, Qu2) +K2 = np.matrix(K) -H2x = ss(Ax - Bx*K2[0,lat], Bx*K2[0,lat]*xd[lat,:], Cx, Dx); -H2y = ss(Ay - By*K2[1,alt], By*K2[1,alt]*yd[alt,:], Cy, Dy); +H2x = ss(Ax - Bx * K2[0, lat], Bx * K2[0, lat] * xd[lat, :], Cx, Dx) +H2y = ss(Ay - By * K2[1, alt], By * K2[1, alt] * yd[alt, :], Cy, Dy) -subplot(223); title("Output weighting") -[Y2x, T2x] = step(H2x, T=linspace(0,10,100)); -[Y2y, T2y] = step(H2y, T=linspace(0,10,100)); -plot(T2x.T, Y2x.T, T2y.T, Y2y.T) -ylabel('position'); -xlabel('time'); ylabel('position'); -legend(('x', 'y'), loc='lower right'); +plt.subplot(223) +plt.title("Output weighting") +[Y2x, T2x] = step(H2x, T=np.linspace(0, 10, 100)) +[Y2y, T2y] = step(H2y, T=np.linspace(0, 10, 100)) +plt.plot(T2x.T, Y2x.T, T2y.T, Y2y.T) +plt.ylabel('position') +plt.xlabel('time') +plt.ylabel('position') +plt.legend(('x', 'y'), loc='lower right') # # Physically motivated weighting @@ -177,21 +191,21 @@ # due to loss in efficiency. # -Qx3 = diag([100, 10, 2*pi/5, 0, 0, 0]); -Qu3 = 0.1 * diag([1, 10]); -(K, X, E) = lqr(A, B, Qx3, Qu3); K3 = matrix(K); +Qx3 = np.diag([100, 10, 2 * np.pi / 5, 0, 0, 0]) +Qu3 = 0.1 * np.diag([1, 10]) +(K, X, E) = lqr(A, B, Qx3, Qu3) +K3 = np.matrix(K) -H3x = ss(Ax - Bx*K3[0,lat], Bx*K3[0,lat]*xd[lat,:], Cx, Dx); -H3y = ss(Ay - By*K3[1,alt], By*K3[1,alt]*yd[alt,:], Cy, Dy); -subplot(224) -# step(H3x, H3y, 10); -[Y3x, T3x] = step(H3x, T=linspace(0,10,100)); -[Y3y, T3y] = step(H3y, T=linspace(0,10,100)); -plot(T3x.T, Y3x.T, T3y.T, Y3y.T) -title("Physically motivated weights") -xlabel('time'); -legend(('x', 'y'), loc='lower right'); +H3x = ss(Ax - Bx * K3[0, lat], Bx * K3[0, lat] * xd[lat, :], Cx, Dx) +H3y = ss(Ay - By * K3[1, alt], By * K3[1, alt] * yd[alt, :], Cy, Dy) +plt.subplot(224) +# step(H3x, H3y, 10) +[Y3x, T3x] = step(H3x, T=np.linspace(0, 10, 100)) +[Y3y, T3y] = step(H3y, T=np.linspace(0, 10, 100)) +plt.plot(T3x.T, Y3x.T, T3y.T, Y3y.T) +plt.title("Physically motivated weights") +plt.xlabel('time') +plt.legend(('x', 'y'), loc='lower right') if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: - show() - + plt.show() diff --git a/examples/pvtol-nested-ss.py b/examples/pvtol-nested-ss.py index 24e173bc8..702bd7fc7 100644 --- a/examples/pvtol-nested-ss.py +++ b/examples/pvtol-nested-ss.py @@ -8,24 +8,25 @@ # package. # -from matplotlib.pyplot import * # Grab MATLAB plotting functions +import os +import matplotlib.pyplot as plt # MATLAB plotting functions from control.matlab import * # MATLAB-like functions import numpy as np # System parameters -m = 4; # mass of aircraft -J = 0.0475; # inertia around pitch axis -r = 0.25; # distance to center of force -g = 9.8; # gravitational constant -c = 0.05; # damping factor (estimated) +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # Transfer functions for dynamics -Pi = tf([r], [J, 0, 0]); # inner loop (roll) -Po = tf([1], [m, c, 0]); # outer loop (position) +Pi = tf([r], [J, 0, 0]) # inner loop (roll) +Po = tf([1], [m, c, 0]) # outer loop (position) # Use state space versions -Pi = tf2ss(Pi); -Po = tf2ss(Po); +Pi = tf2ss(Pi) +Po = tf2ss(Po) # # Inner loop control design @@ -36,102 +37,111 @@ # # Design a simple lead controller for the system -k = 200; a = 2; b = 50; -Ci = k*tf([1, a], [1, b]); # lead compensator +k, a, b = 200, 2, 50 +Ci = k*tf([1, a], [1, b]) # lead compensator # Convert to statespace -Ci = tf2ss(Ci); +Ci = tf2ss(Ci) # Compute the loop transfer function for the inner loop -Li = Pi*Ci; +Li = Pi*Ci # Bode plot for the open loop process -figure(1); -bode(Pi); +plt.figure(1) +bode(Pi) # Bode plot for the loop transfer function, with margins -figure(2); -bode(Li); +plt.figure(2) +bode(Li) # Compute out the gain and phase margins #! Not implemented # (gm, pm, wcg, wcp) = margin(Li); # Compute the sensitivity and complementary sensitivity functions -Si = feedback(1, Li); -Ti = Li * Si; +Si = feedback(1, Li) +Ti = Li*Si # Check to make sure that the specification is met -figure(3); gangof4(Pi, Ci); +plt.figure(3) +gangof4(Pi, Ci) # Compute out the actual transfer function from u1 to v1 (see L8.2 notes) # Hi = Ci*(1-m*g*Pi)/(1+Ci*Pi); -Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1)); +Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1)) -figure(4); clf; subplot(221); -bode(Hi); +plt.figure(4) +plt.clf() +plt.subplot(221) +bode(Hi) # Now design the lateral control system -a = 0.02; b = 5; K = 2; -Co = -K*tf([1, 0.3], [1, 10]); # another lead compensator +a, b, K = 0.02, 5, 2 +Co = -K*tf([1, 0.3], [1, 10]) # another lead compensator # Convert to statespace -Co = tf2ss(Co); +Co = tf2ss(Co) # Compute the loop transfer function for the outer loop -Lo = -m*g*Po*Co; +Lo = -m*g*Po*Co -figure(5); -bode(Lo); # margin(Lo) +plt.figure(5) +bode(Lo) # margin(Lo) # Finally compute the real outer-loop loop gain + responses -L = Co*Hi*Po; -S = feedback(1, L); -T = feedback(L, 1); +L = Co*Hi*Po +S = feedback(1, L) +T = feedback(L, 1) # Compute stability margins #! Not yet implemented # (gm, pm, wgc, wpc) = margin(L); -figure(6); clf; subplot(221); -bode(L, logspace(-4, 3)); +plt.figure(6) +plt.clf() +plt.subplot(221) +bode(L, logspace(-4, 3)) # Add crossover line -subplot(211); -loglog([1e-4, 1e3], [1, 1], 'k-') - -# Replot phase starting at -90 degrees -(mag, phase, w) = freqresp(L, logspace(-4, 3)); -phase = phase - 360; - -subplot(212); -semilogx([1e-4, 1e3], [-180, -180], 'k-') -semilogx(w, np.squeeze(phase), 'b-') -axis([1e-4, 1e3, -360, 0]); -xlabel('Frequency [deg]'); ylabel('Phase [deg]'); -# set(gca, 'YTick', [-360, -270, -180, -90, 0]); -# set(gca, 'XTick', [10^-4, 10^-2, 1, 100]); +plt.subplot(211) +plt.loglog([1e-4, 1e3], [1, 1], 'k-') + +# Re-plot phase starting at -90 degrees +mag, phase, w = freqresp(L, logspace(-4, 3)) +phase = phase - 360 + +plt.subplot(212) +plt.semilogx([1e-4, 1e3], [-180, -180], 'k-') +plt.semilogx(w, np.squeeze(phase), 'b-') +plt.axis([1e-4, 1e3, -360, 0]) +plt.xlabel('Frequency [deg]') +plt.ylabel('Phase [deg]') +# plt.set(gca, 'YTick', [-360, -270, -180, -90, 0]) +# plt.set(gca, 'XTick', [10^-4, 10^-2, 1, 100]) # # Nyquist plot for complete design # -figure(7); clf; -axis([-700, 5300, -3000, 3000]); -nyquist(L, (0.0001, 1000)); -axis([-700, 5300, -3000, 3000]); +plt.figure(7) +plt.clf() +plt.axis([-700, 5300, -3000, 3000]) +nyquist(L, (0.0001, 1000)) +plt.axis([-700, 5300, -3000, 3000]) # Add a box in the region we are going to expand -plot([-400, -400, 200, 200, -400], [-100, 100, 100, -100, -100], 'r-') +plt.plot([-400, -400, 200, 200, -400], [-100, 100, 100, -100, -100], 'r-') # Expanded region -figure(8); clf; subplot(231); -axis([-10, 5, -20, 20]); -nyquist(L); -axis([-10, 5, -20, 20]); +plt.figure(8) +plt.clf() +plt.subplot(231) +plt.axis([-10, 5, -20, 20]) +nyquist(L) +plt.axis([-10, 5, -20, 20]) # set up the color -color = 'b'; +color = 'b' # Add arrows to the plot # H1 = L.evalfr(0.4); H2 = L.evalfr(0.41); @@ -142,19 +152,23 @@ # arrow([real(H2), -imag(H2)], [real(H1), -imag(H1)], AM_normal_arrowsize, \ # 'EdgeColor', color, 'FaceColor', color); -figure(9); -(Yvec, Tvec) = step(T, linspace(1, 20)); -plot(Tvec.T, Yvec.T); +plt.figure(9) +Yvec, Tvec = step(T, linspace(1, 20)) +plt.plot(Tvec.T, Yvec.T) -(Yvec, Tvec) = step(Co*S, linspace(1, 20)); -plot(Tvec.T, Yvec.T); +Yvec, Tvec = step(Co*S, linspace(1, 20)) +plt.plot(Tvec.T, Yvec.T) #TODO: PZmap for statespace systems has not yet been implemented. -figure(10); clf(); -# (P, Z) = pzmap(T, Plot=True) -# print "Closed loop poles and zeros: ", P, Z +plt.figure(10) +plt.clf() +# P, Z = pzmap(T, Plot=True) +# print("Closed loop poles and zeros: ", P, Z) # Gang of Four -figure(11); clf(); -gangof4(Hi*Po, Co, linspace(-2, 3)); +plt.figure(11) +plt.clf() +gangof4(Hi*Po, Co, linspace(-2, 3)) +if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: + plt.show() diff --git a/examples/pvtol-nested.py b/examples/pvtol-nested.py index e02d86352..3521ec6d8 100644 --- a/examples/pvtol-nested.py +++ b/examples/pvtol-nested.py @@ -3,30 +3,32 @@ # # This file works through a fairly complicated control design and # analysis, corresponding to the planar vertical takeoff and landing -# (PVTOL) aircraft in Astrom and Mruray, Chapter 11. It is intended +# (PVTOL) aircraft in Astrom and Murray, Chapter 11. It is intended # to demonstrate the basic functionality of the python-control # package. # from __future__ import print_function -from matplotlib.pyplot import * # Grab MATLAB plotting functions + +import os +import matplotlib.pyplot as plt # MATLAB plotting functions from control.matlab import * # MATLAB-like functions import numpy as np # System parameters -m = 4; # mass of aircraft -J = 0.0475; # inertia around pitch axis -r = 0.25; # distance to center of force -g = 9.8; # gravitational constant -c = 0.05; # damping factor (estimated) +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # Transfer functions for dynamics -Pi = tf([r], [J, 0, 0]); # inner loop (roll) -Po = tf([1], [m, c, 0]); # outer loop (position) +Pi = tf([r], [J, 0, 0]) # inner loop (roll) +Po = tf([1], [m, c, 0]) # outer loop (position) # Use state space versions -Pi = tf2ss(Pi); -Po = tf2ss(Po); +Pi = tf2ss(Pi) +Po = tf2ss(Po) # # Inner loop control design @@ -37,110 +39,118 @@ # # Design a simple lead controller for the system -k = 200; a = 2; b = 50; -Ci = k*tf([1, a], [1, b]); # lead compensator -Li = Pi*Ci; +k, a, b = 200, 2, 50 +Ci = k*tf([1, a], [1, b]) # lead compensator +Li = Pi*Ci # Bode plot for the open loop process -figure(1); -bode(Pi); +plt.figure(1) +bode(Pi) # Bode plot for the loop transfer function, with margins -figure(2); -bode(Li); +plt.figure(2) +bode(Li) # Compute out the gain and phase margins #! Not implemented -# (gm, pm, wcg, wcp) = margin(Li); +# gm, pm, wcg, wcp = margin(Li) # Compute the sensitivity and complementary sensitivity functions -Si = feedback(1, Li); -Ti = Li * Si; +Si = feedback(1, Li) +Ti = Li * Si # Check to make sure that the specification is met -figure(3); gangof4(Pi, Ci); +plt.figure(3) +gangof4(Pi, Ci) # Compute out the actual transfer function from u1 to v1 (see L8.2 notes) -# Hi = Ci*(1-m*g*Pi)/(1+Ci*Pi); -Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1)); +# Hi = Ci*(1-m*g*Pi)/(1+Ci*Pi) +Hi = parallel(feedback(Ci, Pi), -m*g*feedback(Ci*Pi, 1)) -figure(4); clf; subplot(221); -bode(Hi); +plt.figure(4) +plt.clf() +plt.subplot(221) +bode(Hi) # Now design the lateral control system -a = 0.02; b = 5; K = 2; -Co = -K*tf([1, 0.3], [1, 10]); # another lead compensator -Lo = -m*g*Po*Co; +a, b, K = 0.02, 5, 2 +Co = -K*tf([1, 0.3], [1, 10]) # another lead compensator +Lo = -m*g*Po*Co -figure(5); -bode(Lo); # margin(Lo) +plt.figure(5) +bode(Lo) # margin(Lo) # Finally compute the real outer-loop loop gain + responses -L = Co*Hi*Po; -S = feedback(1, L); -T = feedback(L, 1); +L = Co*Hi*Po +S = feedback(1, L) +T = feedback(L, 1) # Compute stability margins -(gm, pm, wgc, wpc) = margin(L); +gm, pm, wgc, wpc = margin(L) print("Gain margin: %g at %g" % (gm, wgc)) print("Phase margin: %g at %g" % (pm, wpc)) -figure(6); clf; -bode(L, logspace(-4, 3)); +plt.figure(6) +plt.clf() +bode(L, np.logspace(-4, 3)) # Add crossover line to the magnitude plot # # Note: in matplotlib before v2.1, the following code worked: # -# subplot(211); hold(True); +# plt.subplot(211); hold(True); # loglog([1e-4, 1e3], [1, 1], 'k-') # -# In later versions of matplotlib the call to subplot will clear the +# In later versions of matplotlib the call to plt.subplot will clear the # axes and so we have to extract the axes that we want to use by hand. # In addition, hold() is deprecated so we no longer require it. # -for ax in gcf().axes: +for ax in plt.gcf().axes: if ax.get_label() == 'control-bode-magnitude': break -ax.semilogx([1e-4, 1e3], 20 * np.log10([1, 1]), 'k-') + ax.semilogx([1e-4, 1e3], 20*np.log10([1, 1]), 'k-') # # Replot phase starting at -90 degrees # # Get the phase plot axes -for ax in gcf().axes: +for ax in plt.gcf().axes: if ax.get_label() == 'control-bode-phase': break -# Recreate the frequency response and shift the phase -(mag, phase, w) = freqresp(L, logspace(-4, 3)); -phase = phase - 360; + # Recreate the frequency response and shift the phase + mag, phase, w = freqresp(L, np.logspace(-4, 3)) + phase = phase - 360 -# Replot the phase by hand -ax.semilogx([1e-4, 1e3], [-180, -180], 'k-') -ax.semilogx(w, np.squeeze(phase), 'b-') -ax.axis([1e-4, 1e3, -360, 0]); -xlabel('Frequency [deg]'); ylabel('Phase [deg]'); -# set(gca, 'YTick', [-360, -270, -180, -90, 0]); -# set(gca, 'XTick', [10^-4, 10^-2, 1, 100]); + # Replot the phase by hand + ax.semilogx([1e-4, 1e3], [-180, -180], 'k-') + ax.semilogx(w, np.squeeze(phase), 'b-') + ax.axis([1e-4, 1e3, -360, 0]) +plt.xlabel('Frequency [deg]') +plt.ylabel('Phase [deg]') +# plt.set(gca, 'YTick', [-360, -270, -180, -90, 0]) +# plt.set(gca, 'XTick', [10^-4, 10^-2, 1, 100]) # # Nyquist plot for complete design # -figure(7); clf; -nyquist(L, (0.0001, 1000)); -axis([-700, 5300, -3000, 3000]); +plt.figure(7) +plt.clf() +nyquist(L, (0.0001, 1000)) +plt.axis([-700, 5300, -3000, 3000]) # Add a box in the region we are going to expand -plot([-400, -400, 200, 200, -400], [-100, 100, 100, -100, -100], 'r-') +plt.plot([-400, -400, 200, 200, -400], [-100, 100, 100, -100, -100], 'r-') # Expanded region -figure(8); clf; subplot(231); -nyquist(L); -axis([-10, 5, -20, 20]); +plt.figure(8) +plt.clf() +plt.subplot(231) +nyquist(L) +plt.axis([-10, 5, -20, 20]) # set up the color -color = 'b'; +color = 'b' # Add arrows to the plot # H1 = L.evalfr(0.4); H2 = L.evalfr(0.41); @@ -151,18 +161,22 @@ # arrow([real(H2), -imag(H2)], [real(H1), -imag(H1)], AM_normal_arrowsize, \ # 'EdgeColor', color, 'FaceColor', color); -figure(9); -(Yvec, Tvec) = step(T, linspace(0, 20)); -plot(Tvec.T, Yvec.T); +plt.figure(9) +Yvec, Tvec = step(T, np.linspace(0, 20)) +plt.plot(Tvec.T, Yvec.T) -(Yvec, Tvec) = step(Co*S, linspace(0, 20)); -plot(Tvec.T, Yvec.T); +Yvec, Tvec = step(Co*S, np.linspace(0, 20)) +plt.plot(Tvec.T, Yvec.T) -figure(10); clf(); -(P, Z) = pzmap(T, Plot=True) +plt.figure(10) +plt.clf() +P, Z = pzmap(T, Plot=True) print("Closed loop poles and zeros: ", P, Z) # Gang of Four -figure(11); clf(); -gangof4(Hi*Po, Co); +plt.figure(11) +plt.clf() +gangof4(Hi*Po, Co) +if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: + plt.show() diff --git a/examples/robust_mimo.py b/examples/robust_mimo.py index c7a06ea1c..8844fbf46 100644 --- a/examples/robust_mimo.py +++ b/examples/robust_mimo.py @@ -10,7 +10,7 @@ import numpy as np import matplotlib.pyplot as plt -from control import tf, ss, mixsyn, feedback, step_response +from control import tf, ss, mixsyn, step_response def weighting(wb, m, a): diff --git a/examples/robust_siso.py b/examples/robust_siso.py index 013ea821d..038152f80 100644 --- a/examples/robust_siso.py +++ b/examples/robust_siso.py @@ -11,7 +11,7 @@ import numpy as np import matplotlib.pyplot as plt -from control import tf, ss, mixsyn, feedback, step_response +from control import tf, mixsyn, feedback, step_response s = tf([1, 0], 1) # the plant diff --git a/examples/rss-balred.py b/examples/rss-balred.py index 86e499a80..a89fb2880 100755 --- a/examples/rss-balred.py +++ b/examples/rss-balred.py @@ -10,7 +10,7 @@ plt.close('all') -#controlable canonical realization computed in matlab for the transfer function: +# controlable canonical realization computed in matlab for the transfer function: # num = [1 11 45 32], den = [1 15 60 200 60] A = np.matrix('-15., -7.5, -6.25, -1.875; \ 8., 0., 0., 0.; \ @@ -21,10 +21,11 @@ D = np.matrix('0.') # The full system -fsys = StateSpace(A,B,C,D) +fsys = StateSpace(A, B, C, D) + # The reduced system, truncating the order by 1 ord = 3 -rsys = msimp.balred(fsys,ord, method = 'truncate') +rsys = msimp.balred(fsys, ord, method='truncate') # Comparison of the step responses of the full and reduced systems plt.figure(1) @@ -35,7 +36,7 @@ # Repeat balanced reduction, now with 100-dimensional random state space sysrand = mt.rss(100, 1, 1) -rsysrand = msimp.balred(sysrand,10,method ='truncate') +rsysrand = msimp.balred(sysrand, 10, method='truncate') # Comparison of the impulse responses of the full and reduced random systems plt.figure(2) diff --git a/examples/secord-matlab.py b/examples/secord-matlab.py index d11af6be9..8876193db 100644 --- a/examples/secord-matlab.py +++ b/examples/secord-matlab.py @@ -1,8 +1,9 @@ # secord.py - demonstrate some standard MATLAB commands # RMM, 25 May 09 -from matplotlib.pyplot import * # Grab MATLAB plotting functions -from control.matlab import * # MATLAB-like functions +import os +import matplotlib.pyplot as plt # MATLAB plotting functions +from control.matlab import * # MATLAB-like functions # Parameters defining the system m = 250.0 # system mass @@ -16,22 +17,23 @@ sys = ss(A, B, C, 0) # Step response for the system -figure(1) +plt.figure(1) yout, T = step(sys) -plot(T.T, yout.T) -show() +plt.plot(T.T, yout.T) +plt.show(block=False) # Bode plot for the system -figure(2) +plt.figure(2) mag, phase, om = bode(sys, logspace(-2, 2), Plot=True) -show() +plt.show(block=False) # Nyquist plot for the system -figure(3) +plt.figure(3) nyquist(sys, logspace(-2, 2)) -show() +plt.show(block=False) -# Root lcous plut for the system -figure(4) +# Root lcous plot for the system rlocus(sys) -show() \ No newline at end of file + +if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: + plt.show() diff --git a/examples/slycot-import-test.py b/examples/slycot-import-test.py index 7e4f0d9a9..2015a3e7a 100644 --- a/examples/slycot-import-test.py +++ b/examples/slycot-import-test.py @@ -5,7 +5,6 @@ """ import numpy as np -from scipy import * from control.matlab import * from control.exception import slycot_check @@ -35,8 +34,8 @@ n = 3 # Number of states m = 1 # Number of inputs - npp = 3 # Number of placed eigen values - alpha = 1 # Maximum threshold for eigen values + npp = 3 # Number of placed eigen values + alpha = 1 # Maximum threshold for eigen values dico = 'D' # Discrete system _, _, _, _, _, K, _ = sb01bd(n, m, npp, alpha, A, B, w, dico, tol=0.0, ldwork=None) print("[slycot] K = ", K) diff --git a/examples/test-response.py b/examples/test-response.py index 745a14fb6..0ccc70b6c 100644 --- a/examples/test-response.py +++ b/examples/test-response.py @@ -1,7 +1,8 @@ # test-response.py - Unit tests for system response functions # RMM, 11 Sep 2010 -from matplotlib.pyplot import * # Grab MATLAB plotting functions +import os +import matplotlib.pyplot as plt # MATLAB plotting functions from control.matlab import * # Load the controls systems library from scipy import arange # function to create range of numbers @@ -11,8 +12,11 @@ # Generate step responses (y1a, T1a) = step(sys1) -(y1b, T1b) = step(sys1, T = arange(0, 10, 0.1)) -(y1c, T1c) = step(sys1, X0 = [1, 0]) -(y2a, T2a) = step(sys2, T = arange(0, 10, 0.1)) +(y1b, T1b) = step(sys1, T=arange(0, 10, 0.1)) +(y1c, T1c) = step(sys1, X0=[1, 0]) +(y2a, T2a) = step(sys2, T=arange(0, 10, 0.1)) -plot(T1a, y1a, T1b, y1b, T1c, y1c, T2a, y2a) +plt.plot(T1a, y1a, T1b, y1b, T1c, y1c, T2a, y2a) + +if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: + plt.show() \ No newline at end of file diff --git a/examples/tfvis.py b/examples/tfvis.py index 056fd62eb..60b837d99 100644 --- a/examples/tfvis.py +++ b/examples/tfvis.py @@ -56,6 +56,7 @@ from control.matlab import logspace from numpy import conj + def make_poly(facts): """ Create polynomial from factors """ poly = [1] @@ -63,7 +64,8 @@ def make_poly(facts): poly = polymul(poly, [1, -factor]) return real(poly) - + + def coeff_string_check(text): """ Check so textfield entry is valid string of coeffs. """ try: @@ -73,6 +75,7 @@ def coeff_string_check(text): return Pmw.OK + class TFInput: """ Class for handling input of transfer function coeffs.""" def __init__(self, parent): @@ -150,6 +153,7 @@ def set_zeros(self, zeros): self.numerator_widget.setentry( ' '.join([format(i,'.3g') for i in self.numerator])) + class Analysis: """ Main class for GUI visualising transfer functions """ def __init__(self, parent): @@ -179,7 +183,7 @@ def __init__(self, parent): self.sys = self.tfi.get_tf() tkinter.Button(self.entries, text='Apply', command=self.apply, - width=9).grid(row=0, column=1, rowspan=3, padx=10, pady=5) + width=9).grid(row=0, column=1, rowspan=3, padx=10, pady=5) self.f_bode = plt.figure(figsize=(4, 4)) self.f_nyquist = plt.figure(figsize=(4, 4)) @@ -187,35 +191,35 @@ def __init__(self, parent): self.f_step = plt.figure(figsize=(4, 4)) self.canvas_pzmap = FigureCanvasTkAgg(self.f_pzmap, - master=self.figure) + master=self.figure) self.canvas_pzmap.draw() self.canvas_pzmap.get_tk_widget().grid(row=0, column=0, - padx=0, pady=0) + padx=0, pady=0) self.canvas_bode = FigureCanvasTkAgg(self.f_bode, - master=self.figure) + master=self.figure) self.canvas_bode.draw() self.canvas_bode.get_tk_widget().grid(row=0, column=1, - padx=0, pady=0) + padx=0, pady=0) self.canvas_step = FigureCanvasTkAgg(self.f_step, - master=self.figure) + master=self.figure) self.canvas_step.draw() self.canvas_step.get_tk_widget().grid(row=1, column=0, - padx=0, pady=0) + padx=0, pady=0) self.canvas_nyquist = FigureCanvasTkAgg(self.f_nyquist, master=self.figure) self.canvas_nyquist.draw() self.canvas_nyquist.get_tk_widget().grid(row=1, column=1, - padx=0, pady=0) + padx=0, pady=0) self.canvas_pzmap.mpl_connect('button_press_event', - self.button_press) + self.button_press) self.canvas_pzmap.mpl_connect('button_release_event', - self.button_release) + self.button_release) self.canvas_pzmap.mpl_connect('motion_notify_event', - self.mouse_move) + self.mouse_move) self.apply() @@ -223,7 +227,7 @@ def button_press(self, event): """ Handle button presses, detect if we are going to move any poles/zeros""" # find closest pole/zero - if (event.xdata != None and event.ydata != None): + if event.xdata != None and event.ydata != None: new = event.xdata + 1.0j*event.ydata @@ -361,6 +365,7 @@ def redraw(self): self.canvas_step.draw() self.canvas_nyquist.draw() + def create_analysis(): """ Create main object """ def handler(): @@ -376,6 +381,7 @@ def handler(): Analysis(root) root.mainloop() + if __name__ == '__main__': import os if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: diff --git a/examples/type2_type3.py b/examples/type2_type3.py index c8fe39155..250aa266c 100644 --- a/examples/type2_type3.py +++ b/examples/type2_type3.py @@ -2,10 +2,11 @@ # tracking and disturbance rejection for two proposed controllers # Gunnar Ristroph, 15 January 2010 -from matplotlib.pyplot import * # Grab MATLAB plotting functions -from control.matlab import * # MATLAB-like functions +import os +import matplotlib.pyplot as plt # Grab MATLAB plotting functions +from control.matlab import * # MATLAB-like functions from scipy import pi -integrator = tf([0, 1], [1, 0]) # 1/s +integrator = tf([0, 1], [1, 0]) # 1/s # Parameters defining the system J = 1.0 @@ -16,8 +17,8 @@ # Plant transfer function from torque to rate inertia = integrator*1/J -friction = b # transfer function from rate to torque -P = inertia # friction is modelled as a separate block +friction = b # transfer function from rate to torque +P = inertia # friction is modelled as a separate block # Gyro transfer function from rate to rate gyro = 1. # for now, our gyro is perfect @@ -34,12 +35,14 @@ disturbance_rejection_type3 = P*friction/(1. + P*friction + P*C_type3) # Bode plot for the system -figure(1) -bode(closed_loop_type2, logspace(0, 2)*2*pi, dB=True, Hz=True) # blue -bode(closed_loop_type3, logspace(0, 2)*2*pi, dB=True, Hz=True) # green -show() - -figure(2) -bode(disturbance_rejection_type2, logspace(0, 2)*2*pi, Hz=True) # blue -bode(disturbance_rejection_type3, logspace(0, 2)*2*pi, Hz=True) # green -show() +plt.figure(1) +bode(closed_loop_type2, logspace(0, 2)*2*pi, dB=True, Hz=True) # blue +bode(closed_loop_type3, logspace(0, 2)*2*pi, dB=True, Hz=True) # green +plt.show(block=False) + +plt.figure(2) +bode(disturbance_rejection_type2, logspace(0, 2)*2*pi, Hz=True) # blue +bode(disturbance_rejection_type3, logspace(0, 2)*2*pi, Hz=True) # green + +if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: + plt.show() From 7e70e8a06766ee93b95cf53700bf2eb0869225e7 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 14:08:31 -0700 Subject: [PATCH 05/12] Removed spacing around `*` and `/` operators for consistency and as per PEP 8. --- ...check-controllability-and-observability.py | 4 +- examples/genswitch.py | 4 +- examples/phaseplots.py | 4 +- examples/pvtol-lqr.py | 42 +++++++++---------- examples/pvtol-nested.py | 2 +- examples/robust_mimo.py | 20 ++++----- examples/robust_siso.py | 28 ++++++------- examples/slycot-import-test.py | 6 +-- 8 files changed, 55 insertions(+), 55 deletions(-) diff --git a/examples/check-controllability-and-observability.py b/examples/check-controllability-and-observability.py index d20416f1f..70dcc7aa3 100644 --- a/examples/check-controllability-and-observability.py +++ b/examples/check-controllability-and-observability.py @@ -17,11 +17,11 @@ # System matrices A = matrix([[1, -1, 1.], - [1, -k / m, -b / m], + [1, -k/m, -b/m], [1, 1, 1]]) B = matrix([[0], - [1 / m], + [1/m], [1]]) C = matrix([[1., 0, 1.]]) diff --git a/examples/genswitch.py b/examples/genswitch.py index 46513a36f..5034ecee5 100644 --- a/examples/genswitch.py +++ b/examples/genswitch.py @@ -17,7 +17,7 @@ # This function implements the basic model of the genetic switch # Parameters taken from Gardner, Cantor and Collins, Nature, 2000 def genswitch(y, t, mu=4, n=2): - return mu / (1 + y[1]**n) - y[0], mu / (1 + y[0]**n) - y[1] + return mu/(1 + y[1]**n) - y[0], mu/(1 + y[0]**n) - y[1] # Run a simulation from an initial condition tim1 = np.linspace(0, 10, 100) @@ -36,7 +36,7 @@ def genswitch(y, t, mu=4, n=2): # First plot out the curves that define the equilibria u = np.linspace(0, 4.5, 46) -f = np.divide(mu, (1 + u**n)) # mu / (1 + u^n), element-wise +f = np.divide(mu, (1 + u**n)) # mu/(1 + u^n), element-wise plt.figure(1); plt.clf() plt.axis([0, 5, 0, 5]) # box on; diff --git a/examples/phaseplots.py b/examples/phaseplots.py index a71c029d7..cf05c384a 100644 --- a/examples/phaseplots.py +++ b/examples/phaseplots.py @@ -20,13 +20,13 @@ # Define the ODEs for a damped (inverted) pendulum def invpend_ode(x, t, m=1., l=1., b=0.2, g=1): - return x[1], -b/m*x[1] + (g*l/m) * np.sin(x[0]) + return x[1], -b/m*x[1] + (g*l/m)*np.sin(x[0]) # Set up the figure the way we want it to look plt.figure() plt.clf() -plt.axis([-2 * pi, 2 * pi, -2.1, 2.1]) +plt.axis([-2*pi, 2*pi, -2.1, 2.1]) plt.title('Inverted pendulum') # Outer trajectories diff --git a/examples/pvtol-lqr.py b/examples/pvtol-lqr.py index 29ba7f4df..0c379b0a7 100644 --- a/examples/pvtol-lqr.py +++ b/examples/pvtol-lqr.py @@ -28,24 +28,24 @@ # State space dynamics xe = [0, 0, 0, 0, 0, 0] # equilibrium point of interest -ue = [0, m * g] # (note these are lists, not matrices) +ue = [0, m*g] # (note these are lists, not matrices) # Dynamics matrix (use matrix type so that * works for multiplication) A = np.matrix( [[0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1], - [0, 0, (-ue[0] * np.sin(xe[2]) - ue[1] * np.cos(xe[2])) / m, -c / m, 0, 0], - [0, 0, (ue[0] * np.cos(xe[2]) - ue[1] * np.sin(xe[2])) / m, 0, -c / m, 0], + [0, 0, (-ue[0]*np.sin(xe[2]) - ue[1]*np.cos(xe[2]))/m, -c/m, 0, 0], + [0, 0, (ue[0]*np.cos(xe[2]) - ue[1]*np.sin(xe[2]))/m, 0, -c/m, 0], [0, 0, 0, 0, 0, 0]] ) # Input matrix B = np.matrix( [[0, 0], [0, 0], [0, 0], - [np.cos(xe[2]) / m, -np.sin(xe[2]) / m], - [np.sin(xe[2]) / m, np.cos(xe[2]) / m], - [r / J, 0]] + [np.cos(xe[2])/m, -np.sin(xe[2])/m], + [np.sin(xe[2])/m, np.cos(xe[2])/m], + [r/J, 0]] ) # Output matrix @@ -118,11 +118,11 @@ # (T, Y) = step(H1a, T=np.linspace(0,10,100)); # Step response for the first input -H1ax = ss(Ax - Bx * K1a[0, lat], Bx * K1a[0, lat] * xd[lat, :], Cx, Dx) +H1ax = ss(Ax - Bx*K1a[0, lat], Bx*K1a[0, lat]*xd[lat, :], Cx, Dx) Yx, Tx = step(H1ax, T=np.linspace(0, 10, 100)) # Step response for the second input -H1ay = ss(Ay - By * K1a[1, alt], By * K1a[1, alt] * yd[alt, :], Cy, Dy) +H1ay = ss(Ay - By*K1a[1, alt], By*K1a[1, alt]*yd[alt, :], Cy, Dy) Yy, Ty = step(H1ay, T=np.linspace(0, 10, 100)) plt.subplot(221) @@ -138,15 +138,15 @@ # Look at different input weightings Qu1a = np.diag([1, 1]) K1a, X, E = lqr(A, B, Qx1, Qu1a) -H1ax = ss(Ax - Bx * K1a[0, lat], Bx * K1a[0, lat] * xd[lat, :], Cx, Dx) +H1ax = ss(Ax - Bx*K1a[0, lat], Bx*K1a[0, lat]*xd[lat, :], Cx, Dx) -Qu1b = (40 ** 2) * np.diag([1, 1]) +Qu1b = (40 ** 2)*np.diag([1, 1]) K1b, X, E = lqr(A, B, Qx1, Qu1b) -H1bx = ss(Ax - Bx * K1b[0, lat], Bx * K1b[0, lat] * xd[lat, :], Cx, Dx) +H1bx = ss(Ax - Bx*K1b[0, lat], Bx*K1b[0, lat]*xd[lat, :], Cx, Dx) -Qu1c = (200 ** 2) * np.diag([1, 1]) +Qu1c = (200 ** 2)*np.diag([1, 1]) K1c, X, E = lqr(A, B, Qx1, Qu1c) -H1cx = ss(Ax - Bx * K1c[0, lat], Bx * K1c[0, lat] * xd[lat, :], Cx, Dx) +H1cx = ss(Ax - Bx*K1c[0, lat], Bx*K1c[0, lat]*xd[lat, :], Cx, Dx) [Y1, T1] = step(H1ax, T=np.linspace(0, 10, 100)) [Y2, T2] = step(H1bx, T=np.linspace(0, 10, 100)) @@ -165,13 +165,13 @@ plt.text(5.3, 0.4, 'rho') # Output weighting - change Qx to use outputs -Qx2 = C.T * C -Qu2 = 0.1 * np.diag([1, 1]) +Qx2 = C.T*C +Qu2 = 0.1*np.diag([1, 1]) K, X, E = lqr(A, B, Qx2, Qu2) K2 = np.matrix(K) -H2x = ss(Ax - Bx * K2[0, lat], Bx * K2[0, lat] * xd[lat, :], Cx, Dx) -H2y = ss(Ay - By * K2[1, alt], By * K2[1, alt] * yd[alt, :], Cy, Dy) +H2x = ss(Ax - Bx*K2[0, lat], Bx*K2[0, lat]*xd[lat, :], Cx, Dx) +H2y = ss(Ay - By*K2[1, alt], By*K2[1, alt]*yd[alt, :], Cy, Dy) plt.subplot(223) plt.title("Output weighting") @@ -191,13 +191,13 @@ # due to loss in efficiency. # -Qx3 = np.diag([100, 10, 2 * np.pi / 5, 0, 0, 0]) -Qu3 = 0.1 * np.diag([1, 10]) +Qx3 = np.diag([100, 10, 2*np.pi/5, 0, 0, 0]) +Qu3 = 0.1*np.diag([1, 10]) (K, X, E) = lqr(A, B, Qx3, Qu3) K3 = np.matrix(K) -H3x = ss(Ax - Bx * K3[0, lat], Bx * K3[0, lat] * xd[lat, :], Cx, Dx) -H3y = ss(Ay - By * K3[1, alt], By * K3[1, alt] * yd[alt, :], Cy, Dy) +H3x = ss(Ax - Bx*K3[0, lat], Bx*K3[0, lat]*xd[lat, :], Cx, Dx) +H3y = ss(Ay - By*K3[1, alt], By*K3[1, alt]*yd[alt, :], Cy, Dy) plt.subplot(224) # step(H3x, H3y, 10) [Y3x, T3x] = step(H3x, T=np.linspace(0, 10, 100)) diff --git a/examples/pvtol-nested.py b/examples/pvtol-nested.py index 3521ec6d8..b3904e98b 100644 --- a/examples/pvtol-nested.py +++ b/examples/pvtol-nested.py @@ -57,7 +57,7 @@ # Compute the sensitivity and complementary sensitivity functions Si = feedback(1, Li) -Ti = Li * Si +Ti = Li*Si # Check to make sure that the specification is met plt.figure(3) diff --git a/examples/robust_mimo.py b/examples/robust_mimo.py index 8844fbf46..402d91488 100644 --- a/examples/robust_mimo.py +++ b/examples/robust_mimo.py @@ -21,7 +21,7 @@ def weighting(wb, m, a): wf - SISO LTI object """ s = tf([1, 0], [1]) - return (s / m + wb) / (s + wb * a) + return (s/m + wb) / (s + wb*a) def plant(): @@ -44,7 +44,7 @@ def triv_sigma(g, w): w - frequencies, length m s - (m,n) array of singular values of g(1j*w)""" m, p, _ = g.freqresp(w) - sjw = (m * np.exp(1j * p * np.pi / 180)).transpose(2, 0, 1) + sjw = (m*np.exp(1j*p*np.pi/180)).transpose(2, 0, 1) sv = np.linalg.svd(sjw, compute_uv=False) return sv @@ -135,8 +135,8 @@ def design(): g = plant() w = np.logspace(-2, 2, 101) I = ss([], [], [], np.eye(2)) - s1 = I.feedback(g * k1) - s2 = I.feedback(g * k2) + s1 = I.feedback(g*k1) + s2 = I.feedback(g*k2) # frequency response sv1 = triv_sigma(s1, w) @@ -145,10 +145,10 @@ def design(): plt.figure(2) plt.subplot(1, 2, 1) - plt.semilogx(w, 20 * np.log10(sv1[:, 0]), label=r'$\sigma_1(S_1)$') - plt.semilogx(w, 20 * np.log10(sv1[:, 1]), label=r'$\sigma_2(S_1)$') - plt.semilogx(w, 20 * np.log10(sv2[:, 0]), label=r'$\sigma_1(S_2)$') - plt.semilogx(w, 20 * np.log10(sv2[:, 1]), label=r'$\sigma_2(S_2)$') + plt.semilogx(w, 20*np.log10(sv1[:, 0]), label=r'$\sigma_1(S_1)$') + plt.semilogx(w, 20*np.log10(sv1[:, 1]), label=r'$\sigma_2(S_1)$') + plt.semilogx(w, 20*np.log10(sv2[:, 0]), label=r'$\sigma_1(S_2)$') + plt.semilogx(w, 20*np.log10(sv2[:, 1]), label=r'$\sigma_2(S_2)$') plt.ylim([-60, 10]) plt.ylabel('magnitude [dB]') plt.xlim([1e-2, 1e2]) @@ -162,8 +162,8 @@ def design(): # design 2, output 2 does not, and is very fast, while output 1 # has a larger initial inverse response than in design 1 time = np.linspace(0, 10, 301) - t1 = (g * k1).feedback(I) - t2 = (g * k2).feedback(I) + t1 = (g*k1).feedback(I) + t2 = (g*k2).feedback(I) y1 = step_opposite(t1, time) y2 = step_opposite(t2, time) diff --git a/examples/robust_siso.py b/examples/robust_siso.py index 038152f80..87fcdb707 100644 --- a/examples/robust_siso.py +++ b/examples/robust_siso.py @@ -15,16 +15,16 @@ s = tf([1, 0], 1) # the plant -g = 200 / (10 * s + 1) / (0.05 * s + 1) ** 2 +g = 200/(10*s + 1) / (0.05*s + 1)**2 # disturbance plant -gd = 100 / (10 * s + 1) +gd = 100/(10*s + 1) # first design # sensitivity weighting M = 1.5 wb = 10 A = 1e-4 -ws1 = (s / M + wb) / (s + wb * A) +ws1 = (s/M + wb) / (s + wb*A) # KS weighting wu = tf(1, 1) @@ -32,21 +32,21 @@ # sensitivity (S) and complementary sensitivity (T) functions for # design 1 -s1 = feedback(1, g * k1) -t1 = feedback(g * k1, 1) +s1 = feedback(1, g*k1) +t1 = feedback(g*k1, 1) # second design # this weighting differs from the text, where A**0.5 is used; if you use that, # the frequency response doesn't match the figure. The time responses # are similar, though. -ws2 = (s / M ** 0.5 + wb) ** 2 / (s + wb * A) ** 2 +ws2 = (s/M ** 0.5 + wb)**2 / (s + wb*A)**2 # the KS weighting is the same as for the first design k2, cl2, info2 = mixsyn(g, ws2, wu) # S and T for design 2 -s2 = feedback(1, g * k2) -t2 = feedback(g * k2, 1) +s2 = feedback(1, g*k2) +t2 = feedback(g*k2, 1) # frequency response omega = np.logspace(-2, 2, 101) @@ -57,11 +57,11 @@ plt.figure(1) # text uses log-scaled absolute, but dB are probably more familiar to most control engineers -plt.semilogx(omega, 20 * np.log10(s1mag.flat), label='$S_1$') -plt.semilogx(omega, 20 * np.log10(s2mag.flat), label='$S_2$') +plt.semilogx(omega, 20*np.log10(s1mag.flat), label='$S_1$') +plt.semilogx(omega, 20*np.log10(s2mag.flat), label='$S_2$') # -1 in logspace is inverse -plt.semilogx(omega, -20 * np.log10(ws1mag.flat), label='$1/w_{P1}$') -plt.semilogx(omega, -20 * np.log10(ws2mag.flat), label='$1/w_{P2}$') +plt.semilogx(omega, -20*np.log10(ws1mag.flat), label='$1/w_{P1}$') +plt.semilogx(omega, -20*np.log10(ws2mag.flat), label='$1/w_{P2}$') plt.ylim([-80, 10]) plt.xlim([1e-2, 1e2]) @@ -77,8 +77,8 @@ # gd injects into the output (that is, g and gd are summed), and the # closed loop mapping from output disturbance->output is S. -_, y1d = step_response(s1 * gd, time) -_, y2d = step_response(s2 * gd, time) +_, y1d = step_response(s1*gd, time) +_, y2d = step_response(s2*gd, time) plt.figure(2) plt.subplot(1, 2, 1) diff --git a/examples/slycot-import-test.py b/examples/slycot-import-test.py index 2015a3e7a..88b1c9486 100644 --- a/examples/slycot-import-test.py +++ b/examples/slycot-import-test.py @@ -14,8 +14,8 @@ b = 60.0 # damping constant # System matrices -A = np.matrix([[1, -1, 1.], [1, -k / m, -b / m], [1, 1, 1]]) -B = np.matrix([[0], [1 / m], [1]]) +A = np.matrix([[1, -1, 1.], [1, -k/m, -b/m], [1, 1, 1]]) +B = np.matrix([[0], [1/m], [1]]) C = np.matrix([[1., 0, 1.]]) sys = ss(A, B, C, 0) @@ -24,7 +24,7 @@ w = [-3, -2, -1] K = place(A, B, w) print("[python-control (from scipy)] K = ", K) -print("[python-control (from scipy)] eigs = ", np.linalg.eig(A - B * K)[0]) +print("[python-control (from scipy)] eigs = ", np.linalg.eig(A - B*K)[0]) # Before using one of its routine, check that slycot is installed. w = np.array([-3, -2, -1]) From ebc5137d22525ed61396366b02d45bf2629aa3b4 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 14:14:37 -0700 Subject: [PATCH 06/12] Refactored name 'ord' which conflicts with built-in. --- examples/rss-balred.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/rss-balred.py b/examples/rss-balred.py index a89fb2880..d7a47c205 100755 --- a/examples/rss-balred.py +++ b/examples/rss-balred.py @@ -10,7 +10,7 @@ plt.close('all') -# controlable canonical realization computed in matlab for the transfer function: +# controllable canonical realization computed in Matlab for the transfer function: # num = [1 11 45 32], den = [1 15 60 200 60] A = np.matrix('-15., -7.5, -6.25, -1.875; \ 8., 0., 0., 0.; \ @@ -24,8 +24,8 @@ fsys = StateSpace(A, B, C, D) # The reduced system, truncating the order by 1 -ord = 3 -rsys = msimp.balred(fsys, ord, method='truncate') +n = 3 +rsys = msimp.balred(fsys, n, method='truncate') # Comparison of the step responses of the full and reduced systems plt.figure(1) @@ -42,8 +42,7 @@ plt.figure(2) yrand, trand = mt.impulse(sysrand) yrandr, trandr = mt.impulse(rsysrand) -plt.plot(trand.T, yrand.T, trandr.T, yrandr.T) - +plt.plot(trand.T, yrand.T, trandr.T, yrandr.T) if 'PYCONTROL_TEST_EXAMPLES' not in os.environ: plt.show() From fddbf0fd8c1058f2b872bebc36c1ae12fcb69999 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 14:16:19 -0700 Subject: [PATCH 07/12] Reformatted comments --- examples/pvtol-lqr.py | 8 ++++---- examples/pvtol-nested-ss.py | 8 ++++---- examples/slycot-import-test.py | 14 +++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/pvtol-lqr.py b/examples/pvtol-lqr.py index 0c379b0a7..33f76d89c 100644 --- a/examples/pvtol-lqr.py +++ b/examples/pvtol-lqr.py @@ -20,11 +20,11 @@ # # System parameters -m = 4 # mass of aircraft +m = 4 # mass of aircraft J = 0.0475 # inertia around pitch axis -r = 0.25 # distance to center of force -g = 9.8 # gravitational constant -c = 0.05 # damping factor (estimated) +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # State space dynamics xe = [0, 0, 0, 0, 0, 0] # equilibrium point of interest diff --git a/examples/pvtol-nested-ss.py b/examples/pvtol-nested-ss.py index 702bd7fc7..3f98d7b59 100644 --- a/examples/pvtol-nested-ss.py +++ b/examples/pvtol-nested-ss.py @@ -14,11 +14,11 @@ import numpy as np # System parameters -m = 4 # mass of aircraft -J = 0.0475 # inertia around pitch axis -r = 0.25 # distance to center of force +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force g = 9.8 # gravitational constant -c = 0.05 # damping factor (estimated) +c = 0.05 # damping factor (estimated) # Transfer functions for dynamics Pi = tf([r], [J, 0, 0]) # inner loop (roll) diff --git a/examples/slycot-import-test.py b/examples/slycot-import-test.py index 88b1c9486..8ca7f0226 100644 --- a/examples/slycot-import-test.py +++ b/examples/slycot-import-test.py @@ -10,8 +10,8 @@ # Parameters defining the system m = 250.0 # system mass -k = 40.0 # spring constant -b = 60.0 # damping constant +k = 40.0 # spring constant +b = 60.0 # damping constant # System matrices A = np.matrix([[1, -1, 1.], [1, -k/m, -b/m], [1, 1, 1]]) @@ -32,11 +32,11 @@ # Import routine sb01bd used for pole placement. from slycot import sb01bd - n = 3 # Number of states - m = 1 # Number of inputs - npp = 3 # Number of placed eigen values - alpha = 1 # Maximum threshold for eigen values - dico = 'D' # Discrete system + n = 3 # Number of states + m = 1 # Number of inputs + npp = 3 # Number of placed eigen values + alpha = 1 # Maximum threshold for eigen values + dico = 'D' # Discrete system _, _, _, _, _, K, _ = sb01bd(n, m, npp, alpha, A, B, w, dico, tol=0.0, ldwork=None) print("[slycot] K = ", K) print("[slycot] eigs = ", np.linalg.eig(A + np.dot(B, K))[0]) From 1555a5bf81b79b99b36a339bac61684e4048104f Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 14:24:09 -0700 Subject: [PATCH 08/12] Reversed previous mistaken edit. --- examples/pvtol-nested.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/pvtol-nested.py b/examples/pvtol-nested.py index b3904e98b..4cad1f782 100644 --- a/examples/pvtol-nested.py +++ b/examples/pvtol-nested.py @@ -118,14 +118,14 @@ if ax.get_label() == 'control-bode-phase': break - # Recreate the frequency response and shift the phase - mag, phase, w = freqresp(L, np.logspace(-4, 3)) - phase = phase - 360 - - # Replot the phase by hand - ax.semilogx([1e-4, 1e3], [-180, -180], 'k-') - ax.semilogx(w, np.squeeze(phase), 'b-') - ax.axis([1e-4, 1e3, -360, 0]) +# Recreate the frequency response and shift the phase +mag, phase, w = freqresp(L, np.logspace(-4, 3)) +phase = phase - 360 + +# Replot the phase by hand +ax.semilogx([1e-4, 1e3], [-180, -180], 'k-') +ax.semilogx(w, np.squeeze(phase), 'b-') +ax.axis([1e-4, 1e3, -360, 0]) plt.xlabel('Frequency [deg]') plt.ylabel('Phase [deg]') # plt.set(gca, 'YTick', [-360, -270, -180, -90, 0]) From ddad0a7e244600f33477732ea75fa6c17a84c420 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 14:36:32 -0700 Subject: [PATCH 09/12] Removed tab characters --- examples/genswitch.py | 2 +- examples/pvtol-lqr.py | 4 ++-- examples/pvtol-nested-ss.py | 16 ++++++++-------- examples/pvtol-nested.py | 14 +++++++------- examples/secord-matlab.py | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/genswitch.py b/examples/genswitch.py index 5034ecee5..e65e40110 100644 --- a/examples/genswitch.py +++ b/examples/genswitch.py @@ -24,7 +24,7 @@ def genswitch(y, t, mu=4, n=2): sol1 = odeint(genswitch, [1, 5], tim1) # Extract the equilibrium points -mu = 4; n = 2 # switch parameters +mu = 4; n = 2 # switch parameters eqpt = np.empty(3) eqpt[0] = sol1[0, -1] eqpt[1] = sol1[1, -1] diff --git a/examples/pvtol-lqr.py b/examples/pvtol-lqr.py index 33f76d89c..7dbbe40f2 100644 --- a/examples/pvtol-lqr.py +++ b/examples/pvtol-lqr.py @@ -62,8 +62,8 @@ # The way these vectors are used is to compute the closed loop system # dynamics as # -# xdot = Ax + B u => xdot = (A-BK)x + K xd -# u = -K(x - xd) y = Cx +# xdot = Ax + B u => xdot = (A-BK)x + K xd +# u = -K(x - xd) y = Cx # # The closed loop dynamics can be simulated using the "step" command, # with K*xd as the input vector (assumes that the "input" is unit size, diff --git a/examples/pvtol-nested-ss.py b/examples/pvtol-nested-ss.py index 3f98d7b59..55ef56e10 100644 --- a/examples/pvtol-nested-ss.py +++ b/examples/pvtol-nested-ss.py @@ -14,15 +14,15 @@ import numpy as np # System parameters -m = 4 # mass of aircraft -J = 0.0475 # inertia around pitch axis -r = 0.25 # distance to center of force -g = 9.8 # gravitational constant -c = 0.05 # damping factor (estimated) +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # Transfer functions for dynamics -Pi = tf([r], [J, 0, 0]) # inner loop (roll) -Po = tf([1], [m, c, 0]) # outer loop (position) +Pi = tf([r], [J, 0, 0]) # inner loop (roll) +Po = tf([1], [m, c, 0]) # outer loop (position) # Use state space versions Pi = tf2ss(Pi) @@ -78,7 +78,7 @@ # Now design the lateral control system a, b, K = 0.02, 5, 2 -Co = -K*tf([1, 0.3], [1, 10]) # another lead compensator +Co = -K*tf([1, 0.3], [1, 10]) # another lead compensator # Convert to statespace Co = tf2ss(Co) diff --git a/examples/pvtol-nested.py b/examples/pvtol-nested.py index 4cad1f782..e502cb3f7 100644 --- a/examples/pvtol-nested.py +++ b/examples/pvtol-nested.py @@ -16,15 +16,15 @@ import numpy as np # System parameters -m = 4 # mass of aircraft -J = 0.0475 # inertia around pitch axis -r = 0.25 # distance to center of force -g = 9.8 # gravitational constant -c = 0.05 # damping factor (estimated) +m = 4 # mass of aircraft +J = 0.0475 # inertia around pitch axis +r = 0.25 # distance to center of force +g = 9.8 # gravitational constant +c = 0.05 # damping factor (estimated) # Transfer functions for dynamics Pi = tf([r], [J, 0, 0]) # inner loop (roll) -Po = tf([1], [m, c, 0]) # outer loop (position) +Po = tf([1], [m, c, 0]) # outer loop (position) # Use state space versions Pi = tf2ss(Pi) @@ -40,7 +40,7 @@ # Design a simple lead controller for the system k, a, b = 200, 2, 50 -Ci = k*tf([1, a], [1, b]) # lead compensator +Ci = k*tf([1, a], [1, b]) # lead compensator Li = Pi*Ci # Bode plot for the open loop process diff --git a/examples/secord-matlab.py b/examples/secord-matlab.py index 8876193db..25bf1ff79 100644 --- a/examples/secord-matlab.py +++ b/examples/secord-matlab.py @@ -6,9 +6,9 @@ from control.matlab import * # MATLAB-like functions # Parameters defining the system -m = 250.0 # system mass -k = 40.0 # spring constant -b = 60.0 # damping constant +m = 250.0 # system mass +k = 40.0 # spring constant +b = 60.0 # damping constant # System matrices A = [[0, 1.], [-k/m, -b/m]] From 51a772bfb802db633610c6206b12f1e3c1323a51 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 16:06:23 -0700 Subject: [PATCH 10/12] Replaced np.matrix with np.array objects --- examples/pvtol-lqr.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/examples/pvtol-lqr.py b/examples/pvtol-lqr.py index 7dbbe40f2..611931a9a 100644 --- a/examples/pvtol-lqr.py +++ b/examples/pvtol-lqr.py @@ -30,6 +30,10 @@ xe = [0, 0, 0, 0, 0, 0] # equilibrium point of interest ue = [0, m*g] # (note these are lists, not matrices) +# TODO: The following objects need converting from np.matrix to np.array +# This will involve re-working the subsequent equations as the shapes +# See below. + # Dynamics matrix (use matrix type so that * works for multiplication) A = np.matrix( [[0, 0, 0, 1, 0, 0], @@ -117,6 +121,29 @@ # H1a = ss(A-B*K1a, B*K1a*concatenate((xd, yd), axis=1), C, D); # (T, Y) = step(H1a, T=np.linspace(0,10,100)); +# TODO: The following equations will need modifying when converting from np.matrix to np.array +# because the results and even intermediate calculations will be different with numpy arrays +# For example: +# Bx = B[lat, 0] +# Will need to be changed to: +# Bx = B[lat, 0].reshape(-1, 1) +# (if we want it to have the same shape as before) + +# For reference, here is a list of the correct shapes of these objects: +# A: (6, 6) +# B: (6, 2) +# C: (2, 6) +# D: (2, 2) +# xd: (6, 1) +# yd: (6, 1) +# Ax: (4, 4) +# Bx: (4, 1) +# Cx: (1, 4) +# Dx: () +# Ay: (2, 2) +# By: (2, 1) +# Cy: (1, 2) + # Step response for the first input H1ax = ss(Ax - Bx*K1a[0, lat], Bx*K1a[0, lat]*xd[lat, :], Cx, Dx) Yx, Tx = step(H1ax, T=np.linspace(0, 10, 100)) From 0df099f84fd8d2c4fd0cd52b8545d7b7c7db2090 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 16:08:08 -0700 Subject: [PATCH 11/12] Replaced np.matrix with np.array objects --- ...check-controllability-and-observability.py | 20 +++++++++--------- examples/rss-balred.py | 21 ++++++++++++------- examples/slycot-import-test.py | 6 +++--- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/examples/check-controllability-and-observability.py b/examples/check-controllability-and-observability.py index 70dcc7aa3..399693781 100644 --- a/examples/check-controllability-and-observability.py +++ b/examples/check-controllability-and-observability.py @@ -6,25 +6,25 @@ from __future__ import print_function -from scipy import * # Load the scipy functions +import numpy as np # Load the scipy functions from control.matlab import * # Load the controls systems library # Parameters defining the system m = 250.0 # system mass -k = 40.0 # spring constant -b = 60.0 # damping constant +k = 40.0 # spring constant +b = 60.0 # damping constant # System matrices -A = matrix([[1, -1, 1.], - [1, -k/m, -b/m], - [1, 1, 1]]) +A = np.array([[1, -1, 1.], + [1, -k/m, -b/m], + [1, 1, 1]]) -B = matrix([[0], - [1/m], - [1]]) +B = np.array([[0], + [1/m], + [1]]) -C = matrix([[1., 0, 1.]]) +C = np.array([[1., 0, 1.]]) sys = ss(A, B, C, 0) diff --git a/examples/rss-balred.py b/examples/rss-balred.py index d7a47c205..f6bc58fd7 100755 --- a/examples/rss-balred.py +++ b/examples/rss-balred.py @@ -12,13 +12,20 @@ # controllable canonical realization computed in Matlab for the transfer function: # num = [1 11 45 32], den = [1 15 60 200 60] -A = np.matrix('-15., -7.5, -6.25, -1.875; \ -8., 0., 0., 0.; \ -0., 4., 0., 0.; \ -0., 0., 1., 0.') -B = np.matrix('2.; 0.; 0.; 0.') -C = np.matrix('0.5, 0.6875, 0.7031, 0.5') -D = np.matrix('0.') +A = np.array([ + [-15., -7.5, -6.25, -1.875], + [8., 0., 0., 0.], + [0., 4., 0., 0.], + [0., 0., 1., 0.] +]) +B = np.array([ + [2.], + [0.], + [0.], + [0.] +]) +C = np.array([[0.5, 0.6875, 0.7031, 0.5]]) +D = np.array([[0.]]) # The full system fsys = StateSpace(A, B, C, D) diff --git a/examples/slycot-import-test.py b/examples/slycot-import-test.py index 8ca7f0226..c2c78fa89 100644 --- a/examples/slycot-import-test.py +++ b/examples/slycot-import-test.py @@ -14,9 +14,9 @@ b = 60.0 # damping constant # System matrices -A = np.matrix([[1, -1, 1.], [1, -k/m, -b/m], [1, 1, 1]]) -B = np.matrix([[0], [1/m], [1]]) -C = np.matrix([[1., 0, 1.]]) +A = np.array([[1, -1, 1.], [1, -k/m, -b/m], [1, 1, 1]]) +B = np.array([[0], [1/m], [1]]) +C = np.array([[1., 0, 1.]]) sys = ss(A, B, C, 0) # Python control may be used without slycot, for example for a pole placement. From 5648440c4c33acc23225f792146d8a98ffc37523 Mon Sep 17 00:00:00 2001 From: Bill Tubbs Date: Sat, 8 Jun 2019 16:26:14 -0700 Subject: [PATCH 12/12] Reverted previous mistaken edit --- examples/pvtol-nested.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pvtol-nested.py b/examples/pvtol-nested.py index e502cb3f7..56685599b 100644 --- a/examples/pvtol-nested.py +++ b/examples/pvtol-nested.py @@ -108,7 +108,7 @@ for ax in plt.gcf().axes: if ax.get_label() == 'control-bode-magnitude': break - ax.semilogx([1e-4, 1e3], 20*np.log10([1, 1]), 'k-') +ax.semilogx([1e-4, 1e3], 20*np.log10([1, 1]), 'k-') # # Replot phase starting at -90 degrees