66from __future__ import print_function
77import unittest
88import numpy as np
9- from control .statefbk import ctrb , obsv , place , lqr , gram , acker
9+ from control .statefbk import ctrb , obsv , place , place_varga , lqr , gram , acker
1010from control .matlab import *
1111from control .exception import slycot_check , ControlDimension
1212
@@ -186,7 +186,10 @@ def testPlace(self):
186186 np .testing .assert_raises (ValueError , place , A , B , P_repeated )
187187
188188 @unittest .skipIf (not slycot_check (), "slycot not installed" )
189- def testPlace_varga (self ):
189+ def testPlace_varga_continuous (self ):
190+ """
191+ Check that we can place eigenvalues for dtime=False
192+ """
190193 A = np .array ([[1. , - 2. ], [3. , - 4. ]])
191194 B = np .array ([[5. ], [7. ]])
192195
@@ -202,6 +205,77 @@ def testPlace_varga(self):
202205 np .testing .assert_raises (ControlDimension , place , A [1 :, :], B , P )
203206 np .testing .assert_raises (ControlDimension , place , A , B [1 :, :], P )
204207
208+ # Regression test against bug #177
209+ # https://github.com/python-control/python-control/issues/177
210+ A = np .array ([[0 , 1 ], [100 , 0 ]])
211+ B = np .array ([[0 ], [1 ]])
212+ P = np .array ([- 20 + 10 * 1j , - 20 - 10 * 1j ])
213+ K = place_varga (A , B , P )
214+ P_placed = np .linalg .eigvals (A - B .dot (K ))
215+
216+ # No guarantee of the ordering, so sort them
217+ P .sort ()
218+ P_placed .sort ()
219+ np .testing .assert_array_almost_equal (P , P_placed )
220+
221+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
222+ def testPlace_varga_continuous_partial_eigs (self ):
223+ """
224+ Check that we are able to use the alpha parameter to only place
225+ a subset of the eigenvalues, for the continous time case.
226+ """
227+ # A matrix has eigenvalues at s=-1, and s=-2. Choose alpha = -1.5
228+ # and check that eigenvalue at s=-2 stays put.
229+ A = np .array ([[1. , - 2. ], [3. , - 4. ]])
230+ B = np .array ([[5. ], [7. ]])
231+
232+ P = np .array ([- 3. ])
233+ P_expected = np .array ([- 2.0 , - 3.0 ])
234+ alpha = - 1.5
235+ K = place_varga (A , B , P , alpha = alpha )
236+
237+ P_placed = np .linalg .eigvals (A - B .dot (K ))
238+ # No guarantee of the ordering, so sort them
239+ P_expected .sort ()
240+ P_placed .sort ()
241+ np .testing .assert_array_almost_equal (P_expected , P_placed )
242+
243+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
244+ def testPlace_varga_discrete (self ):
245+ """
246+ Check that we can place poles using dtime=True (discrete time)
247+ """
248+ A = np .array ([[1. , 0 ], [0 , 0.5 ]])
249+ B = np .array ([[5. ], [7. ]])
250+
251+ P = np .array ([0.5 , 0.5 ])
252+ K = place_varga (A , B , P , dtime = True )
253+ P_placed = np .linalg .eigvals (A - B .dot (K ))
254+ # No guarantee of the ordering, so sort them
255+ P .sort ()
256+ P_placed .sort ()
257+ np .testing .assert_array_almost_equal (P , P_placed )
258+
259+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
260+ def testPlace_varga_discrete_partial_eigs (self ):
261+ """"
262+ Check that we can only assign a single eigenvalue in the discrete
263+ time case.
264+ """
265+ # A matrix has eigenvalues at 1.0 and 0.5. Set alpha = 0.51, and
266+ # check that the eigenvalue at 0.5 is not moved.
267+ A = np .array ([[1. , 0 ], [0 , 0.5 ]])
268+ B = np .array ([[5. ], [7. ]])
269+ P = np .array ([0.2 , 0.6 ])
270+ P_expected = np .array ([0.5 , 0.6 ])
271+ alpha = 0.51
272+ K = place_varga (A , B , P , dtime = True , alpha = alpha )
273+ P_placed = np .linalg .eigvals (A - B .dot (K ))
274+ P_expected .sort ()
275+ P_placed .sort ()
276+ np .testing .assert_array_almost_equal (P_expected , P_placed )
277+
278+
205279 def check_LQR (self , K , S , poles , Q , R ):
206280 S_expected = np .array (np .sqrt (Q * R ))
207281 K_expected = S_expected / R
0 commit comments