Skip to content
Merged
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
3 changes: 2 additions & 1 deletion control/bdalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ def feedback(sys1, sys2=1, sign=-1):
return sys1.feedback(sys2, sign)

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

Group models by appending their inputs and outputs

Forms an augmented system model, and appends the inputs and
Expand Down
4 changes: 2 additions & 2 deletions control/ctrlutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
# Packages that we need access to
from . import lti
import numpy as np
from numpy import pi
import math

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

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

Parameters
Expand Down
15 changes: 10 additions & 5 deletions control/frdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
__all__ = ['FRD', 'frd']

class FRD(LTI):
"""A class for models defined by Frequency Response Data (FRD)
"""FRD(d, w)

A class for models defined by frequency response data (FRD)

The FRD class is used to represent systems in frequency response data form.

Expand All @@ -81,7 +83,9 @@ class FRD(LTI):
epsw = 1e-8

def __init__(self, *args, **kwargs):
"""Construct an FRD object
"""FRD(d, w)

Construct an FRD object

The default constructor is FRD(d, w), where w is an iterable of
frequency points, and d is the matching frequency data.
Expand Down Expand Up @@ -470,8 +474,9 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
sys.__class__)

def frd(*args):
"""
Construct a Frequency Response Data model, or convert a system
"""frd(d, w)

Construct a frequency response data model

frd models store the (measured) frequency response of a system.

Expand Down Expand Up @@ -501,6 +506,6 @@ def frd(*args):

See Also
--------
ss, tf
FRD, ss, tf
"""
return FRD(*args)
23 changes: 12 additions & 11 deletions control/freqplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import matplotlib.pyplot as plt
import scipy as sp
import numpy as np
import math
from .ctrlutil import unwrap
from .bdalg import feedback

Expand Down Expand Up @@ -128,7 +129,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
else:
omega_limits = np.array(omega_limits)
if Hz:
omega_limits *= 2.*np.pi
omega_limits *= 2.*math.pi
if omega_num:
omega = sp.logspace(np.log10(omega_limits[0]), np.log10(omega_limits[1]), num=omega_num, endpoint=True)
else:
Expand All @@ -142,7 +143,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
else:
omega_sys = np.array(omega)
if sys.isdtime(True):
nyquistfrq = 2. * np.pi * 1. / sys.dt / 2.
nyquistfrq = 2. * math.pi * 1. / sys.dt / 2.
omega_sys = omega_sys[omega_sys < nyquistfrq]
# TODO: What distance to the Nyquist frequency is appropriate?
else:
Expand All @@ -154,9 +155,9 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
phase = unwrap(phase)
nyquistfrq_plot = None
if Hz:
omega_plot = omega_sys / (2. * np.pi)
omega_plot = omega_sys / (2. * math.pi)
if nyquistfrq:
nyquistfrq_plot = nyquistfrq / (2. * np.pi)
nyquistfrq_plot = nyquistfrq / (2. * math.pi)
else:
omega_plot = omega_sys
if nyquistfrq:
Expand Down Expand Up @@ -187,7 +188,7 @@ def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
# Phase plot
ax_phase = plt.subplot(212, sharex=ax_mag);
if deg:
phase_plot = phase * 180. / np.pi
phase_plot = phase * 180. / math.pi
else:
phase_plot = phase
ax_phase.semilogx(omega_plot, phase_plot, *args, **kwargs)
Expand All @@ -208,8 +209,8 @@ def genZeroCenteredSeries(val_min, val_max, period):
ax_phase.set_yticks(genZeroCenteredSeries(ylim[0], ylim[1], 15.), minor=True)
else:
ylim = ax_phase.get_ylim()
ax_phase.set_yticks(genZeroCenteredSeries(ylim[0], ylim[1], np.pi / 4.))
ax_phase.set_yticks(genZeroCenteredSeries(ylim[0], ylim[1], np.pi / 12.), minor=True)
ax_phase.set_yticks(genZeroCenteredSeries(ylim[0], ylim[1], math.pi / 4.))
ax_phase.set_yticks(genZeroCenteredSeries(ylim[0], ylim[1], math.pi / 12.), minor=True)
ax_phase.grid(True, which='both')
# ax_mag.grid(which='minor', alpha=0.3)
# ax_mag.grid(which='major', alpha=0.9)
Expand Down Expand Up @@ -449,7 +450,7 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None, feature_pe
features_ = features_[features_ != 0.0];
features = np.concatenate((features, features_))
elif sys.isdtime(strict=True):
fn = np.pi * 1. / sys.dt
fn = math.pi * 1. / sys.dt
# TODO: What distance to the Nyquist frequency is appropriate?
freq_interesting.append(fn * 0.9)

Expand All @@ -475,12 +476,12 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None, feature_pe
features = np.array([1.]);

if Hz:
features /= 2.*np.pi
features /= 2.*math.pi
features = np.log10(features)
lsp_min = np.floor(np.min(features) - feature_periphery_decade)
lsp_max = np.ceil(np.max(features) + feature_periphery_decade)
lsp_min += np.log10(2.*np.pi)
lsp_max += np.log10(2.*np.pi)
lsp_min += np.log10(2.*math.pi)
lsp_max += np.log10(2.*math.pi)
else:
features = np.log10(features)
lsp_min = np.floor(np.min(features) - feature_periphery_decade)
Expand Down
21 changes: 11 additions & 10 deletions control/margins.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,21 @@
Date: 14 July 2011

$Id$

"""

