Skip to content

Commit 80b0f7b

Browse files
committed
Many small updates to make compatible with python 3.x:
* Updated unit tests to skip certain tests if slycot is not installed * Fixed some problems with timebase (dt) to avoid comparing None to int * Fixed exception syntax in a few more spots (E, T to E(T)) * Fixed print syntax in a few more spots (backward compatible with 2.6+) * Updated FRD to include python 3.x fixes installed in other modules * tests/test_*.py scripts not working in 3.x, but individual tests OK * Current version works with nosetests in py2.7, py3.2 (-slycot) Also, a few other updates not directly relate to python 3.x: * Added FRD to sphinx documentation * Set tests/{test_all.py,test_control_matlab.py} to executable so that they are skipped by nosetests
1 parent 6dc7628 commit 80b0f7b

21 files changed

Lines changed: 132 additions & 58 deletions

ChangeLog

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,48 @@
11
2012-11-03 Richard Murray <murray@altura.local>
22

3+
* src/rlocus.py (_RLSortRoots): convert output of range() to
4+
explicit list for python 3 compatability
5+
6+
* tests/modelsimp_test.py, tests/slycot_convert_test.py,
7+
tests/mateqn_test.py, tests/statefbk_test.py: updated test suites to
8+
skip specific tests that require slycot if it is not installed
9+
10+
* src/exception.py (slycot_check): added a function to check if
11+
slycot is installed
12+
13+
* README: updated readme to include information about running
14+
nosetests, which works in python3 (unlike the test_all.py script)
15+
16+
* tests/test_control_matlab.py, tests/test_all.py: set to executable
17+
so that nosetests does not run this file (it already runs all unit
18+
tests in this directory). Add comments at top talking about tests.
19+
20+
* tests/discrete_test.py (TestDiscrete.test_discrete_bode):
21+
explicitly create a list from map() output for python 3
22+
23+
* src/frdata.py: removed long data type from comparisons for
24+
constant systems (not supported in python3)
25+
26+
* src/xferfcn.py (TransferFunction.freqresp): force frequencies to
27+
be a list (map returns iterator in python3)
28+
29+
* src/lti.py (isdtime, isctime): updated timebase checking since
30+
python3 won't allow dt to be compared to integer
31+
32+
* src/__init__.py: updated frdata import to python3 compatible form
33+
34+
* src/statesp.py (_convertToStateSpace): fixed exception syntax to
35+
be python3 compatible
36+
37+
* examples/pvtol-nested.py: converted print statements to be python3
38+
compatible
39+
40+
* doc/class_strings.rst: added FRD class to list of classes that
41+
show up in the user documentation
42+
43+
* examples/rss-balred.py: fixed error in output argument order for
44+
call to matlab.impulse
45+
346
* ../README: updated readme file as a test of post-commit hook
447

548
2012-11-02 Richard Murray <murray@altura.local>

README

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ Python Control System Library
22
RMM, 23 May 09
33

44
This directory contains the source code for the Python Control Systems
5-
Library (python-control). This library is still under development,
6-
but is intended to serve as a wrapper for standard control system
7-
algorithms in the python programming environment.
5+
Library (python-control). This library is still under development, but is
6+
intended to serve as a wrapper for standard control system algorithms in the
7+
python programming environment.
88

99
Installation instructions
1010
-------------------------
@@ -13,13 +13,18 @@ Standard python package installation:
1313
python setup.py install
1414

1515
To see if things are working, you can run the script
16-
examples/secord-matlab.py (using ipython -pylab). It should generate
17-
a step response, Bode plot and Nyquist plot for a simple second order
18-
linear system.
16+
examples/secord-matlab.py (using ipython -pylab). It should generate a step
17+
response, Bode plot and Nyquist plot for a simple second order linear
18+
system.
1919

20-
You can also run a set of unit tests to make sure that everything is
21-
working correctly. After installation, run
20+
You can also run a set of unit tests to make sure that everything is working
21+
correctly. After installation, run
2222

2323
python tests/test_all.py
2424

25-
from the source distribution directory.
25+
from the source distribution directory (note: doesn't yet work in python
26+
3.x). Alternatively, if you have nosetests installed, you can simply run
27+
28+
nosetests
29+
30+
which gives a somewhat cleaner output (and works in python 3.x)

doc/class_strings.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ Transfer Function Class
1010
=======================
1111
.. automodule:: xferfcn
1212
:members:
13+
14+
FRD Class
15+
=========
16+
.. automodule:: frdata
17+
:members:

examples/pvtol-nested.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
# package.
99
#
1010

11+
from __future__ import print_function
1112
from matplotlib.pyplot import * # Grab MATLAB plotting functions
1213
from control.matlab import * # MATLAB-like functions
1314
import numpy as np
@@ -142,7 +143,7 @@
142143

143144
figure(10); clf();
144145
(P, Z) = pzmap(T, Plot=True)
145-
print "Closed loop poles and zeros: ", P, Z
146+
print("Closed loop poles and zeros: ", P, Z)
146147

