{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simulating a plant with time-dependent control actions - Part II\n",
"\n",
"We'll now generate a similar animation with a bigger system."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import control\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# Start by importing our animation libraries\n",
"%config InlineBackend.figure_formats = {'svg',}\n",
"import matplotlib.pylab as plt\n",
"import matplotlib.gridspec as gridspec\n",
"from IPython.display import display\n",
"from matplotlib import animation\n",
"from IPython.display import HTML"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a transfer function matrix\n",
"\n",
"We are going to build a transfer function matrix where each TF has this form:\n",
"\n",
"$$ G = \\frac{a}{bs+c} $$\n",
"\n",
"We will put those TF coefficients into a Python list, row-wise:\n",
"\n",
"```python\n",
"[ [a_11], [b_11,c_11] ], \n",
"[ [a_12], [b_12,c_12] ],\n",
"[ [a_13], [b_13,c_13] ],\n",
"[ [a_21], [b_22,c_23] ],\n",
"...\n",
"[ [a_nn], [b_nn,c_nn] ],\n",
"```\n",
"\n",
"In this order:\n",
"\n",
"$$\n",
"M = \\begin{bmatrix}\n",
"G_{11} & G_{12} & G_{13} \\\\\n",
"G_{21} & G_{22} & G_{23} \\\\\n",
"G_{31} & G_{32} & G_{33} \n",
"\\end{bmatrix}$$"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"tf_coeffs = [\n",
" [[12.8], [16.7,1]],\n",
" [[-18.9], [21.0,1]],\n",
" [[6.6], [10.9,1]],\n",
" [[-19.4], [14.4,1]],\n",
" [[3.8], [14.9,1]],\n",
" [[4.9], [13.2,1]],\n",
" [[20.4], [11.4,1]],\n",
" [[3.2], [21.5,1]],\n",
" [[4.1], [10.2,1]] \n",
"]\n",
"\n",
"td_coeffs = [1,3,7,3,8,3,5,6,7]\n",
"\n",
"# Empty list to store all transfer functions\n",
"g_array = []\n",
"\n",
"# Generate transfer functions\n",
"for tf, td in zip(tf_coeffs, td_coeffs):\n",
" g_tf = control.tf([num for num in tf[0]],[den for den in tf[1]])\n",
" g_delay = control.tf(control.pade(td,1)[0],control.pade(td,1)[1])\n",
" g = g_tf*g_delay\n",
" g_array.append(g)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"nums = [g.num[0][0] for g in g_array]\n",
"dens = [g.den[0][0] for g in g_array]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now have a list of arrays, where each array contains the 2 numerator coefficients for a transfer function:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([-12.8, 25.6]),\n",
" array([ 18.9, -12.6]),\n",
" array([-6.6 , 1.88571429]),\n",
" array([ 19.4 , -12.93333333]),\n",
" array([-3.8 , 0.95]),\n",
" array([-4.9 , 3.26666667]),\n",
" array([-20.4 , 8.16]),\n",
" array([-3.2 , 1.06666667]),\n",
" array([-4.1 , 1.17142857])]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nums"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, we have another list of arrays, where each array contains the 3 denominator coefficients for a transfer function:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([16.7, 34.4, 2. ]),\n",
" array([21. , 15. , 0.66666667]),\n",
" array([10.9 , 4.11428571, 0.28571429]),\n",
" array([14.4 , 10.6 , 0.66666667]),\n",
" array([14.9 , 4.725, 0.25 ]),\n",
" array([13.2 , 9.8 , 0.66666667]),\n",
" array([11.4 , 5.56, 0.4 ]),\n",
" array([21.5 , 8.16666667, 0.33333333]),\n",
" array([10.2 , 3.91428571, 0.28571429])]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dens"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For a MIMO system, the `python-control` library asks that we supply **lists of lists of vectors**.\n",
"\n",
"In simpler terms, we need to call `control.tf` with 2 lists, one containing numerator stuff and the other one containing denominator stuff.\n",
"\n",
"```\n",
"control.tf(num_stuff,denom_stuff)\n",
"```\n",
"\n",
"The numerator list itself is in this form:\n",
"\n",
"```\n",
"num_stuff = [row1_stuff, \n",
" row2_stuff, \n",
" row3_stuff]\n",
"```\n",
"\n",
"And each row of stuff should contain a list of vectors of the coefficients:\n",
"\n",
"```\n",
"row1_stuff = [array([1,2]),\n",
" array([3,4]),\n",
" array([5,6])]\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So now we need to split our `nums` list into 3 lists, one for each row:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[array([-12.8, 25.6]),\n",
" array([ 18.9, -12.6]),\n",
" array([-6.6 , 1.88571429]),\n",
" array([ 19.4 , -12.93333333]),\n",
" array([-3.8 , 0.95]),\n",
" array([-4.9 , 3.26666667]),\n",
" array([-20.4 , 8.16]),\n",
" array([-3.2 , 1.06666667]),\n",
" array([-4.1 , 1.17142857])]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nums"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can use the `itertools` recipes to easily do this:\n",
"\n",
"https://docs.python.org/3/library/itertools.html#recipes\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import itertools\n",
"from itertools import repeat\n",
"\n",
"def zip_longest(*args, fillvalue=None):\n",
" # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-\n",
" iterators = [iter(it) for it in args]\n",
" num_active = len(iterators)\n",
" if not num_active:\n",
" return\n",
" while True:\n",
" values = []\n",
" for i, it in enumerate(iterators):\n",
" try:\n",
" value = next(it)\n",
" except StopIteration:\n",
" num_active -= 1\n",
" if not num_active:\n",
" return\n",
" iterators[i] = repeat(fillvalue)\n",
" value = fillvalue\n",
" values.append(value)\n",
" yield tuple(values)\n",
"\n",
" \n",
"def grouper(iterable, n, fillvalue=None):\n",
" \"Collect data into fixed-length chunks or blocks\"\n",
" # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx\"\n",
" args = [iter(iterable)] * n\n",
" return zip_longest(*args, fillvalue=fillvalue)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"nums_per_row = list(grouper(nums,3))\n",
"dens_per_row = list(grouper(dens,3))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\n",
"Input 1 to output 1:\n",
" -12.8 s + 25.6\n",
"---------------------\n",
"16.7 s^2 + 34.4 s + 2\n",
"\n",
"Input 1 to output 2:\n",
" 19.4 s - 12.93\n",
"--------------------------\n",
"14.4 s^2 + 10.6 s + 0.6667\n",
"\n",
"Input 1 to output 3:\n",
" -20.4 s + 8.16\n",
"-----------------------\n",
"11.4 s^2 + 5.56 s + 0.4\n",
"\n",
"Input 2 to output 1:\n",
" 18.9 s - 12.6\n",
"----------------------\n",
"21 s^2 + 15 s + 0.6667\n",
"\n",
"Input 2 to output 2:\n",
" -3.8 s + 0.95\n",
"-------------------------\n",
"14.9 s^2 + 4.725 s + 0.25\n",
"\n",
"Input 2 to output 3:\n",
" -3.2 s + 1.067\n",
"---------------------------\n",
"21.5 s^2 + 8.167 s + 0.3333\n",
"\n",
"Input 3 to output 1:\n",
" -6.6 s + 1.886\n",
"---------------------------\n",
"10.9 s^2 + 4.114 s + 0.2857\n",
"\n",
"Input 3 to output 2:\n",
" -4.9 s + 3.267\n",
"-------------------------\n",
"13.2 s^2 + 9.8 s + 0.6667\n",
"\n",
"Input 3 to output 3:\n",
" -4.1 s + 1.171\n",
"---------------------------\n",
"10.2 s^2 + 3.914 s + 0.2857"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sys = control.tf(\n",
" nums_per_row,\n",
" dens_per_row\n",
")\n",
"sys"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# Generate a step response grid\n",
"T = np.linspace(0,100,1000)\n",
"\n",
"# Get the responses for each MV\n",
"y_MVs = []\n",
"for i in range(3):\n",
" _, y = control.step_response(sys,T,input=i)\n",
" y_MVs.append(y)\n",
" \n",
"# Flatten\n",
"flat_y = list(itertools.chain(*y_MVs))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
"