8000 Merge pull request #609 from bnavigator/latex-dt · python-control/python-control@d1f3bca · GitHub
[go: up one dir, main page]

Skip to content

Commit d1f3bca

Browse files
authored
Merge pull request #609 from bnavigator/latex-dt
discrete time LaTeX repr of StateSpace systems
2 parents 15dc5ce + 4608593 commit d1f3bca

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

control/statesp.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -391,11 +391,8 @@ def __str__(self):
391391
"\n ".join(str(M).splitlines()))
392392
for Mvar, M in zip(["A", "B", "C", "D"],
393393
[self.A, self.B, self.C, self.D])])
394-
# TODO: replace with standard calls to lti functions
395-
if (type(self.dt) == bool and self.dt is True):
396-
string += "\ndt unspecified\n"
397-
elif (not (self.dt is None) and type(self.dt) != bool and self.dt > 0):
398-
string += "\ndt = " + self.dt.__str__() + "\n"
394+
if self.isdtime(strict=True):
395+
string += f"\ndt = {self.dt}\n"
399396
return string
400397

401398
# represent to implement a re-loadable version
@@ -418,8 +415,8 @@ def _latex_partitioned_stateless(self):
418415
"""
419416
lines = [
420417
r'\[',
421-
r'\left(',
422-
(r'\begin{array}'
418+
(r'\left('
419+
+ r'\begin{array}'
423420
+ r'{' + 'rll' * self.ninputs + '}')
424421
]
425422

@@ -429,7 +426,8 @@ def _latex_partitioned_stateless(self):
429426

430427
lines.extend([
431428
r'\end{array}'
432-
r'\right)',
429+
r'\right)'
430+
+ self._latex_dt(),
433431
r'\]'])
434432

435433
return '\n'.join(lines)
@@ -449,8 +447,8 @@ def _latex_partitioned(self):
449447

450448
lines = [
451449
r'\[',
452-
r'\left(',
453-
(r'\begin{array}'
450+
(r'\left('
451+
+ r'\begin{array}'
454452
+ r'{' + 'rll' * self.nstates + '|' + 'rll' * self.ninputs + '}')
455453
]
456454

@@ -466,7 +464,8 @@ def _latex_partitioned(self):
466464

467465
lines.extend([
468466
r'\end{array}'
469-
r'\right)',
467+
+ r'\right)'
468+
+ self._latex_dt(),
470469
r'\]'])
471470

472471
return '\n'.join(lines)
@@ -509,11 +508,21 @@ def fmt_matrix(matrix, name):
509508
lines.extend(fmt_matrix(self.D, 'D'))
510509

511510
lines.extend([
512-
r'\end{array}',
511+
r'\end{array}'
512+
+ self._latex_dt(),
513513
r'\]'])
514514

515515
return '\n'.join(lines)
516516

517+
def _latex_dt(self):
518+
if self.isdtime(strict=True):
519+
if self.dt is True:
520+
return r"~,~dt=~\mathrm{True}"
521+
else:
522+
fmt = config.defaults['statesp.latex_num_format']
523+
return f"~,~dt={self.dt:{fmt}}"
524+
return ""
525+
517526
def _repr_latex_(self):
518527
"""LaTeX representation of state-space model
519528
@@ -534,9 +543,9 @@ def _repr_latex_(self):
534543
elif config.defaults['statesp.latex_repr_type'] == 'separate':
535544
return self._latex_separate()
536545
else:
537-
cfg = config.defaults['statesp.latex_repr_type']
538546
raise ValueError(
539-
"Unknown statesp.latex_repr_type '{cfg}'".format(cfg=cfg))
547+
"Unknown statesp.latex_repr_type '{cfg}'".format(
548+
cfg=config.defaults['statesp.latex_repr_type']))
540549

541550
# Negation of a system
542551
def __neg__(self):

control/tests/statesp_test.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,9 @@ def test_str(self, sys322):
743743
" [ 0. 1.]]\n")
744744
assert str(tsys) == tref
745745
tsysdtunspec = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, True)
746-
assert str(tsysdtunspec) == tref + "\ndt unspecified\n"
746+
assert str(tsysdtunspec) == tref + "\ndt = True\n"
747747
sysdt1 = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, 1.)
748-
assert str(sysdt1) == tref + "\ndt = 1.0\n"
748+
assert str(sysdt1) == tref + "\ndt = {}\n".format(1.)
749749

750750
def test_pole_static(self):
751751
"""Regression: pole() of static gain is empty array."""
@@ -997,19 +997,19 @@ def test_statespace_defaults(self, matarrayout):
997997
[[1.2345, -2e-200], [-1, 0]])
998998

999999
LTX_G1_REF = {
1000-
'p3_p' : '\\[\n\\left(\n\\begin{array}{rllrll|rll}\n3.&\\hspace{-1em}14&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n-1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\hline\n9.&\\hspace{-1em}88&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}00123&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
1000+
'p3_p' : '\\[\n\\left(\\begin{array}{rllrll|rll}\n3.&\\hspace{-1em}14&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n-1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\hline\n9.&\\hspace{-1em}88&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}00123&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
10011001

1002-
'p5_p' : '\\[\n\\left(\n\\begin{array}{rllrll|rll}\n3.&\\hspace{-1em}1416&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n-1.&\\hspace{-1em}2346&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\hline\n9.&\\hspace{-1em}8765&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}001234&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
1002+
'p5_p' : '\\[\n\\left(\\begin{array}{rllrll|rll}\n3.&\\hspace{-1em}1416&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n-1.&\\hspace{-1em}2346&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\hline\n9.&\\hspace{-1em}8765&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}001234&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
10031003

10041004
'p3_s' : '\\[\n\\begin{array}{ll}\nA = \\left(\\begin{array}{rllrll}\n3.&\\hspace{-1em}14&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}\\\\\n-1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}\\\\\n\\end{array}\\right)\n&\nB = \\left(\\begin{array}{rll}\n0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\\\\nC = \\left(\\begin{array}{rllrll}\n9.&\\hspace{-1em}88&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}00123&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n&\nD = \\left(\\begin{array}{rll}\n5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\end{array}\n\\]',
10051005

10061006
'p5_s' : '\\[\n\\begin{array}{ll}\nA = \\left(\\begin{array}{rllrll}\n3.&\\hspace{-1em}1416&\\hspace{-1em}\\phantom{\\cdot}&1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{100}\\\\\n-1.&\\hspace{-1em}2346&\\hspace{-1em}\\phantom{\\cdot}&5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-23}\\\\\n\\end{array}\\right)\n&\nB = \\left(\\begin{array}{rll}\n0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\\\\nC = \\left(\\begin{array}{rllrll}\n9.&\\hspace{-1em}8765&\\hspace{-1em}\\cdot10^{8}&0.&\\hspace{-1em}001234&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n&\nD = \\left(\\begin{array}{rll}\n5\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\end{array}\n\\]',
10071007
}
10081008

10091009
LTX_G2_REF = {
1010-
'p3_p' : '\\[\n\\left(\n\\begin{array}{rllrll}\n1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&-2\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-200}\\\\\n-1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
1010+
'p3_p' : '\\[\n\\left(\\begin{array}{rllrll}\n1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&-2\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-200}\\\\\n-1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
10111011

1012-
'p5_p' : '\\[\n\\left(\n\\begin{array}{rllrll}\n1.&\\hspace{-1em}2345&\\hspace{-1em}\\phantom{\\cdot}&-2\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-200}\\\\\n-1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
1012+
'p5_p' : '\\[\n\\left(\\begin{array}{rllrll}\n1.&\\hspace{-1em}2345&\\hspace{-1em}\\phantom{\\cdot}&-2\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-200}\\\\\n-1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\]',
10131013

10141014
'p3_s' : '\\[\n\\begin{array}{ll}\nD = \\left(\\begin{array}{rllrll}\n1.&\\hspace{-1em}23&\\hspace{-1em}\\phantom{\\cdot}&-2\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\cdot10^{-200}\\\\\n-1\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}&0\\phantom{.}&\\hspace{-1em}&\\hspace{-1em}\\phantom{\\cdot}\\\\\n\\end{array}\\right)\n\\end{array}\n\\]',
10151015

@@ -1022,9 +1022,14 @@ def test_statespace_defaults(self, matarrayout):
10221022
@pytest.mark.parametrize(" gmats, ref",
10231023
[(LTX_G1, LTX_G1_REF),
10241024
(LTX_G2, LTX_G2_REF)])
1025+
@pytest.mark.parametrize("dt, dtref",
1026+
[(0, ""),
1027+
(None, ""),
1028+
(True, r"~,~dt=~\mathrm{{True}}"),
1029+
(0.1, r"~,~dt={dt:{fmt}}")])
10251030
@pytest.mark.parametrize("repr_type", [None, "partitioned", "separate"])
10261031
@pytest.mark.parametrize("num_format", [None, ".3g", ".5g"])
1027-
def test_latex_repr(gmats, ref, repr_type, num_format, editsdefaults):
1032+
def test_latex_repr(gmats, ref, dt, dtref, repr_type, num_format, editsdefaults):
10281033
"""Test `._latex_repr_` with different config values
10291034
10301035
This is a 'gold image' test, so if you change behaviour,
@@ -1040,9 +1045,11 @@ def test_latex_repr(gmats, ref, repr_type, num_format, editsdefaults):
10401045
if repr_type is not None:
10411046
set_defaults('statesp', latex_repr_type=repr_type)
10421047

1043-
g = StateSpace(*gmats)
1048+
g = StateSpace(*(gmats+(dt,)))
10441049
refkey = "{}_{}".format(refkey_n[num_format], refkey_r[repr_type])
1045-
assert g._repr_latex_() == ref[refkey]
1050+
dt_latex = dtref.format(dt=dt, fmt=defaults['statesp.latex_num_format'])
1051+
ref_latex = ref[refkey][:-3] + dt_latex + ref[refkey][-3:]
1052+
assert g._repr_latex_() == ref_latex
10461053

10471054

10481055
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)
0