147148
# Gang of Four
148149
figure(11); clf();

examples/rss-balred.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
# Comparison of the impulse responses of the full and reduced random systems
4040
plt.figure(2)
41-
trand, yrand = mt.impulse(sysrand)
42-
trandr, yrandr = mt.impulse(rsysrand)
43-
plt.plot(trand.T, yrand.T,trandr.T, yrandr.T)
41+
yrand, trand = mt.impulse(sysrand)
42+
yrandr, trandr = mt.impulse(rsysrand)
43+
plt.plot(trand.T, yrand.T, trandr.T, yrandr.T)
4444

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
impulse_response
7777
from control.xferfcn import TransferFunction
7878
from control.ctrlutil import unwrap, issys
79-
from frdata import FRD
79+
from control.frdata import FRD
8080

8181
# Import some of the more common (and benign) MATLAB shortcuts
8282
# By default, don't import conflicting commands here

src/exception.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,12 @@ class ControlMIMONotImplemented(Exception):
5959
class ControlNotImplemented(Exception):
6060
"""Functionality is not yet implemented"""
6161
pass
62+
63+
# Utility function to see if slycot is installed
64+
def slycot_check():
65+
try:
66+
import slycot
67+
except:
68+
return False
69+
else:
70+
return True

src/frdata.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,10 @@
7777
real, imag, matrix, absolute, eye, linalg, pi, where
7878
from scipy.interpolate import splprep, splev
7979
from copy import deepcopy
80-
from lti import Lti
81-
import statesp
80+
from control.lti import Lti
81+
import control.statesp as statesp
8282

8383
class FRD(Lti):
84-
8584
"""The FRD class represents (measured?) frequency response
8685
TF instances and functions.
8786
@@ -245,7 +244,7 @@ def __mul__(self, other):
245244
"""Multiply two LTI objects (serial connection)."""
246245

247246
# Convert the second argument to a transfer function.
248-
if isinstance(other, (int, float, long, complex)):
247+
if isinstance(other, (int, float, complex)):
249248
other = _convertToFRD(other, inputs=self.inputs,
250249
outputs=self.inputs, omega=self.omega)
251250
else:
@@ -287,7 +286,7 @@ def __rmul__(self, other):
287286
def __div__(self, other):
288287
"""Divide two LTI objects."""
289288

290-
if isinstance(other, (int, float, long, complex)):
289+
if isinstance(other, (int, float, complex)):
291290
other = _convertToFRD(other, inputs=self.inputs,
292291
outputs=self.inputs, omega=self.omega)
293292
else:
@@ -307,7 +306,7 @@ def __div__(self, other):
307306
# TODO: Division of MIMO transfer function objects is not written yet.
308307
def __rdiv__(self, other):
309308
"""Right divide two LTI objects."""
310-
if isinstance(other, (int, float, long, complex)):
309+
if isinstance(other, (int, float, complex)):
311310
other = _convertToFRD(other, inputs=self.inputs,
312311
outputs=self.inputs, omega=self.omega)
313312
else:
@@ -443,7 +442,7 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
443442

444443
return FRD(fresp, omega)
445444

446-
elif isinstance(sys, (int, long, float, complex)):
445+
elif isinstance(sys, (int, float, complex)):
447446
fresp = ones((outputs, inputs, len(omega)), dtype=float)*sys
448447
return FRD(fresp, omega)
449448

src/lti.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,12 @@ def isdtime(sys, strict=False):
110110

111111
# Check for a transfer fucntion or state space object
112112
if isinstance(sys, Lti):
113-
# Look for dt > 0 or dt == None (if not strict)
114-
# Note that dt = True will be checked by dt > 0
115-
return sys.dt > 0 or (not strict and sys.dt == None)
113+
# If no timebase is given, answer depends on strict flag
114+
if sys.dt == None:
115+
return True if not strict else False
116+
117+
# Look for dt > 0 (also works if dt = True)
118+
return sys.dt > 0
116119

117120
# Got possed something we don't recognize
118121
return False
@@ -127,8 +130,12 @@ def isctime(sys, strict=False):
127130

128131
# Check for a transfer fucntion or state space object
129132
if isinstance(sys, Lti):
130-
# Look for dt == 0 or dt == None (if not strict)
131-
return sys.dt == 0 or (not strict and sys.dt == None)
133+
# If no timebase is given, answer depends on strict flag
134+
if sys.dt == None:
135+
return True if not strict else False
136+
137+
# Look for dt == 0
138+
return sys.dt == 0
132139

133140
# Got possed something we don't recognize
134141
return False

src/rlocus.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def _RLSortRoots(sys, mymat):
157157
# sort the current row by finding the element with the
158158
# smallest absolute distance to each root in the
159159
# previous row
160-
available = range(len(prevrow))
160+
available = list(range(len(prevrow)))
161161
for elem in row:
162162
evect = elem-prevrow[available]
163163
ind1 = abs(evect).argmin()

0 commit comments

Comments
 (0)