Skip to content

Configure flake8. Fix flake8 errors where possible. #283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ python:

# Test against multiple version of SciPy, with and without slycot
#
# Because there were significant changes in SciPy between v0 and v1, we
# Because there were significant changes in SciPy between v0 and v1, we
# test against both of these using the Travis CI environment capability
#
# We also want to test with and without slycot
Expand Down Expand Up @@ -62,7 +62,7 @@ before_install:
# Install packages
install:
# Install packages needed by python-control
- conda install $SCIPY matplotlib
- conda install $SCIPY matplotlib flake8
# Build slycot from source
# For python 3, need to provide pointer to python library
#! git clone https://github.com/repagh/Slycot.git slycot;
Expand All @@ -71,6 +71,9 @@ install:
cd slycot; python setup.py install; cd ..;
fi

before_script:
- flake8 control/

# command to run tests
script:
- 'if [ $SLYCOT != "" ]; then python -c "import slycot"; fi'
Expand Down
46 changes: 23 additions & 23 deletions control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,34 @@

# Import functions from within the control system library
# Note: the functions we use are specified as __all__ variables in the modules
from .bdalg import *
from .delay import *
from .dtime import *
from .freqplot import *
from .lti import *
from .margins import *
from .mateqn import *
from .modelsimp import *
from .nichols import *
from .phaseplot import *
from .pzmap import *
from .rlocus import *
from .statefbk import *
from .statesp import *
from .timeresp import *
from .xferfcn import *
from .ctrlutil import *
from .frdata import *
from .canonical import *
from .robust import *
from .config import *
from .bdalg import * # noqa F403, F401
from .delay import * # noqa F403, F401
from .dtime import * # noqa F403, F401
from .freqplot import * # noqa F403, F401
from .lti import * # noqa F403, F401
from .margins import * # noqa F403, F401
from .mateqn import * # noqa F403, F401
from .modelsimp import * # noqa F403, F401
from .nichols import * # noqa F403, F401
from .phaseplot import * # noqa F403, F401
from .pzmap import * # noqa F403, F401
from .rlocus import * # noqa F403, F401
from .statefbk import * # noqa F403, F401
from .statesp import * # noqa F403, F401
from .timeresp import * # noqa F403, F401
from .xferfcn import * # noqa F403, F401
from .ctrlutil import * # noqa F403, F401
from .frdata import * # noqa F403, F401
from .canonical import * # noqa F403, F401
from .robust import * # noqa F403, F401
from .config import * # noqa F403, F401

# Exceptions
from .exception import *
from .exception import * # noqa F403, F401

# Version information
try:
from ._version import __version__, __commit__
from ._version import __version__, __commit__ # noqa F403, F401
except ImportError:
__version__ = "dev"

Expand Down
69 changes: 36 additions & 33 deletions control/bdalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@

__all__ = ['series', 'parallel', 'negate', 'feedback', 'append', 'connect']


def series(sys1, *sysn):
"""Return the series connection (... \* sys3 \*) sys2 \* sys1
"""
Return the series connection (... \* sys3 \*) sys2 \* sys1

Parameters
----------
Expand Down Expand Up @@ -103,7 +105,8 @@ def series(sys1, *sysn):

"""
from functools import reduce
return reduce(lambda x, y:y*x, sysn, sys1)
return reduce(lambda x, y: y * x, sysn, sys1)


def parallel(sys1, *sysn):
"""
Expand Down Expand Up @@ -148,7 +151,8 @@ def parallel(sys1, *sysn):

"""
from functools import reduce
return reduce(lambda x, y:x+y, sysn, sys1)
return reduce(lambda x, y: x + y, sysn, sys1)


def negate(sys):
"""
Expand Down Expand Up @@ -178,9 +182,10 @@ def negate(sys):

