Skip to content

Commit 76ec68f

Browse files
committed
Added the clean() and fival() functions as functions to the TransferFunction and StateSpace classes
While the functions clean_ss and clean_tf remain as separate functions in the respective files, the function clean() has been added in the respective form to the TransferFunction ans StateSpace classes. This makes it possible to still go directly from a StateSpace to a clean TransferFunction (or vice versa) but makes it easier to clean either one of the two if it is already in the desired form. The fival function remains as a function in the timeresp.py file, but by importing it to the other two files and including it in the aforementioned classes it is now possible to, for instance, use sys.fival(**) where sys is a StateSpace or TransferFunction.
1 parent fa100df commit 76ec68f

3 files changed

Lines changed: 155 additions & 9 deletions

File tree

control/statesp.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from warnings import warn
6464
from .lti import LTI, timebase, timebaseEqual, isdtime
6565
from .xferfcn import TransferFunction
66+
from .timeresp import fival
6667
from . import config
6768
from copy import deepcopy
6869

@@ -931,6 +932,64 @@ def dcgain(self):
931932
gain = np.tile(np.nan, (self.outputs, self.inputs))
932933
return np.squeeze(gain)
933934

935+
def clean(self, precision=10):
936+
"""
937+
Rounds the A, B, C and D matrices of a StateSpace system, removing
938+
small non-zero numbers that are, for instance, a result of computational
939+
errors and that can otherwise lead to problems in future computations
940+
and analyses
941+
942+
Parameters
943+
----------
944+
sys : LTI (StateSpace)
945+
LTI system whose data will be returned
946+
precision : integer
947+
Number of decimals to be left unchanged in rounding
948+
949+
Returns
950+
-------
951+
out : StateSpace
952+
LTI StateSpace rounded to the desired precision
953+
"""
954+
return ss(np.round(self.A, precision), np.round(self.B, precision), np.round(self.C, precision),
955+
np.round(self.D, precision))
956+
957+
def fival(self, forcing="step", input=1, output=1, stabilityCheck=False, precision=10):
958+
"""
959+
Returns the final value of the StateSpace system. It is based on
960+
the mathematical final value theorem and is thus faster and avoids
961+
unnecessarily large time vectors. For MIMO systems one can prescribe
962+
which input and output are desired.
963+
964+
Parameters
965+
----------
966+
sys : LTI (StateSpace, or TransferFunction)
967+
LTI system whose data will be returned
968+
forcing: A SISO TransferFunction
969+
Laplace transform of the forcingunction describing the input
970+
input : integer
971+
Refers to the requested input (starting from 1), 1 by default
972+
output : integer
973+
Refers to the requested output (starting from 1), 1 by default
974+
stabilityCheck : bool
975+
If True it is checked if the system is stable. The final value theorem gives
976+
erroneous results for unstable systems
977+
precision : integer
978+
Number of decimals to be left unchanged in rounding
979+
980+
Returns
981+
-------
982+
out : float or inf
983+
The final value of the system. inf has the correct sign
984+
985+
Raises
986+
------
987+
TypeError
988+
if forcing is not a TransferFunction object
989+
"""
990+
return fival(self, forcing = forcing, input = input, output = output,\
991+
stabilityCheck = stabilityCheck, precision = precision)
992+
934993

935994
# TODO: add discrete time check
936995
def _convertToStateSpace(sys, **kw):
@@ -1508,8 +1567,10 @@ def ssdata(sys):
15081567

15091568
def clean_ss(sys, precision=10):
15101569
"""
1511-
Rounds the A, B, C and D matrices of a StateSpace function, removing small non-zero numbers that are, for instance,
1512-
a result of computational errors and that can otherwise lead to problems in future computations and analyses
1570+
Rounds the A, B, C and D matrices of a StateSpace system, removing small
1571+
non-zero numbers that are, for instance, a result of computational errors
1572+
and that can otherwise lead to problems in future computations and analyses.
1573+
If sys is a TransferFunction it is first converted to a StateSpace
15131574
15141575
Parameters
15151576
----------
@@ -1531,6 +1592,7 @@ def clean_ss(sys, precision=10):
15311592

15321593
if (type(sys) is not TransferFunction) and (type(sys) is not StateSpace):
15331594
raise TypeError("Neither a StateSpace nor TransferFunction was passed to 'sys'")
1534-
sys = ss(sys)
1595+
if (type(sys) is not StateSpace):
1596+
sys = ss(sys)
15351597
return ss(np.round(sys.A, precision), np.round(sys.B, precision), np.round(sys.C, precision),
15361598
np.round(sys.D, precision))

control/timeresp.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -888,9 +888,10 @@ def _default_time_vector(sys, N=None, tfinal=None):
888888

889889
def fival(sys, forcing="step", input=1, output=1, stabilityCheck=False, precision=10):
890890
"""
891-
Returns the final value of a state space or transfer function. It is based on the mathematical final value theorem
892-
and is thus faster and avoids unnecessarily large time vectors. For MIMO systems one can prescribe which input and
893-
output are desired.
891+
Returns the final value of a state space or transfer function.
892+
It is based on the mathematical final value theorem and is thus
893+
faster and avoids unnecessarily large time vectors. For MIMO
894+
systems one can prescribe which input and output are desired.
894895
895896
Parameters
896897
----------

