# 7. The Jupyter notebook cheat sheet¶

This document will be available to you during tests and exams

Numeric

Basic plotting functions

Symbolic manipulation

Equation solving

Matrix math

[1]:

import tbcontrol
tbcontrol.expectversion('0.1.2')


## 7.2. Numeric¶

[2]:

import numpy
import scipy

[3]:

a = numpy.array([1, 2, 3])

[4]:

t = numpy.linspace(0, 10)


## 7.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()


## 7.4. Symbolic manipulation¶

### 7.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)


### 7.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$$

### 7.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 ]$$

## 7.5. Equation solving¶

### 7.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 \}$$

### 7.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]$$

### 7.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])


## 7.6. Matrix math¶

### 7.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 )$$

### 7.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]]))

[ ]: