93 lines
3.4 KiB
Python
93 lines
3.4 KiB
Python
#!/usr/bin/env python -*-coding: utf-8-*-
|
|
#
|
|
# Test Pade approx
|
|
#
|
|
# Primitive; ideally test to numerical limits
|
|
|
|
from __future__ import division
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
from control.delay import pade
|
|
|
|
|
|
class TestPade(unittest.TestCase):
|
|
|
|
# Reference data from Miklos Vajta's paper "Some remarks on
|
|
# Padé-approximations", Table 1, with corrections. The
|
|
# corrections are to highest power coeff in numerator for
|
|
# (ddeg,ndeg)=(4,3) and (5,4); use Eq (12) in the paper to verify
|
|
|
|
# all for T = 1
|
|
ref = [
|
|
# dendeg numdeg den num
|
|
( 1, 1, [1,2], [-1,2]),
|
|
( 1, 0, [1,1], [1]),
|
|
( 2, 2, [1,6,12], [1,-6,12]),
|
|
( 2, 1, [1,4,6], [-2,6]),
|
|
( 3, 3, [1,12,60,120], [-1,12,-60,120]),
|
|
( 3, 2, [1,9,36,60], [3,-24,60]),
|
|
( 4, 4, [1,20,180,840,1680], [1,-20,180,-840,1680]),
|
|
( 4, 3, [1,16,120,480,840], [-4,60,-360,840]),
|
|
( 5, 5, [1,30,420,3360,15120,30240], [-1,30,-420,3360,-15120,30240]),
|
|
( 5, 4, [1,25,300,2100,8400,15120,], [5,-120,1260,-6720,15120]),
|
|
]
|
|
|
|
def testRefs(self):
|
|
"test reference cases for T=1"
|
|
T = 1
|
|
for dendeg, numdeg, refden, refnum in self.ref:
|
|
num, den = pade(T, dendeg, numdeg)
|
|
np.testing.assert_array_almost_equal_nulp(np.array(refden), den, nulp=2)
|
|
np.testing.assert_array_almost_equal_nulp(np.array(refnum), num, nulp=2)
|
|
|
|
def testTvalues(self):
|
|
"test reference cases for T!=1"
|
|
Ts = [1/53, 21.95]
|
|
for dendeg, numdeg, baseden, basenum in self.ref:
|
|
for T in Ts:
|
|
refden = T**np.arange(dendeg, -1, -1)*baseden
|
|
refnum = T**np.arange(numdeg, -1, -1)*basenum
|
|
refnum /= refden[0]
|
|
refden /= refden[0]
|
|
num, den = pade(T, dendeg, numdeg)
|
|
np.testing.assert_array_almost_equal_nulp(refden, den, nulp=2)
|
|
np.testing.assert_array_almost_equal_nulp(refnum, num, nulp=2)
|
|
|
|
def testErrors(self):
|
|
"ValueError raised for invalid arguments"
|
|
self.assertRaises(ValueError,pade,-1,1) # T<0
|
|
self.assertRaises(ValueError,pade,1,-1) # dendeg < 0
|
|
self.assertRaises(ValueError,pade,1,2,-3) # numdeg < 0
|
|
self.assertRaises(ValueError,pade,1,2,3) # numdeg > dendeg
|
|
|
|
def testNumdeg(self):
|
|
"numdeg argument follows docs"
|
|
# trivialish - interface check, not math check
|
|
T = 1
|
|
dendeg = 5
|
|
ref = [pade(T,dendeg,numdeg)
|
|
for numdeg in range(0,dendeg+1)]
|
|
testneg = [pade(T,dendeg,numdeg)
|
|
for numdeg in range(-dendeg,0)]
|
|
self.assertEqual(ref[:-1],testneg)
|
|
self.assertEqual(ref[-1], pade(T,dendeg,dendeg))
|
|
self.assertEqual(ref[-1], pade(T,dendeg,None))
|
|
self.assertEqual(ref[-1], pade(T,dendeg))
|
|
|
|
def testT0(self):
|
|
"T=0 always returns [1],[1]"
|
|
T = 0
|
|
refnum = [1.0]
|
|
refden = [1.0]
|
|
for dendeg in range(1, 6):
|
|
for numdeg in range(0, dendeg+1):
|
|
num, den = pade(T, dendeg, numdeg)
|
|
np.testing.assert_array_almost_equal_nulp(np.array(refnum), np.array(num))
|
|
np.testing.assert_array_almost_equal_nulp(np.array(refden), np.array(den))
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|