control/xferfcn.py

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
from re import sub
6565
from .lti import LTI, timebaseEqual, timebase, isdtime
6666
from .statesp import StateSpace
67+
from .timeresp import fival
6768
from . import config
6869

6970
__all__ = ['TransferFunction', 'tf', 'ss2tf', 'tfdata']
@@ -1092,6 +1093,86 @@ def _dcgain_cont(self):
10921093
gain[i][j] = np.nan
10931094
return np.squeeze(gain)
10941095

1096+
def clean(self, input=None, output=None, precision=10):
1097+
"""
1098+
Rounds the elements of the transfer function. This removes
1099+
small non-zero numbers that, for instance, are a result of
1100+
computational errors and can otherwise lead to problems. The
1101+
function also removes cancelling poles and zeros, similar to
1102+
the control.minreal() function
1103+
1104+
Parameters
1105+
----------
1106+
sys : LTI (StateSpace, or TransferFunction)
1107+
LTI system whose data will be returned
1108+
input : None
1109+
optionally an integer referring to the requested input (starting from 1)
1110+
output : None
1111+
optionally an integer referring to the requested output (starting from 1)
1112+
precision : integer
1113+
Number of decimals to be left unchanged in rounding
1114+
1115+
Returns
1116+
-------
1117+
out : TransferFunctino
1118+
LTI TransferFunction rounded to the desired precision
1119+
"""
1120+
sys = self.minreal()
1121+
if input is not None and output is not None:
1122+
sys = sys[output - 1, input - 1]
1123+
elif output is not None:
1124+
sys = sys[output - 1, :]
1125+
elif input is not None:
1126+
sys = sys[:, input - 1]
1127+
num = np.round(sys.num, precision)
1128+
den = np.round(sys.den, precision)
1129+
for i in range(sys.outputs):
1130+
for j in range(sys.inputs):
1131+
test = True
1132+
while test:
1133+
if num[i][j][-1] == den[i][j][-1] == 0:
1134+
num[i][j] = np.insert(num[i][j][:-1], 0, 0)
1135+
den[i][j] = np.insert(den[i][j][:-1], 0, 0)
1136+
else:
1137+
test = False
1138+
return tf(num, den)
1139+
1140+
def fival(self, forcing="step", input=1, output=1, stabilityCheck=False, precision=10):
1141+
"""
1142+
Returns the final value of the TransferFunction. It is
1143+
based on the mathematical final value theorem and is thus
1144+
faster and avoids unnecessarily large time vectors. For MIMO
1145+
systems one can prescribe which input and output are desired.
1146+
1147+
Parameters
1148+
----------
1149+
sys : LTI (StateSpace, or TransferFunction)
1150+
LTI system whose data will be returned
1151+
forcing: A SISO TransferFunction
1152+
Laplace transform of the forcingunction describing the input
1153+
input : integer
1154+
Refers to the requested input (starting from 1), 1 by default
1155+
output : integer
1156+
Refers to the requested output (starting from 1), 1 by default
1157+
stabilityCheck : bool
1158+
If True it is checked if the system is stable. The final value theorem gives
1159+
erroneous results for unstable systems
1160+
precision : integer
1161+
Number of decimals to be left unchanged in rounding
1162+
1163+
Returns
1164+
-------
1165+
out : float or inf
1166+
The final value of the system. inf has the correct sign
1167+
1168+
Raises
1169+
------
1170+
TypeError
1171+
if forcing is not a TransferFunction object
1172+
"""
1173+
return fival(self, forcing = forcing, input = input, output = output,\
1174+
stabilityCheck = stabilityCheck, precision = precision)
1175+
10951176

10961177
# c2d function contributed by Benjamin White, Oct 2012
10971178
def _c2d_matched(sysC, Ts):
@@ -1568,9 +1649,11 @@ def _clean_part(data):
15681649

15691650
def clean_tf(sys, input=None, output=None, precision=10):
15701651
"""
1571-
Rounds the elements of the desired transfer function. This removes small non-zero numbers that, for instance, are
1572-
a result of computational errors and can otherwise lead to problems. The function also removes cancelling poles
1573-
and zeros, similar to the control.minreal() function
1652+
Rounds the elements of the desired transfer function (which
1653+
is created if sys is a StateSpace). This removes small non-zero
1654+
numbers that, for instance, are a result of computational errors
1655+
and can otherwise lead to problems. The function also removes
1656+
cancelling poles and zeros, similar to the control.minreal() function
15741657
15751658
Parameters
15761659
----------

0 commit comments

Comments
 (0)