"""

return -sys;
return -sys

#! TODO: expand to allow sys2 default to work in MIMO case?

# TODO: expand to allow sys2 default to work in MIMO case?
def feedback(sys1, sys2=1, sign=-1):
"""
Feedback interconnection between two I/O systems.
Expand Down Expand Up @@ -226,14 +231,10 @@ def feedback(sys1, sys2=1, sign=-1):
"""

# Check for correct input types.
if not isinstance(sys1, (int, float, complex, np.number,
tf.TransferFunction, ss.StateSpace, frd.FRD)):
raise TypeError("sys1 must be a TransferFunction, StateSpace " +
"or FRD object, or a scalar.")
if not isinstance(sys2, (int, float, complex, np.number,
tf.TransferFunction, ss.StateSpace, frd.FRD)):
raise TypeError("sys2 must be a TransferFunction, StateSpace " +
"or FRD object, or a scalar.")
if not isinstance(sys1, (int, float, complex, np.number, tf.TransferFunction, ss.StateSpace, frd.FRD)):
raise TypeError("sys1 must be a TransferFunction, StateSpace or FRD object, or a scalar.")
if not isinstance(sys2, (int, float, complex, np.number, tf.TransferFunction, ss.StateSpace, frd.FRD)):
raise TypeError("sys2 must be a TransferFunction, StateSpace or FRD object, or a scalar.")

# If sys1 is a scalar, convert it to the appropriate LTI type so that we can
# its feedback member function.
Expand All @@ -244,15 +245,15 @@ def feedback(sys1, sys2=1, sign=-1):
sys1 = ss._convertToStateSpace(sys1)
elif isinstance(sys2, frd.FRD):
sys1 = ss._convertToFRD(sys1)
else: # sys2 is a scalar.
else: # sys2 is a scalar.
sys1 = tf._convert_to_transfer_function(sys1)
sys2 = tf._convert_to_transfer_function(sys2)

return sys1.feedback(sys2, sign)

def append(*sys):
'''append(sys1, sys2, ..., sysn)

def append(*sys):
"""
Group models by appending their inputs and outputs

Forms an augmented system model, and appends the inputs and
Expand All @@ -278,16 +279,17 @@ def append(*sys):
>>> sys2 = ss("-1.", "1.", "1.", "0.")
>>> sys = append(sys1, sys2)

.. todo::
also implement for transfer function, zpk, etc.
'''
# TODO : also implement for transfer function, zpk, etc.
"""

s1 = sys[0]
for s in sys[1:]:
s1 = s1.append(s)
return s1


def connect(sys, Q, inputv, outputv):
'''
"""
Index-base interconnection of system

The system sys is a system typically constructed with append, with
Expand Down Expand Up @@ -324,23 +326,24 @@ def connect(sys, Q, inputv, outputv):
>>> sys = append(sys1, sys2)
>>> Q = sp.mat([ [ 1, 2], [2, -1] ]) # basically feedback, output 2 in 1
>>> sysc = connect(sys, Q, [2], [1, 2])
'''
"""

# first connect
K = sp.zeros( (sys.inputs, sys.outputs) )
K = sp.zeros((sys.inputs, sys.outputs))
for r in sp.array(Q).astype(int):
inp = r[0]-1
inp = r[0] - 1
for outp in r[1:]:
if outp > 0 and outp <= sys.outputs:
K[inp,outp-1] = 1.
if 0 < outp <= sys.outputs:
K[inp, outp - 1] = 1.
elif outp < 0 and -outp >= -sys.outputs:
K[inp,-outp-1] = -1.
K[inp, -outp - 1] = -1.
sys = sys.feedback(sp.matrix(K), sign=1)

# now trim
Ytrim = sp.zeros( (len(outputv), sys.outputs) )
Utrim = sp.zeros( (sys.inputs, len(inputv)) )
for i,u in enumerate(inputv):
Utrim[u-1,i] = 1.
for i,y in enumerate(outputv):
Ytrim[i,y-1] = 1.
return sp.matrix(Ytrim)*sys*sp.matrix(Utrim)
Ytrim = sp.zeros((len(outputv), sys.outputs))
Utrim = sp.zeros((sys.inputs, len(inputv)))
for i, u in enumerate(inputv):
Utrim[u - 1, i] = 1.
for i, y in enumerate(outputv):
Ytrim[i, y - 1] = 1.
return sp.matrix(Ytrim) * sys * sp.matrix(Utrim)
4 changes: 3 additions & 1 deletion control/bench/time_freqresp.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
nstates = 10
sys = rss(nstates)
sys_tf = tf(sys)
w = logspace(-1,1,50)
w = logspace(-1, 1, 50)
ntimes = 1000

time_ss = timeit("sys.freqresp(w)", setup="from __main__ import sys, w", number=ntimes)
time_tf = timeit("sys_tf.freqresp(w)", setup="from __main__ import sys_tf, w", number=ntimes)

print("State-space model on %d states: %f" % (nstates, time_ss))
print("Transfer-function model on %d states: %f" % (nstates, time_tf))
22 changes: 11 additions & 11 deletions control/canonical.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

__all__ = ['canonical_form', 'reachable_form', 'observable_form']


