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 DICO='C'
192+ """
190193 A = np .array ([[1. , - 2. ], [3. , - 4. ]])
191194 B = np .array ([[5. ], [7. ]])
192195
@@ -202,6 +205,74 @@ 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+ def testPlace_varga_continuous_partial_eigs (self ):
222+ """
223+ Check that we are able to use the alpha parameter to only place
224+ a subset of the eigenvalues, for the continous time case.
225+ """
226+ # A matrix has eigenvalues at s=-1, and s=-2. Choose alpha = -1.5
227+ # and check that eigenvalue at s=-2 stays put.
228+ A = np .array ([[1. , - 2. ], [3. , - 4. ]])
229+ B = np .array ([[5. ], [7. ]])
230+
231+ P = np .array ([- 3. ])
232+ P_expected = np .array ([- 2.0 , - 3.0 ])
233+ alpha = - 1.5
234+ K = place_varga (A , B , P , alpha = alpha )
235+
236+ P_placed = np .linalg .eigvals (A - B .dot (K ))
237+ # No guarantee of the ordering, so sort them
238+ P_expected .sort ()
239+ P_placed .sort ()
240+ np .testing .assert_array_almost_equal (P_expected , P_placed )
241+
242+ def testPlace_varga_discrete (self ):
243+ """
244+ Check that we can place poles using DICO='D' (discrete time)
245+ """
246+ A = np .array ([[1. , 0 ], [0 , 0.5 ]])
247+ B = np .array ([[5. ], [7. ]])
248+
249+ P = np .array ([0.5 , 0.5 ])
250+ K = place_varga (A , B , P , DICO = 'D' )
251+ P_placed = np .linalg .eigvals (A - B .dot (K ))
252+ # No guarantee of the ordering, so sort them
253+ P .sort ()
254+ P_placed .sort ()
255+ np .testing .assert_array_almost_equal (P , P_placed )
256+
257+ def testPlace_varga_discrete_partial_eigs (self ):
258+ """"
259+ Check that we can only assign a single eigenvalue in the discrete
260+ time case.
261+ """
262+ # A matrix has eigenvalues at 1.0 and 0.5. Set alpha = 0.51, and
263+ # check that the eigenvalue at 0.5 is not moved.
264+ A = np .array ([[1. , 0 ], [0 , 0.5 ]])
265+ B = np .array ([[5. ], [7. ]])
266+ P = np .array ([0.2 , 0.6 ])
267+ P_expected = np .array ([0.5 , 0.6 ])
268+ alpha = 0.51
269+ K = place_varga (A , B , P , DICO = 'D' , alpha = alpha )
270+ P_placed = np .linalg .eigvals (A - B .dot (K ))
271+ P_expected .sort ()
272+ P_placed .sort ()
273+ np .testing .assert_array_almost_equal (P_expected , P_placed )
274+
275+
205276 def check_LQR (self , K , S , poles , Q , R ):
206277 S_expected = np .array (np .sqrt (Q * R ))
207278 K_expected = S_expected / R
0 commit comments