Skip to content

Commit 37b06f4

Browse files
author
Jed
committed
Added notebook for doing development work on IO-Cleanup.
Added IO cleanup function to xferfcn module.
1 parent b1ebbdf commit 37b06f4

2 files changed

Lines changed: 280 additions & 43 deletions

File tree

control/xferfcn.py

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# Python 3 compatibility (needs to go here)
1111
from __future__ import print_function
1212
from __future__ import division
13+
from __future__ import absolute_import
1314

1415
"""Copyright (c) 2010 by California Institute of Technology
1516
All rights reserved.
@@ -55,6 +56,13 @@
5556
from numpy import angle, any, array, empty, finfo, insert, ndarray, ones, \
5657
polyadd, polymul, polyval, roots, sort, sqrt, zeros, squeeze, exp, pi, \
5758
where, delete, real, poly, poly1d
59+
60+
from numpy import int, int8, int16, int32, int64
61+
from numpy import float, float16, float32, float64, float128
62+
from numpy import complex, complex64, complex128, complex256
63+
64+
from copy import deepcopy
65+
5866
import numpy as np
5967
from scipy.signal import lti, tf2zpk, zpk2tf, cont2discrete
6068
from copy import deepcopy
@@ -96,7 +104,7 @@ def __init__(self, *args):
96104
where sys is a TransferFunction object (continuous or discrete).
97105
98106
"""
99-
107+
args = deepcopy(args)
100108
if len(args) == 2:
101109
# The user provided a numerator and a denominator.
102110
(num, den) = args
@@ -120,48 +128,8 @@ def __init__(self, *args):
120128
raise ValueError("Needs 1, 2 or 3 arguments; received %i."
121129
% len(args))
122130

