@@ -475,6 +475,10 @@ def lqr(*args, **keywords):
475475 State and input weight matrices
476476 N : 2D array, optional
477477 Cross weight matrix
478+ method : str, optional
479+ Set the method used for computing the result. Current methods are
480+ 'slycot' and 'scipy'. If set to None (default), try 'slycot' first
481+ and then 'scipy'.
478482
479483 Returns
480484 -------
@@ -498,14 +502,23 @@ def lqr(*args, **keywords):
498502 --------
499503 >>> K, S, E = lqr(sys, Q, R, [N])
500504 >>> K, S, E = lqr(A, B, Q, R, [N])
505+
501506 """
502507
503- # Make sure that SLICOT is installed
504- try :
505- from slycot import sb02md
506- from slycot import sb02mt
507- except ImportError :
508- raise ControlSlycot ("can't find slycot module 'sb02md' or 'sb02nt'" )
508+ # Figure out what method to use
509+ method = keywords .get ('method' , None )
510+ if method == 'slycot' or method is None :
511+ # Make sure that SLICOT is installed
512+ try :
513+ from slycot import sb02md
514+ from slycot import sb02mt
515+ method = 'slycot'
516+ except ImportError :
517+ if method == 'slycot' :
518+ raise ControlSlycot (
519+ "can't find slycot module 'sb02md' or 'sb02nt'" )
520+ else :
521+ method = 'scipy'
509522
510523 #
511524 # Process the arguments and figure out what inputs we received
@@ -546,18 +559,28 @@ def lqr(*args, **keywords):
546559 N .shape [0 ] != nstates or N .shape [1 ] != ninputs ):
547560 raise ControlDimension ("incorrect weighting matrix dimensions" )
548561
549- # Compute the G matrix required by SB02MD
550- A_b , B_b , Q_b , R_b , L_b , ipiv , oufact , G = \
551- sb02mt (nstates , ninputs , B , R , A , Q , N , jobl = 'N' )
562+ if method == 'slycot' :
563+ # Compute the G matrix required by SB02MD
564+ A_b , B_b , Q_b , R_b , L_b , ipiv , oufact , G = \
565+ sb02mt (nstates , ninputs , B , R , A , Q , N , jobl = 'N' )
552566
553- # Call the SLICOT function
554- X , rcond , w , S , U , A_inv = sb02md (nstates , A_b , G , Q_b , 'C' )
567+ # Call the SLICOT function
568+ X , rcond , w , S , U , A_inv = sb02md (nstates , A_b , G , Q_b , 'C' )
555569
556- # Now compute the return value
557- # We assume that R is positive definite and, hence, invertible
558- K = np .linalg .solve (R , B .T @ X + N .T )
559- S = X
560- E = w [0 :nstates ]
570+ # Now compute the return value
571+ # We assume that R is positive definite and, hence, invertible
572+ K = np .linalg .solve (R , np .dot (B .T , X ) + N .T )
573+ S = X
574+ E = w [0 :nstates ]
575+
576+ elif method == 'scipy' :
577+ import scipy as sp
578+ S = sp .linalg .solve_continuous_are (A , B , Q , R , s = N )
579+ K = np .linalg .solve (R , B .T @ S + N .T )
580+ E , _ = np .linalg .eig (A - B @ K )
581+
582+ else :
583+ raise ValueError ("unknown method: %s" % method )
561584
562585 return _ssmatrix (K ), _ssmatrix (S ), E
563586
0 commit comments