def canonical_form(xsys, form='reachable'):
"""Convert a system into canonical form

Expand Down Expand Up @@ -40,8 +41,7 @@ def canonical_form(xsys, form='reachable'):
elif form == 'modal':
return modal_form(xsys)
else:
raise ControlNotImplemented(
"Canonical form '%s' not yet implemented" % form)
raise ControlNotImplemented("Canonical form '%s' not yet implemented" % form)


# Reachable canonical form
Expand All @@ -62,8 +62,7 @@ def reachable_form(xsys):
"""
# Check to make sure we have a SISO system
if not issiso(xsys):
raise ControlNotImplemented(
"Canonical forms for MIMO systems not yet supported")
raise ControlNotImplemented("Canonical forms for MIMO systems not yet supported")

# Create a new system, starting with a copy of the old one
zsys = StateSpace(xsys)
Expand All @@ -74,9 +73,9 @@ def reachable_form(xsys):
zsys.A = zeros(shape(xsys.A))
Apoly = poly(xsys.A) # characteristic polynomial
for i in range(0, xsys.states):
zsys.A[0, i] = -Apoly[i+1] / Apoly[0]
if (i+1 < xsys.states):
zsys.A[i+1, i] = 1.0
zsys.A[0, i] = -Apoly[i + 1] / Apoly[0]
if i + 1 < xsys.states:
zsys.A[i + 1, i] = 1.0

# Compute the reachability matrices for each set of states
Wrx = ctrb(xsys.A, xsys.B)
Expand Down Expand Up @@ -126,9 +125,9 @@ def observable_form(xsys):
zsys.A = zeros(shape(xsys.A))
Apoly = poly(xsys.A) # characteristic polynomial
for i in range(0, xsys.states):
zsys.A[i, 0] = -Apoly[i+1] / Apoly[0]
if (i+1 < xsys.states):
zsys.A[i, i+1] = 1
zsys.A[i, 0] = -Apoly[i + 1] / Apoly[0]
if i + 1 < xsys.states:
zsys.A[i, i + 1] = 1

# Compute the observability matrices for each set of states
Wrx = obsv(xsys.A, xsys.C)
Expand All @@ -145,6 +144,7 @@ def observable_form(xsys):

return zsys, Tzx


def modal_form(xsys):
"""Convert a system into modal canonical form

Expand Down Expand Up @@ -176,7 +176,7 @@ def modal_form(xsys):
# Sorting eigenvalues and respective vectors by largest to smallest eigenvalue
idx = eigval.argsort()[::-1]
eigval = eigval[idx]
eigvec = eigvec[:,idx]
eigvec = eigvec[:, idx]

# If all eigenvalues are real, the matrix of eigenvectors is Tzx directly
if not iscomplex(eigval).any():
Expand Down
20 changes: 14 additions & 6 deletions control/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
bode_number_of_samples = None # Bode plot number of samples
bode_feature_periphery_decade = 1.0 # Bode plot feature periphery in decades


# Set defaults to match MATLAB
def use_matlab_defaults():
"""
Expand All @@ -23,9 +24,13 @@ def use_matlab_defaults():
* Bode plots plot gain in dB, phase in degrees, frequency in Hertz
"""
# Bode plot defaults
global bode_dB; bode_dB = True
global bode_deg; bode_deg = True
global bode_Hz; bode_Hz = True
global bode_dB
bode_dB = True
global bode_deg
bode_deg = True
global bode_Hz
bode_Hz = True


# Set defaults to match FBS (Astrom and Murray)
def use_fbs_defaults():
Expand All @@ -37,6 +42,9 @@ def use_fbs_defaults():
frequency in Hertz
"""
# Bode plot defaults
global bode_dB; bode_dB = False
global bode_deg; bode_deg = True
global bode_Hz; bode_Hz = True
global bode_dB
bode_dB = False
global bode_deg
bode_deg = True
global bode_Hz
bode_Hz = True
8 changes: 6 additions & 2 deletions control/ctrlutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@

__all__ = ['unwrap', 'issys', 'db2mag', 'mag2db']


# Utility function to unwrap an angle measurement
def unwrap(angle, period=2*math.pi):
def unwrap(angle, period=2 * math.pi):
"""Unwrap a phase angle to give a continuous curve

Parameters
Expand All @@ -72,15 +73,17 @@ def unwrap(angle, period=2*math.pi):

"""
dangle = np.diff(angle)
dangle_desired = (dangle + period/2.) % period - period/2.
dangle_desired = (dangle + period / 2.) % period - period / 2.
correction = np.cumsum(dangle_desired - dangle)
angle[1:] += correction
return angle


def issys(obj):
"""Return True if an object is a system, otherwise False"""
return isinstance(obj, lti.LTI)


def db2mag(db):
"""Convert a gain in decibels (dB) to a magnitude

Expand All @@ -101,6 +104,7 @@ def db2mag(db):
"""
return 10. ** (db / 20.)


def mag2db(mag):
"""Convert a magnitude to decibels (dB)

Expand Down
Loading