123-
# Make num and den into lists of lists of arrays, if necessary.
124-
# Beware: this is a shallow copy! This should be okay,
125-
# but be careful.
126-
data = [num, den]
127-
for i in range(len(data)):
128-
# Check for a scalar (including 0d ndarray)
129-
if (isinstance(data[i], (int, float, complex)) or
130-
(isinstance(data[i], ndarray) and data[i].ndim == 0)):
131-
# Convert scalar to list of list of array.
132-
if (isinstance(data[i], int)):
133-
# Convert integers to floats at this point
134-
data[i] = [[array([data[i]], dtype=float)]]
135-
else:
136-
data[i] = [[array([data[i]])]]
137-
elif (isinstance(data[i], (list, tuple, ndarray)) and
138-
isinstance(data[i][0], (int, float, complex))):
139-
# Convert array to list of list of array.
140-
if (isinstance(data[i][0], int)):
141-
# Convert integers to floats at this point
142-
#! Not sure this covers all cases correctly
143-
data[i] = [[array(data[i], dtype=float)]]
144-
else:
145-
data[i] = [[array(data[i])]]
146-
elif (isinstance(data[i], list) and
147-
isinstance(data[i][0], list) and
148-
isinstance(data[i][0][0], (list, tuple, ndarray)) and
149-
isinstance(data[i][0][0][0], (int, float, complex))):
150-
# We might already have the right format. Convert the
151-
# coefficient vectors to arrays, if necessary.
152-
for j in range(len(data[i])):
153-
for k in range(len(data[i][j])):
154-
if (isinstance(data[i][j][k], int)):
155-
data[i][j][k] = array(data[i][j][k], dtype=float)
156-
else:
157-
data[i][j][k] = array(data[i][j][k])
158-
else:
159-
# If the user passed in anything else, then it's unclear what
160-
# the meaning is.
161-
raise TypeError("The numerator and denominator inputs must be \
162-
scalars or vectors (for\nSISO), or lists of lists of vectors (for SISO or \
163-
MIMO).")
164-
[num, den] = data
131+
num = tf_clean_parts(num)
132+
den = tf_clean_parts(den)
165133

166134
inputs = len(num[0])
167135
outputs = len(num)
@@ -1349,3 +1317,41 @@ def tfdata(sys):
13491317
tf = _convertToTransferFunction(sys)
13501318

13511319
return (tf.num, tf.den)
1320+
1321+
def tf_clean_parts(data):
1322+
'''
1323+
Return a valid, cleaned up numerator or denominator
1324+
for the TransferFunction class.
1325+
1326+
Parameters:
1327+
data: numerator or denominator of a transfer function.
1328+
1329+
Returns:
1330+
data: correctly formatted transfer function part.
1331+
1332+
'''
1333+
valid_types = (int, int8, int16, int32, int64,
1334+
float, float16, float32, float64, float128,
1335+
complex, complex64, complex128, complex256)
1336+
valid_collection = (list, tuple, ndarray)
1337+
1338+
if (isinstance(data, valid_types) or
1339+
(isinstance(data, ndarray) and data.ndim == 0)):
1340+
return [[array([data], dtype=float)]]
1341+
elif (isinstance(data, valid_collection) and
1342+
all([isinstance(d, valid_types) for d in data])):
1343+
return [[array(data, dtype=float)]]
1344+
elif (isinstance(data, list) and
1345+
isinstance(data[0], list) and
1346+
(isinstance(data[0][0], valid_collection) and
1347+
isinstance(data[0][0][0], valid_types))):
1348+
for j in range(len(data)):
1349+
for k in range(len(data[j])):
1350+
data[j][k] = array(data[j][k], dtype=float)
1351+
return data
1352+
else:
1353+
# If the user passed in anything else, then it's unclear what
1354+
# the meaning is.
1355+
raise TypeError("The numerator and denominator inputs must be \
1356+
scalars or vectors (for\nSISO), or lists of lists of vectors (for SISO or \
1357+
MIMO).")

notebooks/IO_Cleanup.ipynb

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {
7+
"collapsed": true
8+
},
9+
"outputs": [],
10+
"source": [
11+
"from numpy import int, int8, int16, int32, int64\n",
12+
"from numpy import float, float16, float32, float64, float128\n",
13+
"from numpy import complex, complex64, complex128, complex256\n",
14+
"from numpy import all, ndarray, array\n",
15+
"import numpy as np"
16+
]
17+
},
18+
{
19+
"cell_type": "code",
20+
"execution_count": 2,
21+
"metadata": {
22+
"collapsed": false
23+
},
24+
"outputs": [],
25+
"source": [
26+
"def tf_clean_parts(data):\n",
27+
" '''\n",
28+
" Return a valid, cleaned up numerator or denominator \n",
29+
" for the TransferFunction class.\n",
30+
" \n",
31+
" Parameters:\n",
32+
" data: numerator or denominator of a transfer function.\n",
33+
" \n",
34+
" Returns:\n",
35+
" data: correctly formatted transfer function part.\n",
36+
" \n",
37+
" '''\n",
38+
" valid_types = (int, int8, int16, int32, int64,\n",
39+
" float, float16, float32, float64, float128,\n",
40+
" complex, complex64, complex128, complex256)\n",
41+
" valid_collection = (list, tuple, ndarray)\n",
42+
"\n",
43+
" if (isinstance(data, valid_types) or\n",
44+
" (isinstance(data, ndarray) and data.ndim == 0)):\n",
45+
" return [[array([data], dtype=float)]]\n",
46+
" elif (isinstance(data, valid_collection) and\n",
47+
" all([isinstance(d, valid_types) for d in data])):\n",
48+
" return [[array(data, dtype=float)]]\n",
49+
" elif (isinstance(data, list) and\n",
50+
" isinstance(data[0], list) and\n",
51+
" (isinstance(data[0][0], valid_collection) and \n",
52+
" isinstance(data[0][0][0], valid_types))):\n",
53+
" for j in range(len(data)):\n",
54+
" for k in range(len(data[j])):\n",
55+
" data[j][k] = array(data[j][k], dtype=float)\n",
56+
" return data\n",
57+
" else:\n",
58+
" # If the user passed in anything else, then it's unclear what\n",
59+
" # the meaning is.\n",
60+
" raise TypeError(\"The numerator and denominator inputs must be \\\n",
61+
"scalars or vectors (for\\nSISO), or lists of lists of vectors (for SISO or \\\n",
62+
"MIMO).\")"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": 3,
68+
"metadata": {
69+
"collapsed": false
70+
},
71+
"outputs": [],
72+
"source": [
73+
"num = 1\n",
74+
"num_ = tf_clean_parts(num)\n",
75+
"np.testing.assert_array_equal(num_[0][0], array([1.0], dtype=float))"
76+
]
77+
},
78+
{
79+
"cell_type": "code",
80+
"execution_count": 4,
81+
"metadata": {
82+
"collapsed": false
83+
},
84+
"outputs": [],
85+
"source": [
86+
"num = [1]\n",
87+
"num_ = tf_clean_parts(num)\n",
88+
"np.testing.assert_array_equal(num_[0][0], array([1.0], dtype=float))"
89+
]
90+
},
91+
{
92+
"cell_type": "code",
93+
"execution_count": 5,
94+
"metadata": {
95+
"collapsed": false,
96+
"scrolled": true
97+
},
98+
"outputs": [],
99+
"source": [
100+
"num = [1,1]\n",
101+
"num_ = tf_clean_parts(num)\n",
102+
"np.testing.assert_array_equal(num_[0][0], array([1.0, 1.0], dtype=float))"
103+
]
104+
},
105+
{
106+
"cell_type": "code",
107+
"execution_count": 6,
108+
"metadata": {
109+
"collapsed": false
110+
},
111+
"outputs": [],
112+
"source": [
113+
"num = [[[1,1],[2,2]]]\n",
114+
"num_ = tf_clean_parts(num)\n",
115+
"np.testing.assert_array_equal(num_[0][0], array([1.0, 1.0], dtype=float))\n",
116+
"np.testing.assert_array_equal(num_[0][1], array([2.0, 2.0], dtype=float))"
117+
]
118+
},
119+
{
120+
"cell_type": "code",
121+
"execution_count": 7,
122+
"metadata": {
123+
"collapsed": true
124+
},
125+
"outputs": [],
126+
"source": [
127+
"num = [[[1.0,1.0],[2.0,2.0]]]\n",
128+
"num_ = tf_clean_parts(num)\n",
129+
"np.testing.assert_array_equal(num_[0][0], array([1.0, 1.0], dtype=float))\n",
130+
"np.testing.assert_array_equal(num_[0][1], array([2.0, 2.0], dtype=float))"
131+
]
132+
},
133+
{
134+
"cell_type": "code",
135+
"execution_count": 8,
136+
"metadata": {
137+
"collapsed": false
138+
},
139+
"outputs": [],
140+
"source": [
141+
"num = [[array([1,1]),array([2,2])]]\n",
142+
"num_ = tf_clean_parts(num)\n",
143+
"np.testing.assert_array_equal(num_[0][0], array([1.0, 1.0], dtype=float))\n",
144+
"np.testing.assert_array_equal(num_[0][1], array([2.0, 2.0], dtype=float))"
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": 9,
150+
"metadata": {
151+
"collapsed": true
152+
},
153+
"outputs": [],
154+
"source": [
155+
"num = [[array([1.0,1.0]),array([2.0,2.0])]]\n",
156+
"num_ = tf_clean_parts(num)\n",
157+
"np.testing.assert_array_equal(num_[0][0], array([1.0, 1.0], dtype=float))\n",
158+
"np.testing.assert_array_equal(num_[0][1], array([2.0, 2.0], dtype=float))"
159+
]
160+
},
161+
{
162+
"cell_type": "code",
163+
"execution_count": 10,
164+
"metadata": {
165+
"collapsed": false
166+
},
167+
"outputs": [
168+
{
169+
"data": {
170+
"text/plain": [
171+
"[[array([ 1., 2., 3.]), array([ 1., 2., 3.])]]"
172+
]
173+
},
174+
"execution_count": 10,
175+
"metadata": {},
176+
"output_type": "execute_result"
177+
}
178+
],
179+
"source": [
180+
"num = [[[1,2,3],[1,2,3]]]\n",
181+
"tf_clean_parts(num)"
182+
]
183+
},
184+
{
185+
"cell_type": "code",
186+
"execution_count": 11,
187+
"metadata": {
188+
"collapsed": false
189+
},
190+
"outputs": [
191+
{
192+
"ename": "TypeError",
193+
"evalue": "The numerator and denominator inputs must be scalars or vectors (for\nSISO), or lists of lists of vectors (for SISO or MIMO).",
194+
"output_type": "error",
195+
"traceback": [
196+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
197+
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
198+
"\u001b[0;32m<ipython-input-11-735b56338072>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mnum\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtf_clean_parts\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
199+
"\u001b[0;32m<ipython-input-2-f22688626b29>\u001b[0m in \u001b[0;36mtf_clean_parts\u001b[0;34m(data)\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0;31m# If the user passed in anything else, then it's unclear what\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;31m# the meaning is.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 35\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"The numerator and denominator inputs must be scalars or vectors (for\\nSISO), or lists of lists of vectors (for SISO or MIMO).\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
200+
"\u001b[0;31mTypeError\u001b[0m: The numerator and denominator inputs must be scalars or vectors (for\nSISO), or lists of lists of vectors (for SISO or MIMO)."
201+
]
202+
}
203+
],
204+
"source": [
205+
"num = [[1,2,3],[1,2,3]]\n",
206+
"tf_clean_parts(num)"
207+
]
208+
}
209+
],
210+
"metadata": {
211+
"kernelspec": {
212+
"display_name": "Python 3",
213+
"language": "python",
214+
"name": "python3"
215+
},
216+
"language_info": {
217+
"codemirror_mode": {
218+
"name": "ipython",
219+
"version": 3
220+
},
221+
"file_extension": ".py",
222+
"mimetype": "text/x-python",
223+
"name": "python",
224+
"nbconvert_exporter": "python",
225+
"pygments_lexer": "ipython3",
226+
"version": "3.5.2"
227+
}
228+
},
229+
"nbformat": 4,
230+
"nbformat_minor": 0
231+
}

0 commit comments

Comments
 (0)