Skip to content

Commit c4adc4c

Browse files
committed
added acker() from Roberto Bucher
1 parent 5925723 commit c4adc4c

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2012-09-09 Richard Murray <murray@altura.local>
2+
3+
* tests/statefbk_test.py (TestStatefbk.testAcker): unit test
4+
5+
* src/statefbk.py (acker): added acker() from Roberto Bucher.
6+
17
2012-08-29 Richard Murray <murray@altura.local>
28

39
* src/xferfcn.py (TransferFunction._common_den): fixed up code for

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
from nichols import nichols_plot, nichols
6868
from phaseplot import phase_plot, box_grid
6969
from rlocus import root_locus
70-
from statefbk import place, lqr, ctrb, obsv, gram
70+
from statefbk import place, lqr, ctrb, obsv, gram, acker
7171
from statesp import StateSpace
7272
from timeresp import forced_response, initial_response, step_response, \
7373
impulse_response

src/statefbk.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
# External packages and modules
4343
import numpy as np
44+
import scipy as sp
4445
import ctrlutil
4546
from exception import *
4647
import statesp
@@ -99,6 +100,44 @@ def place(A, B, p):
99100
# Return the gain matrix, with MATLAB gain convention
100101
return -F
101102

103+
# Contributed by Roberto Bucher <roberto.bucher@supsi.ch>
104+
def acker(A,B,poles):
105+
"""Pole placemenmt using Ackermann method
106+
107+
Call:
108+
k=acker(A,B,poles)
109+
110+
Parameters
111+
----------
112+
A, B : State and input matrix of the system
113+
poles: desired poles
114+
115+
Returns
116+
-------
117+
k: matrix
118+
State feedback gains
119+
120+
"""
121+
# Convert the inputs to matrices
122+
a = np.mat(A)
123+
b = np.mat(B)
124+
125+
# Make sure the system is controllable
126+
p = np.real(np.poly(poles))
127+
ct = ctrb(A,B)
128+
if sp.linalg.det(ct) == 0:
129+
raise ValueError, "System not reachable; pole placement invalid"
130+
131+
# Place the poles using Ackermann's method
132+
n = np.size(p)
133+
pmat = p[n-1]*a**0
134+
for i in np.arange(1,n):
135+
pmat = pmat+p[n-i-1]*a**i
136+
k = sp.linalg.inv(ct)*pmat
137+
k = k[-1][:]
138+
139+
return k
140+
102141
def lqr(*args, **keywords):
103142
"""Linear quadratic regulator design
104143

tests/statefbk_test.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@
55

66
import unittest
77
import numpy as np
8-
from control.statefbk import ctrb, obsv, place, lqr, gram
8+
from control.statefbk import ctrb, obsv, place, lqr, gram, acker
99
from control.matlab import *
1010

1111
class TestStatefbk(unittest.TestCase):
12+
"""Test state feedback functions"""
13+
14+
def setUp(self):
15+
# Maximum number of states to test + 1
16+
self.maxStates = 5
17+
# Maximum number of inputs and outputs to test + 1
18+
self.maxTries = 4
19+
# Set to True to print systems to the output.
20+
self.debug = False
21+
1222
def testCtrbSISO(self):
1323
A = np.matrix("1. 2.; 3. 4.")
1424
B = np.matrix("5.; 7.")
@@ -83,6 +93,34 @@ def testGramsys(self):
8393
self.assertRaises(ValueError, gram, sys, 'o')
8494
self.assertRaises(ValueError, gram, sys, 'c')
8595

96+
def testAcker(self):
97+
for states in range(1, self.maxStates):
98+
for i in range(self.maxTries):
99+
# start with a random SS system and transform to TF then
100+
# back to SS, check that the matrices are the same.
101+
sys = rss(states, 1, 1)
102+
if (self.debug):
103+
print sys
104+
105+
# Make sure the system is not degenerate
106+
Cmat = ctrb(sys.A, sys.B)
107+
if (np.linalg.matrix_rank(Cmat) != states):
108+
if (self.debug):
109+
print " skipping (not reachable)"
110+
continue
111+
112+
# Place the poles at random locations
113+
des = rss(states, 1, 1);
114+
poles = pole(des)
115+
116+
# Now place the poles using acker
117+
K = acker(sys.A, sys.B, poles)
118+
new = ss(sys.A - sys.B * K, sys.B, sys.C, sys.D)
119+
placed = pole(new)
120+
121+
np.testing.assert_array_almost_equal(np.sort(poles),
122+
np.sort(placed))
123+
86124
def suite():
87125
return unittest.TestLoader().loadTestsFromTestCase(TestStatefbk)
88126

0 commit comments

Comments
 (0)