Skip to content

Commit bba73aa

Browse files
committed
addition of minreal for TransferFunction
1 parent ccebddc commit bba73aa

File tree

4 files changed

+85
-22
lines changed

4 files changed

+85
-22
lines changed

scratch/minreal.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,34 @@
44

55
s = TransferFunction([1, 0], [1])
66

7-
h = (s+1)*(s+2)/(s+2)/(s**2+s+1)
7+
h = (s+1)*(s+2)/s/(s+2)/(s**2+s+1)
88
tol = None
99

1010
sqrt_eps = np.sqrt(float_info.epsilon)
1111

12-
for i in range(h.inputs):
13-
for j in range(h.outputs):
14-
newzeros = []
15-
zeros = np.roots(h.num[i][j])
16-
poles = np.roots(h.den[i][j])
17-
# check all zeros
18-
for z in zeros:
19-
t = tol or \
20-
1000 * max(float_info.epsilon, abs(z) * sqrt_eps)
21-
idx = np.where(abs(z - poles) < t)[0]
22-
print idx
23-
if len(idx):
24-
print "found match %s" % (abs(z - poles) < t)
25-
poles = np.delete(poles, idx[0])
26-
else:
27-
newzeros.append(z)
28-
print newzeros
29-
print poles
12+
i = 0
13+
j = 0
14+
newzeros = []
15+
zeros = np.roots(h.num[i][j])
16+
poles = np.roots(h.den[i][j])
17+
gain = h.num[i][j][0] / h.den[i][j][0]
18+
# check all zeros
19+
for z in zeros:
20+
t = tol or \
21+
1000 * max(float_info.epsilon, abs(z) * sqrt_eps)
22+
idx = np.where(abs(z - poles) < t)[0]
23+
print idx
24+
if len(idx):
25+
print "found match %s" % (abs(z - poles) < t)
26+
poles = np.delete(poles, idx[0])
27+
else:
28+
newzeros.append(z)
29+
30+
print newzeros
31+
print poles
3032

31-
32-
33+
h2 = TransferFunction(gain*np.real(np.poly(newzeros)), np.real(np.poly(poles)))
34+
35+
print h2
3336

3437

scratch/svninfo.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
revisions work merged?
2+
3+
218 - 212 addition of frd
4+
5+
213 scratch code frd DO NOT MERGE
6+
7+
214 scratch code minreal DO NOT MERGE
8+
9+
215 minreal for xferfcn

src/xferfcn.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
TransferFunction.pole
2727
TransferFunction.zero
2828
TransferFunction.feedback
29+
TransferFunction.minreal
2930
TransferFunction.returnScipySignalLti
3031
TransferFunction._common_den
3132
_tfpolyToString
@@ -76,7 +77,8 @@
7677

7778
# External function declarations
7879
from numpy import angle, any, array, empty, finfo, insert, ndarray, ones, \
79-
polyadd, polymul, polyval, roots, sort, sqrt, zeros, squeeze
80+
polyadd, polymul, polyval, roots, sort, sqrt, zeros, squeeze, where, \
81+
delete, real, poly
8082
from scipy.signal import lti
8183
from copy import deepcopy
8284
from lti import Lti
@@ -505,6 +507,46 @@ def feedback(self, other, sign=-1):
505507
# But this does not work correctly because the state size will be too
506508
# large.
507509

510+
def minreal(self, tol=None):
511+
"""Remove cancelling pole/zero pairs from a transfer function"""
512+
# based on octave minreal
513+
514+
# default accuracy
515+
from sys import float_info
516+
sqrt_eps = sqrt(float_info.epsilon)
517+
518+
# pre-allocate arrays
519+
num = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
520+
den = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
521+
522+
for i in range(self.outputs):
523+
for j in range(self.inputs):
524+
525+
# split up in zeros, poles and gain
526+
newzeros = []
527+
zeros = roots(self.num[i][j])
528+
poles = roots(self.den[i][j])
529+
gain = self.num[i][j][0] / self.den[i][j][0]
530+
531+
# check all zeros
532+
for z in zeros:
533+
t = tol or \
534+
1000 * max(float_info.epsilon, abs(z) * sqrt_eps)
535+
idx = where(abs(z - poles) < t)[0]
536+
if len(idx):
537+
# cancel this zero against one of the poles
538+
poles = delete(poles, idx[0])
539+
else:
540+
# keep this zero
541+
newzeros.append(z)
542+
543+
# keep result
544+
num[i][j] = gain * real(poly(newzeros))
545+
den[i][j] = real(poly(poles))
546+
547+
# end result
548+
return TransferFunction(num, den)
549+
508550
def returnScipySignalLti(self):
509551
"""Return a list of a list of scipy.signal.lti objects.
510552

tests/xferfcn_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,15 @@ def testConvertToTransferFunction(self):
433433
np.testing.assert_array_almost_equal(tfsys.num[i][j], num[i][j])
434434
np.testing.assert_array_almost_equal(tfsys.den[i][j], den[i][j])
435435

436+
def testMinreal(self):
437+
"""Try the minreal function"""
438+
s = TransferFunction([1, 0], [1])
439+
h = (s+1)*(s+2.00000000001)/(s+2)/(s**2+s+1)
440+
hm = h.minreal()
441+
hr = (s+1)/(s**2+s+1)
442+
np.testing.assert_array_almost_equal(hm.num[0][0], hr.num[0][0])
443+
np.testing.assert_array_almost_equal(hm.den[0][0], hr.den[0][0])
444+
436445
def suite():
437446
return unittest.TestLoader().loadTestsFromTestCase(TestXferFcn)
438447

0 commit comments

Comments
 (0)