import math
import numpy as np
import scipy as sp
from . import xferfcn
from .lti import issiso
from . import frdata
import scipy as sp

__all__ = ['stability_margins', 'phase_crossover_frequencies', 'margin']

# helper functions for stability_margins
def _polyimsplit(pol):
"""split a polynomial with (iw) applied into a real and an
imaginary part with w applied"""
imaginary part with w applied"""
rpencil = np.zeros_like(pol)
ipencil = np.zeros_like(pol)
rpencil[-1::-4] = 1.
Expand Down Expand Up @@ -141,7 +141,7 @@ def stability_margins(sysdata, returnall=False, epsw=0.0):
sys = sysdata
elif getattr(sysdata, '__iter__', False) and len(sysdata) == 3:
mag, phase, omega = sysdata
sys = frdata.FRD(mag * np.exp(1j * phase * np.pi/180),
sys = frdata.FRD(mag * np.exp(1j * phase * math.pi/180),
omega, smooth=True)
else:
sys = xferfcn._convertToTransferFunction(sysdata)
Expand Down Expand Up @@ -294,8 +294,7 @@ def dstab(w):
# Contributed by Steffen Waldherr <waldherr@ist.uni-stuttgart.de>
#! TODO - need to add test functions
def phase_crossover_frequencies(sys):
"""
Compute frequencies and gains at intersections with real axis
"""Compute frequencies and gains at intersections with real axis
in Nyquist plot.

Call as:
Expand Down Expand Up @@ -338,11 +337,13 @@ def phase_crossover_frequencies(sys):


def margin(*args):
"""Calculate gain and phase margins and associated crossover frequencies
"""margin(sysdata)

Calculate gain and phase margins and associated crossover frequencies

Parameters
----------
sysdata: LTI system or (mag, phase, omega) sequence
sysdata : LTI system or (mag, phase, omega) sequence
sys : StateSpace or TransferFunction
Linear SISO system
mag, phase, omega : sequence of array_like
Expand All @@ -360,8 +361,8 @@ def margin(*args):
Wcp : float
Phase crossover frequency (corresponding to gain margin) (in rad/sec)

Margins are of SISO open-loop. If more than one crossover frequency is
detected, returns the lowest corresponding margin.
Margins are of SISO open-loop. If more than one crossover frequency is
detected, returns the lowest corresponding margin.

Examples
--------
Expand Down
4 changes: 3 additions & 1 deletion control/matlab/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
__all__ = ['bode', 'ngrid', 'dcgain']

def bode(*args, **keywords):
"""Bode plot of the frequency response
"""bode(syslist[, omega, dB, Hz, deg, ...])

Bode plot of the frequency response

Plots a bode gain and phase diagram

Expand Down
11 changes: 5 additions & 6 deletions control/robust.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ def h2syn(P,nmeas,ncon):
>>> K = h2syn(P,nmeas,ncon)

"""

#Check for ss system object, need a utility for this?

#TODO: Check for continous or discrete, only continuous supported right now
Expand Down Expand Up @@ -116,11 +115,11 @@ def hinfsyn(P,nmeas,ncon):
CL: closed loop system (State-space sys)
gam: infinity norm of closed loop system
rcond: 4-vector, reciprocal condition estimates of:
1: control transformation matrix
2: measurement transformation matrix
3: X-Ricatti equation
4: Y-Ricatti equation
TODO: document significance of rcond
1: control transformation matrix
2: measurement transformation matrix
3: X-Ricatti equation
4: Y-Ricatti equation
TODO: document significance of rcond

Raises
------
Expand Down
4 changes: 3 additions & 1 deletion control/statefbk.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ def acker(A, B, poles):
return K

def lqr(*args, **keywords):
"""Linear quadratic regulator design
"""lqr(A, B, Q, R[, N])

Linear quadratic regulator design

The lqr() function computes the optimal state feedback controller
that minimizes the quadratic cost
Expand Down
35 changes: 22 additions & 13 deletions control/statesp.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@
$Id$
"""

import math
import numpy as np
from numpy import all, angle, any, array, asarray, concatenate, cos, delete, \
dot, empty, exp, eye, matrix, ones, pi, poly, poly1d, roots, shape, sin, \
dot, empty, exp, eye, matrix, ones, poly, poly1d, roots, shape, sin, \
zeros, squeeze
from numpy.random import rand, randn
from numpy.linalg import solve, eigvals, matrix_rank
Expand All @@ -69,7 +70,9 @@
__all__ = ['StateSpace', 'ss', 'rss', 'drss', 'tf2ss', 'ssdata']

class StateSpace(LTI):
"""A class for representing state-space models
"""StateSpace(A, B, C, D[, dt])

A class for representing state-space models

The StateSpace class is used to represent state-space realizations of linear
time-invariant (LTI) systems:
Expand All @@ -89,15 +92,19 @@ class StateSpace(LTI):
means the system timebase is not specified. If 'dt' is set to True, the
system will be treated as a discrete time system with unspecified
sampling time.

"""

def __init__(self, *args):
"""Construct a state space object.
"""
StateSpace(A, B, C, D[, dt])

Construct a state space object.

The default constructor is StateSpace(A, B, C, D), where A, B, C, D are
matrices or equivalent objects. To call the copy constructor, call
StateSpace(sys), where sys is a StateSpace object.
The default constructor is StateSpace(A, B, C, D), where A, B, C, D
are matrices or equivalent objects. To create a discrete time system,
use StateSpace(A, B, C, D, dt) where 'dt' is the sampling time (or
True for unspecified sampling time). To call the copy constructor,
call StateSpace(sys), where sys is a StateSpace object.

"""

Expand All @@ -111,8 +118,7 @@ def __init__(self, *args):
elif len(args) == 1:
# Use the copy constructor.
if not isinstance(args[0], StateSpace):
raise TypeError("The one-argument constructor can only take in \
a StateSpace object. Recived %s." % type(args[0]))
raise TypeError("The one-argument constructor can only take in a StateSpace object. Received %s." % type(args[0]))
A = args[0].A
B = args[0].B
C = args[0].C
Expand Down Expand Up @@ -363,7 +369,7 @@ def evalfr(self, omega):
if isdtime(self, strict=True):
dt = timebase(self)
s = exp(1.j * omega * dt)
if (omega * dt > pi):
if (omega * dt > math.pi):
warnings.warn("evalfr: frequency evaluation above Nyquist frequency")
else:
s = omega * 1.j
Expand Down Expand Up @@ -793,7 +799,7 @@ def _rss_generate(states, inputs, outputs, type):
poles[i] = complex(-exp(randn()), 3. * exp(randn()))
elif type == 'd':
mag = rand()
phase = 2. * pi * rand()
phase = 2. * math.pi * rand()
poles[i] = complex(mag * cos(phase),
mag * sin(phase))
poles[i+1] = complex(poles[i].real, -poles[i].imag)
Expand Down Expand Up @@ -956,7 +962,8 @@ def _mimo2simo(sys, input, warn_conversion=False):
return sys

def ss(*args):
"""
"""ss(A, B, C, D[, dt])

Create a state space system.

The function accepts either 1, 4 or 5 parameters:
Expand Down Expand Up @@ -1014,6 +1021,7 @@ def ss(*args):

See Also
--------
StateSpace
tf
ss2tf
tf2ss
Expand Down Expand Up @@ -1045,7 +1053,8 @@ def ss(*args):
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))

def tf2ss(*args):
"""
"""tf2ss(sys)

Transform a transfer function to a state space system.

The function accepts either 1 or 2 parameters:
Expand Down
Loading