Skip to content

Commit 7bed77f

Browse files
repaghmurrayrm
authored andcommitted
TransferFunction _common_den rewrite - issue #194 (#206)
* replaced the _common_den function internals. Passes tests * make xferfcn.py python2 compatible again * working tf -> ss transformation now, also solved #111 * disabled MIMO test when no slycot * do not cancel pole/zero pairs before calculating pole() in xferfcn.py - for the above reason, do conversion on minreal'd xferfcn in statesp.py - add a test for not canceling pole/zero pairs when calculating pole() - add import of matlab in discrete_test.py * change testModred; that one did state removal on a system of which the selection of states was automatic
1 parent f66d842 commit 7bed77f

File tree

6 files changed

+152
-167
lines changed

6 files changed

+152
-167
lines changed

control/statesp.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,6 @@ def _convertToStateSpace(sys, **kw):
757757
[1., 1., 1.]].
758758
759759
"""
760-
761760
from .xferfcn import TransferFunction
762761
import itertools
763762
if isinstance(sys, StateSpace):
@@ -771,20 +770,17 @@ def _convertToStateSpace(sys, **kw):
771770
try:
772771
from slycot import td04ad
773772
if len(kw):
774-
raise TypeError("If sys is a TransferFunction, _convertToStateSpace \
775-
cannot take keywords.")
773+
raise TypeError("If sys is a TransferFunction, "
774+
"_convertToStateSpace cannot take keywords.")
776775

777776
# Change the numerator and denominator arrays so that the transfer
778777
# function matrix has a common denominator.
779-
num, den = sys._common_den()
780-
# Make a list of the orders of the denominator polynomials.
781-
index = [len(den) - 1 for i in range(sys.outputs)]
782-
# Repeat the common denominator along the rows.
783-
den = array([den for i in range(sys.outputs)])
784-
#! TODO: transfer function to state space conversion is still buggy!
785-
#print num
786-
#print shape(num)
787-
ssout = td04ad('R',sys.inputs, sys.outputs, index, den, num,tol=0.0)
778+
# matrices are also sized/padded to fit td04ad
779+
num, den, denorder = sys.minreal()._common_den()
780+
781+
# transfer function to state space conversion now should work!
782+
ssout = td04ad('C', sys.inputs, sys.outputs,
783+
denorder, den, num, tol=0)
788784

789785
states = ssout[0]
790786
return StateSpace(ssout[1][:states, :states],

control/tests/convert_test.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def setUp(self):
4040
# Set to True to print systems to the output.
4141
self.debug = False
4242
# get consistent results
43-
np.random.seed(9)
43+
np.random.seed(7)
4444

4545
def printSys(self, sys, ind):
4646
"""Print system to the standard output."""
@@ -141,10 +141,9 @@ def testConvert(self):
141141
ssxfrm_real = ssxfrm_mag * np.cos(ssxfrm_phase)
142142
ssxfrm_imag = ssxfrm_mag * np.sin(ssxfrm_phase)
143143
np.testing.assert_array_almost_equal( \
144-
ssorig_real, ssxfrm_real)
144+
ssorig_real, ssxfrm_real)
145145
np.testing.assert_array_almost_equal( \
146-
ssorig_imag, ssxfrm_imag)
147-
146+
ssorig_imag, ssxfrm_imag)
148147
#
149148
# Make sure xform'd TF has same frequency response
150149
#
@@ -198,8 +197,9 @@ def testTf2ssStaticMimo(self):
198197
"""Regression: tf2ss for MIMO static gain"""
199198
import control
200199
# 2x3 TFM
201-
gmimo = control.tf2ss(control.tf([[ [23], [3], [5] ], [ [-1], [0.125], [101.3] ]],
202-
[[ [46], [0.1], [80] ], [ [2], [-0.1], [1] ]]))
200+
gmimo = control.tf2ss(control.tf(
201+
[[ [23], [3], [5] ], [ [-1], [0.125], [101.3] ]],
202+
[[ [46], [0.1], [80] ], [ [2], [-0.1], [1] ]]))
203203
self.assertEqual(0, gmimo.states)
204204
self.assertEqual(3, gmimo.inputs)
205205
self.assertEqual(2, gmimo.outputs)
@@ -229,6 +229,21 @@ def testSs2tfStaticMimo(self):
229229
numref = np.asarray(d)[...,np.newaxis]
230230
np.testing.assert_array_equal(numref, np.array(gtf.num) / np.array(gtf.den))
231231

232+
def testTf2SsDuplicatePoles(self):
233+
"""Tests for "too few poles for MIMO tf #111" """
234+
import control
235+
try:
236+
import slycot
237+
num = [ [ [1], [0] ],
238+
[ [0], [1] ] ]
239+
240+
den = [ [ [1,0], [1] ],
241+
[ [1], [1,0] ] ]
242+
g = control.tf(num, den)
243+
s = control.ss(g)
244+
np.testing.assert_array_equal(g.pole(), s.pole())
245+
except ImportError:
246+
print("Slycot not present, skipping")
232247

233248
def suite():
234249
return unittest.TestLoader().loadTestsFromTestCase(TestConvert)

control/tests/discrete_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import unittest
77
import numpy as np
88
from control import *
9+
from control import matlab
910

1011
class TestDiscrete(unittest.TestCase):
1112
"""Tests for the DiscreteStateSpace class."""

control/tests/matlab_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,9 @@ def testBalred(self):
396396
@unittest.skipIf(not slycot_check(), "slycot not installed")
397397
def testModred(self):
398398
modred(self.siso_ss1, [1])
399-
modred(self.siso_ss2 * self.siso_ss3, [0, 1])
400-
modred(self.siso_ss3, [1], 'matchdc')
401-
modred(self.siso_ss3, [1], 'truncate')
399+
modred(self.siso_ss2 * self.siso_ss1, [0, 1])
400+
modred(self.siso_ss1, [1], 'matchdc')
401+
modred(self.siso_ss1, [1], 'truncate')
402402

403403
@unittest.skipIf(not slycot_check(), "slycot not installed")
404404
def testPlace_varga(self):

control/tests/xferfcn_test.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,10 +425,16 @@ def testPoleMIMO(self):
425425
[[[1., 2.], [1., 3.]], [[1., 4., 4.], [1., 9., 14.]]])
426426
p = sys.pole()
427427

428-
np.testing.assert_array_almost_equal(p, [-7., -3., -2., -2.])
429-
430-
# Tests for TransferFunction.feedback.
428+
np.testing.assert_array_almost_equal(p, [-2., -2., -7., -3., -2.])
431429

430+
@unittest.skipIf(not slycot_check(), "slycot not installed")
431+
def testDoubleCancelingPoleSiso(self):
432+
433+
H = TransferFunction([1,1],[1,2,1])
434+
p = H.pole()
435+
np.testing.assert_array_almost_equal(p, [-1, -1])
436+
437+
# Tests for TransferFunction.feedback
432438
def testFeedbackSISO(self):
433439
"""Test for correct SISO transfer function feedback."""
434440

0 commit comments

Comments
 (0)