3. The Jupyter notebook cheat sheet

This document will be available to you during tests and exams

3.1. Table of Contents

Numeric

Basic plotting functions

Symbolic manipulation

Equation solving

Matrix math

[1]:
import tbcontrol
tbcontrol.expectversion('0.1.2')

3.2. Numeric

[2]:
import numpy
import scipy
[3]:
a = numpy.array([1, 2, 3])
[4]:
t = numpy.linspace(0, 10)

3.3. Basic plotting functions

[5]:
import matplotlib.pyplot as plt
%matplotlib inline
[6]:
plotfuncs = [plt.plot,
             plt.stem,
             plt.scatter,
             plt.semilogx,
             plt.semilogy,
             plt.loglog]

for i, func in enumerate(plotfuncs, 1):
    plt.subplot(2, 3, i)
    func([1, 2, 3], [2, 1, 2])
    plt.title(func.__name__)
plt.tight_layout()
../_images/0_Getting_Started_Cheatsheet_9_0.png

3.4. Symbolic manipulation

3.4.1. Imports

[7]:
import sympy
sympy.init_printing()

Symbol definitions

[8]:
s = sympy.Symbol('s')  # A single symbol
tau, K_c = sympy.symbols('tau K_c', positive=True) # we can use real=True or complex=True for other kinds of variables

Example controller and system

[9]:
Gc = K_c*((tau*s + 1) / (tau*s))
GvGpGm = 5 / ((10*s + 1)**2)

3.4.2. Working with rational functions and polynomials

We often want nice rational functions, but sympy doesn’t make expressions rational by default

[10]:
chareq = GvGpGm*Gc + 1
chareq
[10]:
$$\frac{5 K_{c} \left(s \tau + 1\right)}{s \tau \left(10 s + 1\right)^{2}} + 1$$

The cancel function forces this to be a fraction. collect collects terms.

[11]:
chareq = chareq.cancel().collect(s)
chareq
[11]:
$$\frac{5 K_{c} + 100 s^{3} \tau + 20 s^{2} \tau + s \left(5 K_{c} \tau + \tau\right)}{100 s^{3} \tau + 20 s^{2} \tau + s \tau}$$

In some cases we can factor equations:

[12]:
chareq.factor(s)
[12]:
$$\frac{5 K_{c} + 100 s^{3} \tau + 20 s^{2} \tau + s \left(5 K_{c} \tau + \tau\right)}{s \tau \left(10 s + 1\right)^{2}}$$

Obtain the numerator and denominator:

[13]:
sympy.numer(chareq), sympy.denom(chareq)
[13]:
$$\left ( 5 K_{c} + 100 s^{3} \tau + 20 s^{2} \tau + s \left(5 K_{c} \tau + \tau\right), \quad 100 s^{3} \tau + 20 s^{2} \tau + s \tau\right )$$

If you want them both, you can use

[14]:
chareq.as_numer_denom()
[14]:
$$\left ( 5 K_{c} + 100 s^{3} \tau + 20 s^{2} \tau + s \left(5 K_{c} \tau + \tau\right), \quad 100 s^{3} \tau + 20 s^{2} \tau + s \tau\right )$$

Convert to polynomial in s

[15]:
numer = sympy.poly(sympy.numer(chareq), s)

Once we have a polynomial, it is easy to obtain coefficients:

[16]:
numer.all_coeffs()
[16]:
$$\left [ 100 \tau, \quad 20 \tau, \quad 5 K_{c} \tau + \tau, \quad 5 K_{c}\right ]$$

Calculate the Routh Array

[17]:
from tbcontrol.symbolic import routh
[18]:
routh(numer)
[18]:
$$\left[\begin{matrix}100 \tau & 5 K_{c} \tau + \tau\\20 \tau & 5 K_{c}\\- 25 K_{c} + \tau \left(5 K_{c} + 1\right) & 0\\5 K_{c} & 0\end{matrix}\right]$$

To get a function which can be used numerically, use lambdify:

[19]:
f = sympy.lambdify((K_c, tau), K_c + tau)
[20]:
f(1, 2)
[20]:
$$3$$

3.4.3. Functions useful for discrete systems

[21]:
z, q = sympy.symbols('z, q')
[22]:
Gz = z**-1/(1 - z**-1)
Gz
[22]:
$$\frac{1}{z \left(1 - \frac{1}{z}\right)}$$

Write in terms of positive powers of \(z\):

[23]:
Gz.cancel()
[23]:
$$\frac{1}{z - 1}$$

Write in terms of negative powers of \(z\):

[24]:
Gz.subs({z: q**-1}).cancel()
[24]:
$$- \frac{q}{q - 1}$$

Inversion of the \(z\) transform

[25]:
from tbcontrol.symbolic import sampledvalues
[26]:
sampledvalues(Gz, z, 10)
[26]:
$$\left [ 0, \quad 1, \quad 1, \quad 1, \quad 1, \quad 1, \quad 1, \quad 1, \quad 1, \quad 1\right ]$$

3.5. Equation solving

3.5.1. Symbolic

[27]:
x, y, z, a = sympy.symbols('x, y, z, a')
residuals = [x + y - 2, y + z - a, x + y + z]
unknowns = [x, y, z]
sympy.solve(residuals, unknowns)
[27]:
$$\left \{ x : - a, \quad y : a + 2, \quad z : -2\right \}$$

3.5.2. Numeric sympy

[28]:
residuals = [2*x**2 - 2*y**2, sympy.sin(x) + sympy.log(y)]
unknowns = [x, y]
sympy.nsolve(residuals, unknowns, [1, 3])
[28]:
$$\left[\begin{matrix}-2.21910714891375\\2.21910714891375\end{matrix}\right]$$

3.5.3. Numeric

[29]:
import scipy.optimize
[30]:
def residuals(unknowns):
    x, y = unknowns
    return [2*x**2 - 2*y**2, numpy.sin(x) + numpy.log(y)]
[31]:
starting_point = [1, 3]
[32]:
residuals(starting_point)
[32]:
$$\left [ -16, \quad 1.9400832734760063\right ]$$
[33]:
scipy.optimize.fsolve(residuals, starting_point)
[33]:
array([-2.21910715,  2.21910715])

3.6. Matrix math

3.6.1. Symbolic

[34]:
G11, G12, G21, G22 = sympy.symbols('G11, G12, G21, G22')

Creation

[35]:
G = sympy.Matrix([[G11, G12], [G21, G22]])
G
[35]:
$$\left[\begin{matrix}G_{11} & G_{12}\\G_{21} & G_{22}\end{matrix}\right]$$

Determinant, inverse, transpose

[36]:
G.det(), G.inv(), G.T
[36]:
$$\left ( G_{11} G_{22} - G_{12} G_{21}, \quad \left[\begin{matrix}\frac{G_{22}}{G_{11} G_{22} - G_{12} G_{21}} & - \frac{G_{12}}{G_{11} G_{22} - G_{12} G_{21}}\\- \frac{G_{21}}{G_{11} G_{22} - G_{12} G_{21}} & \frac{G_{11}}{G_{11} G_{22} - G_{12} G_{21}}\end{matrix}\right], \quad \left[\begin{matrix}G_{11} & G_{21}\\G_{12} & G_{22}\end{matrix}\right]\right )$$

Math operations: Multiplication, addition, elementwise multiplication:

[37]:
G*G, G+G, G.multiply_elementwise(G)
[37]:
$$\left ( \left[\begin{matrix}G_{11}^{2} + G_{12} G_{21} & G_{11} G_{12} + G_{12} G_{22}\\G_{11} G_{21} + G_{21} G_{22} & G_{12} G_{21} + G_{22}^{2}\end{matrix}\right], \quad \left[\begin{matrix}2 G_{11} & 2 G_{12}\\2 G_{21} & 2 G_{22}\end{matrix}\right], \quad \left[\begin{matrix}G_{11}^{2} & G_{12}^{2}\\G_{21}^{2} & G_{22}^{2}\end{matrix}\right]\right )$$

3.6.2. Numeric

Creation

[38]:
G = numpy.matrix([[1, 2], [3, 4]])

Determinant, inverse, transpose

[39]:
numpy.linalg.det(G), G.I, G.T
[39]:
(-2.0000000000000004, matrix([[-2. ,  1. ],
         [ 1.5, -0.5]]), matrix([[1, 3],
         [2, 4]]))

Math operations: Multiplication, addition, elementwise multiplication:

[40]:
G*G, G+G, G.A*G.A
[40]:
(matrix([[ 7, 10],
         [15, 22]]), matrix([[2, 4],
         [6, 8]]), array([[ 1,  4],
        [ 9, 16]]))
[ ]: