Skip to content

Commit

Permalink
Merge c268c7c into a4b4c43
Browse files Browse the repository at this point in the history
  • Loading branch information
bnavigator committed Nov 18, 2019
2 parents a4b4c43 + c268c7c commit 5d7395e
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 15 deletions.
2 changes: 1 addition & 1 deletion control/bdalg.py
Expand Up @@ -62,7 +62,7 @@


def series(sys1, *sysn):
"""Return the series connection (... \* sys3 \*) sys2 \* sys1
"""Return the series connection (... \\* sys3 \\*) sys2 \\* sys1
Parameters
----------
Expand Down
6 changes: 3 additions & 3 deletions control/freqplot.py
Expand Up @@ -110,7 +110,7 @@ def bode_plot(syslist, omega=None,
config.defaults['freqplot.number_of_samples'].
margins : bool
If True, plot gain and phase margin.
\*args, \**kwargs:
\\*args, \\*\\*kwargs:
Additional options to matplotlib (color, linestyle, etc)
Returns
Expand Down Expand Up @@ -139,7 +139,7 @@ def bode_plot(syslist, omega=None,
2. If a discrete time model is given, the frequency response is plotted
along the upper branch of the unit circle, using the mapping z = exp(j
\omega dt) where omega ranges from 0 to pi/dt and dt is the discrete
\\omega dt) where omega ranges from 0 to pi/dt and dt is the discrete
timebase. If not timebase is specified (dt = True), dt is set to 1.
Examples
Expand Down Expand Up @@ -450,7 +450,7 @@ def nyquist_plot(syslist, omega=None, Plot=True, color=None,
Used to specify the color of the plot
labelFreq : int
Label every nth frequency on the plot
\*args, \**kwargs:
\\*args, \\*\\*kwargs:
Additional options to matplotlib (color, linestyle, etc)
Returns
Expand Down
2 changes: 1 addition & 1 deletion control/grid.py
Expand Up @@ -175,7 +175,7 @@ def zgrid(zetas=None, wns=None):
an_x = xret[an_i]
an_y = yret[an_i]
num = '{:1.1f}'.format(a)
ax.annotate("$\\frac{"+num+"\pi}{T}$", xy=(an_x, an_y), xytext=(an_x, an_y), size=9)
ax.annotate(r"$\frac{"+num+r"\pi}{T}$", xy=(an_x, an_y), xytext=(an_x, an_y), size=9)

_final_setup(ax)
return ax, fig
Expand Down
2 changes: 1 addition & 1 deletion control/iosys.py
Expand Up @@ -1244,7 +1244,7 @@ def _parse_signal(self, spec, signame='input', dictname=None):

if isinstance(spec, str):
# If we got a dotted string, break up into pieces
namelist = re.split('\.', spec)
namelist = re.split(r'\.', spec)

# For now, only allow signal level of system name
# TODO: expand to allow nested signal names
Expand Down
4 changes: 2 additions & 2 deletions control/matlab/wrappers.py
Expand Up @@ -130,7 +130,7 @@ def dcgain(*args):
-------
gain: ndarray
The gain of each output versus each input:
:math:`y = gain \cdot u`
:math:`y = gain \\cdot u`
Notes
-----
Expand All @@ -140,7 +140,7 @@ def dcgain(*args):
All systems are first converted to state space form. The function then
computes:
.. math:: gain = - C \cdot A^{-1} \cdot B + D
.. math:: gain = - C \\cdot A^{-1} \\cdot B + D
'''
#Convert the parameters to state space form
if len(args) == 4:
Expand Down
2 changes: 1 addition & 1 deletion control/statefbk.py
Expand Up @@ -270,7 +270,7 @@ def lqr(*args, **keywords):
The lqr() function computes the optimal state feedback controller
that minimizes the quadratic cost
.. math:: J = \int_0^\infty (x' Q x + u' R u + 2 x' N u) dt
.. math:: J = \\int_0^\\infty (x' Q x + u' R u + 2 x' N u) dt
The function can be called with either 3, 4, or 5 arguments:
Expand Down
32 changes: 27 additions & 5 deletions control/tests/xferfcn_test.py
Expand Up @@ -449,7 +449,7 @@ def test_evalfr_mimo(self):
np.testing.assert_array_almost_equal(sys(2.j), resp)

def test_freqresp_siso(self):
"""Evaluate the magnitude and phase of a SISO system at
"""Evaluate the magnitude and phase of a SISO system at
multiple frequencies."""

sys = TransferFunction([1., 3., 5], [1., 6., 2., -1])
Expand All @@ -467,7 +467,7 @@ def test_freqresp_siso(self):

@unittest.skipIf(not slycot_check(), "slycot not installed")
def test_freqresp_mimo(self):
"""Evaluate the magnitude and phase of a MIMO system at
"""Evaluate the magnitude and phase of a MIMO system at
multiple frequencies."""

num = [[[1., 2.], [0., 3.], [2., -1.]],
Expand Down Expand Up @@ -496,7 +496,7 @@ def test_freqresp_mimo(self):
np.testing.assert_array_equal(omega, true_omega)

# Tests for TransferFunction.pole and TransferFunction.zero.

@unittest.skipIf(not slycot_check(), "slycot not installed")
def test_pole_mimo(self):
"""Test for correct MIMO poles."""
Expand All @@ -510,11 +510,11 @@ def test_pole_mimo(self):

@unittest.skipIf(not slycot_check(), "slycot not installed")
def test_double_cancelling_poles_siso(self):

H = TransferFunction([1, 1], [1, 2, 1])
p = H.pole()
np.testing.assert_array_almost_equal(p, [-1, -1])

# Tests for TransferFunction.feedback
def test_feedback_siso(self):
"""Test for correct SISO transfer function feedback."""
Expand Down Expand Up @@ -756,6 +756,28 @@ def test_size_mismatch(self):
self.assertRaises(NotImplementedError,
TransferFunction.feedback, sys2, sys1)

def test_latex_repr(self):
""" Test latex printout for TransferFunction """
Hc = TransferFunction([1e-5, 2e5, 3e-4],
[1.2e34, 2.3e-4, 2.3e-45])
Hd = TransferFunction([1e-5, 2e5, 3e-4],
[1.2e34, 2.3e-4, 2.3e-45],
.1)
# TODO: make the multiplication sign configurable
expmul = r'\times'
for var, H, suffix in zip(['s', 'z'],
[Hc, Hd],
['', r'\quad dt = 0.1']):
ref = (r'$$\frac{'
r'1 ' + expmul + ' 10^{-5} ' + var + '^2 '
r'+ 2 ' + expmul + ' 10^{5} ' + var + ' + 0.0003'
r'}{'
r'1.2 ' + expmul + ' 10^{34} ' + var + '^2 '
r'+ 0.00023 ' + var + ' '
r'+ 2.3 ' + expmul + ' 10^{-45}'
r'}' + suffix + '$$')
self.assertEqual(H._repr_latex_(), ref)


def suite():
return unittest.TestLoader().loadTestsFromTestCase(TestXferFcn)
Expand Down
18 changes: 17 additions & 1 deletion control/xferfcn.py
Expand Up @@ -62,6 +62,7 @@
from copy import deepcopy
from warnings import warn
from itertools import chain
from re import sub
from .lti import LTI, timebaseEqual, timebase, isdtime

__all__ = ['TransferFunction', 'tf', 'ss2tf', 'tfdata']
Expand Down Expand Up @@ -302,6 +303,9 @@ def _repr_latex_(self, var=None):
numstr = _tf_polynomial_to_string(self.num[i][j], var=var)
denstr = _tf_polynomial_to_string(self.den[i][j], var=var)

numstr = _tf_string_to_latex(numstr, var=var)
denstr = _tf_string_to_latex(denstr, var=var)

out += [r"\frac{", numstr, "}{", denstr, "}"]

if mimo and j < self.outputs - 1:
Expand All @@ -315,7 +319,7 @@ def _repr_latex_(self, var=None):

# See if this is a discrete time system with specific sampling time
if not (self.dt is None) and type(self.dt) != bool and self.dt > 0:
out += ["\quad dt = ", str(self.dt)]
out += [r"\quad dt = ", str(self.dt)]

out.append("$$")

Expand Down Expand Up @@ -1098,6 +1102,18 @@ def _tf_polynomial_to_string(coeffs, var='s'):
return thestr


def _tf_string_to_latex(thestr, var='s'):
""" make sure to superscript all digits in a polynomial string
and convert float coefficients in scientific notation
to prettier LaTeX representation """
# TODO: make the multiplication sign configurable
expmul = r' \\times'
thestr = sub(var + r'\^(\d{2,})', var + r'^{\1}', thestr)
thestr = sub(r'[eE]\+0*(\d+)', expmul + r' 10^{\1}', thestr)
thestr = sub(r'[eE]\-0*(\d+)', expmul + r' 10^{-\1}', thestr)
return thestr


def _add_siso(num1, den1, num2, den2):
"""Return num/den = num1/den1 + num2/den2.
Expand Down

0 comments on commit 5d7395e

Please sign in to comment.