From 0a7cd533fbc5712acac2c10fa22f97be755b3d17 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sun, 11 Apr 2021 18:39:46 +0200 Subject: [PATCH 1/3] discrete time LaTeX repr of StateSpace systems --- control/statesp.py | 30 +++++++++++++++++++++--------- control/tests/statesp_test.py | 21 ++++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/control/statesp.py b/control/statesp.py index c12583111..b7d4bca7a 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -418,8 +418,8 @@ def _latex_partitioned_stateless(self): """ lines = [ r'\[', - r'\left(', - (r'\begin{array}' + (r'\left(' + + r'\begin{array}' + r'{' + 'rll' * self.ninputs + '}') ] @@ -429,7 +429,8 @@ def _latex_partitioned_stateless(self): lines.extend([ r'\end{array}' - r'\right)', + r'\right)' + + self._latex_dt(), r'\]']) return '\n'.join(lines) @@ -449,8 +450,8 @@ def _latex_partitioned(self): lines = [ r'\[', - r'\left(', - (r'\begin{array}' + (r'\left(' + + r'\begin{array}' + r'{' + 'rll' * self.nstates + '|' + 'rll' * self.ninputs + '}') ] @@ -466,7 +467,8 @@ def _latex_partitioned(self): lines.extend([ r'\end{array}' - r'\right)', + + r'\right)' + + self._latex_dt(), r'\]']) return '\n'.join(lines) @@ -509,11 +511,21 @@ def fmt_matrix(matrix, name): lines.extend(fmt_matrix(self.D, 'D')) lines.extend([ - r'\end{array}', + r'\end{array}' + + self._latex_dt(), r'\]']) return '\n'.join(lines) + def _latex_dt(self): + if self.isdtime(strict=True): + if self.dt is True: + return r"~,~dt~\mathrm{unspecified}" + else: + fmt = config.defaults['statesp.latex_num_format'] + return f"~,~dt={self.dt:{fmt}}" + return "" + def _repr_latex_(self): """LaTeX representation of state-space model @@ -534,9 +546,9 @@ def _repr_latex_(self): elif config.defaults['statesp.latex_repr_type'] == 'separate': return self._latex_separate() else: - cfg = config.defaults['statesp.latex_repr_type'] raise ValueError( - "Unknown statesp.latex_repr_type '{cfg}'".format(cfg=cfg)) + "Unknown statesp.latex_repr_type '{cfg}'".format( + cfg=config.defaults['statesp.latex_repr_type'])) # Negation of a system def __neg__(self): diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 71e7cc4bc..a63013113 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -997,9 +997,9 @@ def test_statespace_defaults(self, matarrayout): [[1.2345, -2e-200], [-1, 0]]) LTX_G1_REF = { - '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\\]', + '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\\]', - '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\\]', + '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\\]', '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\\]', @@ -1007,9 +1007,9 @@ def test_statespace_defaults(self, matarrayout): } LTX_G2_REF = { - '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\\]', + '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\\]', - '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\\]', + '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\\]', '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\\]', @@ -1022,9 +1022,14 @@ def test_statespace_defaults(self, matarrayout): @pytest.mark.parametrize(" gmats, ref", [(LTX_G1, LTX_G1_REF), (LTX_G2, LTX_G2_REF)]) +@pytest.mark.parametrize("dt, dtref", + [(0, ""), + (None, ""), + (True, r"~,~dt~\mathrm{{unspecified}}"), + (0.1, r"~,~dt={dt:{fmt}}")]) @pytest.mark.parametrize("repr_type", [None, "partitioned", "separate"]) @pytest.mark.parametrize("num_format", [None, ".3g", ".5g"]) -def test_latex_repr(gmats, ref, repr_type, num_format, editsdefaults): +def test_latex_repr(gmats, ref, dt, dtref, repr_type, num_format, editsdefaults): """Test `._latex_repr_` with different config values 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): if repr_type is not None: set_defaults('statesp', latex_repr_type=repr_type) - g = StateSpace(*gmats) + g = StateSpace(*(gmats+(dt,))) refkey = "{}_{}".format(refkey_n[num_format], refkey_r[repr_type]) - assert g._repr_latex_() == ref[refkey] + dt_latex = dtref.format(dt=dt, fmt=defaults['statesp.latex_num_format']) + ref_latex = ref[refkey][:-3] + dt_latex + ref[refkey][-3:] + assert g._repr_latex_() == ref_latex @pytest.mark.parametrize( From 89c22c160a6db38ec971d538c4413f72838e0514 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sun, 11 Apr 2021 18:51:29 +0200 Subject: [PATCH 2/3] use isdtime in StateSpace.__str__() --- control/statesp.py | 10 +++++----- control/tests/statesp_test.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/control/statesp.py b/control/statesp.py index b7d4bca7a..82039975d 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -391,11 +391,11 @@ def __str__(self): "\n ".join(str(M).splitlines())) for Mvar, M in zip(["A", "B", "C", "D"], [self.A, self.B, self.C, self.D])]) - # TODO: replace with standard calls to lti functions - if (type(self.dt) == bool and self.dt is True): - string += "\ndt unspecified\n" - elif (not (self.dt is None) and type(self.dt) != bool and self.dt > 0): - string += "\ndt = " + self.dt.__str__() + "\n" + if self.isdtime(strict=True): + if self.dt is True: + string += "\ndt unspecified\n" + else: + string += f"\ndt = {self.dt}\n" return string # represent to implement a re-loadable version diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index a63013113..94c82280d 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -745,7 +745,7 @@ def test_str(self, sys322): tsysdtunspec = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, True) assert str(tsysdtunspec) == tref + "\ndt unspecified\n" sysdt1 = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, 1.) - assert str(sysdt1) == tref + "\ndt = 1.0\n" + assert str(sysdt1) == tref + "\ndt = {}\n".format(1.) def test_pole_static(self): """Regression: pole() of static gain is empty array.""" From 460859368661c0903fcf41040df8bd446e9cac2f Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sun, 11 Apr 2021 19:56:12 +0200 Subject: [PATCH 3/3] print dt=True instead of unspecified --- control/statesp.py | 7 ++----- control/tests/statesp_test.py | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/control/statesp.py b/control/statesp.py index 82039975d..bfa55b357 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -392,10 +392,7 @@ def __str__(self): for Mvar, M in zip(["A", "B", "C", "D"], [self.A, self.B, self.C, self.D])]) if self.isdtime(strict=True): - if self.dt is True: - string += "\ndt unspecified\n" - else: - string += f"\ndt = {self.dt}\n" + string += f"\ndt = {self.dt}\n" return string # represent to implement a re-loadable version @@ -520,7 +517,7 @@ def fmt_matrix(matrix, name): def _latex_dt(self): if self.isdtime(strict=True): if self.dt is True: - return r"~,~dt~\mathrm{unspecified}" + return r"~,~dt=~\mathrm{True}" else: fmt = config.defaults['statesp.latex_num_format'] return f"~,~dt={self.dt:{fmt}}" diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 94c82280d..ab62bc1b6 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -743,7 +743,7 @@ def test_str(self, sys322): " [ 0. 1.]]\n") assert str(tsys) == tref tsysdtunspec = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, True) - assert str(tsysdtunspec) == tref + "\ndt unspecified\n" + assert str(tsysdtunspec) == tref + "\ndt = True\n" sysdt1 = StateSpace(tsys.A, tsys.B, tsys.C, tsys.D, 1.) assert str(sysdt1) == tref + "\ndt = {}\n".format(1.) @@ -1025,7 +1025,7 @@ def test_statespace_defaults(self, matarrayout): @pytest.mark.parametrize("dt, dtref", [(0, ""), (None, ""), - (True, r"~,~dt~\mathrm{{unspecified}}"), + (True, r"~,~dt=~\mathrm{{True}}"), (0.1, r"~,~dt={dt:{fmt}}")]) @pytest.mark.parametrize("repr_type", [None, "partitioned", "separate"]) @pytest.mark.parametrize("num_format", [None, ".3g", ".5g"]) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy