@@ -583,7 +583,7 @@ def dlqr(*args, **kwargs):
583583# Function to create an I/O sytems representing a state feedback controller
584584def create_statefbk_iosystem (
585585 sys , gain , feedfwd_gain = None , integral_action = None , estimator = None ,
586- controller_type = None , xd_labels = None , ud_labels = None ,
586+ controller_type = None , xd_labels = None , ud_labels = None , ref_labels = None ,
587587 feedfwd_pattern = 'trajgen' , gainsched_indices = None ,
588588 gainsched_method = 'linear' , control_indices = None , state_indices = None ,
589589 name = None , inputs = None , outputs = None , states = None , ** kwargs ):
@@ -645,24 +645,15 @@ def create_statefbk_iosystem(
645645 If an I/O system is given, the error e = x - xd is passed to the
646646 system and the output is used as the feedback compensation term.
647647
648- xd_labels, ud_labels : str or list of str, optional
649- Set the name of the signals to use for the desired state and
650- inputs. If a single string is specified, it should be a format
651- string using the variable `i` as an index. Otherwise, a list of
652- strings matching the size of `x_d` and `u_d`, respectively, should
653- be used. Default is "xd[{i}]" for xd_labels and "ud[{i}]" for
654- ud_labels. These settings can also be overridden using the
655- `inputs` keyword.
656-
657- feedfwd_pattern : str, optional
658- If set to 'refgain', the reference gain design pattern is used to
659- create the controller instead of the trajectory generation pattern.
660-
661648 feedfwd_gain : array_like, optional
662649 Specify the feedforward gain, `k_f`. Used only for the reference
663650 gain design pattern. If not given and if `sys` is a `StateSpace`
664651 (linear) system, will be computed as -1/(C (A-BK)^{-1}) B.
665652
653+ feedfwd_pattern : str, optional
654+ If set to 'refgain', the reference gain design pattern is used to
655+ create the controller instead of the trajectory generation pattern.
656+
666657 integral_action : ndarray, optional
667658 If this keyword is specified, the controller can include integral
668659 action in addition to state feedback. The value of the
@@ -703,17 +694,19 @@ def create_statefbk_iosystem(
703694 Returns
704695 -------
705696 ctrl : NonlinearIOSystem
706- Input/output system representing the controller. This system
707- takes as inputs the desired state `x_d`, the desired input
708- `u_d`, and either the system state `x` or the estimated state
709- `xhat`. It outputs the controller action `u` according to the
710- formula `u = u_d - K(x - x_d)`. If the keyword
711- `integral_action` is specified, then an additional set of
712- integrators is included in the control system (with the gain
713- matrix `K` having the integral gains appended after the state
714- gains). If a gain scheduled controller is specified, the gain
715- (proportional and integral) are evaluated using the scheduling
716- variables specified by `gainsched_indices`.
697+ Input/output system representing the controller. For the 'trajgen'
698+ design patter (default), this system takes as inputs the desired
699+ state `x_d`, the desired input `u_d`, and either the system state
700+ `x` or the estimated state `xhat`. It outputs the controller
701+ action `u` according to the formula `u = u_d - K(x - x_d)`. For
702+ the 'refgain' design patter, the system takes as inputs the
703+ reference input `r` and the system or estimated state. If the
704+ keyword `integral_action` is specified, then an additional set of
705+ integrators is included in the control system (with the gain matrix
706+ `K` having the integral gains appended after the state gains). If
707+ a gain scheduled controller is specified, the gain (proportional
708+ and integral) are evaluated using the scheduling variables
709+ specified by `gainsched_indices`.
717710
718711 clsys : NonlinearIOSystem
719712 Input/output system representing the closed loop system. This
@@ -739,6 +732,15 @@ def create_statefbk_iosystem(
739732 specified as either integer offsets or as estimator/system output
740733 signal names. If not specified, defaults to the system states.
741734
735+ xd_labels, ud_labels, ref_labels : str or list of str, optional
736+ Set the name of the signals to use for the desired state and inputs
737+ or the reference inputs (for the 'refgain' design pattern). If a
738+ single string is specified, it should be a format string using the
739+ variable `i` as an index. Otherwise, a list of strings matching
740+ the size of `x_d` and `u_d`, respectively, should be used. Default
741+ is "xd[{i}]" for xd_labels and "ud[{i}]" for ud_labels. These
742+ settings can also be overridden using the `inputs` keyword.
743+
742744 inputs, outputs, states : str, or list of str, optional
743745 List of strings that name the individual signals of the transformed
744746 system. If not given, the inputs, outputs, and states are the same
@@ -835,14 +837,18 @@ def create_statefbk_iosystem(
835837 # Check for gain scheduled controller
836838 if len (gain ) != 2 :
837839 raise ControlArgument ("gain must be a 2-tuple for gain scheduling" )
840+ elif feedfwd_pattern != 'trajgen' :
841+ raise NotImplementedError (
842+ "Gain scheduling is not implemented for pattern "
843+ f"'{ feedfwd_pattern } '" )
838844 gains , points = gain [0 :2 ]
839845
840846 # Stack gains and points if past as a list
841847 gains = np .stack (gains )
842848 points = np .stack (points )
843849 gainsched = True
844850
845- elif isinstance (gain , NonlinearIOSystem ):
851+ elif isinstance (gain , NonlinearIOSystem ) and feedfwd_pattern != 'refgain' :
846852 if controller_type not in ['iosystem' , None ]:
847853 raise ControlArgument (
848854 f"incompatible controller type '{ controller_type } '" )
@@ -874,7 +880,10 @@ def create_statefbk_iosystem(
874880 if inputs is None :
875881 inputs = xd_labels + ud_labels + estimator .output_labels
876882 elif feedfwd_pattern == 'refgain' :
877- raise NotImplementedError ("reference gain pattern not yet implemented" )
883+ ref_labels = _process_labels (ref_labels , 'r' , [
884+ f'r[{ i } ]' for i in range (sys_ninputs )])
885+ if inputs is None :
886+ inputs = ref_labels + estimator .output_labels
878887 else :
879888 raise NotImplementedError (f"unknown pattern '{ feedfwd_pattern } '" )
880889
@@ -1006,7 +1015,32 @@ def _control_output(t, states, inputs, params):
10061015 if controller_type not in ['linear' , 'iosystem' ]:
10071016 raise ControlArgument (
10081017 "refgain design pattern only supports linear controllers" )
1009- raise NotImplementedError ("reference gain pattern not yet implemented" )
1018+
1019+ if feedfwd_gain is None :
1020+ raise ControlArgument (
1021+ "'feedfwd_gain' required for reference gain pattern" )
1022+
1023+ # Check to make sure the reference gain is valid
1024+ Kf = np .atleast_2d (feedfwd_gain )
1025+ if Kf .ndim != 2 or Kf .shape [0 ] != sys .ninputs or \
1026+ Kf .shape [1 ] != sys .ninputs :
1027+ raise ControlArgument ("feedfwd_gain is not the right shape" )
1028+
1029+ # Create the matrices implementing the controller
1030+ # [r, x]->[u]: u = k_f r - K_p x - K_i \int(C x - r)
1031+ if isctime (sys ):
1032+ # Continuous time: integrator
1033+ A_lqr = np .zeros ((C .shape [0 ], C .shape [0 ]))
1034+ else :
1035+ # Discrete time: summer
1036+ A_lqr = np .eye (C .shape [0 ])
1037+ B_lqr = np .hstack ([- np .eye (C .shape [0 ], sys_ninputs ), C ])
1038+ C_lqr = - K [:, sys_nstates :] # integral gain (opt)
1039+ D_lqr = np .hstack ([Kf , - K ])
1040+
1041+ ctrl = ss (
1042+ A_lqr , B_lqr , C_lqr , D_lqr , dt = sys .dt , name = name ,
1043+ inputs = inputs , outputs = outputs , states = states )
10101044
10111045 else :
10121046 raise ControlArgument (f"unknown controller_type '{ controller_type } '" )
0 commit comments