## Copyright (C) 2009-2016   Lukas F. Reichlin
##
## This file is part of LTI Syncope.
##
## LTI Syncope is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## LTI Syncope is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with LTI Syncope.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn{Function File} {[@var{Kr}, @var{info}] =} btaconred (@var{G}, @var{K}, @dots{})
## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} btaconred (@var{G}, @var{K}, @var{ncr}, @dots{})
## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} btaconred (@var{G}, @var{K}, @var{opt}, @dots{})
## @deftypefnx{Function File} {[@var{Kr}, @var{info}] =} btaconred (@var{G}, @var{K}, @var{ncr}, @var{opt}, @dots{})
##
## Controller reduction by frequency-weighted Balanced Truncation Approximation (BTA).
## Given a plant @var{G} and a stabilizing controller @var{K}, determine a reduced
## order controller @var{Kr} such that the closed-loop system is stable and closed-loop
## performance is retained.
##
## The algorithm tries to minimize the frequency-weighted error
## @tex
## $$ || V \ (K - K_r) \ W ||_{\infty} = \min $$
## @end tex
## @ifnottex
## @example
## ||V (K-Kr) W||    = min
##               inf
## @end example
## @end ifnottex
## where @var{V} and @var{W} denote output and input weightings.
##
##
## @strong{Inputs}
## @table @var
## @item G
## @acronym{LTI} model of the plant.
## It has m inputs, p outputs and n states.
## @item K
## @acronym{LTI} model of the controller.
## It has p inputs, m outputs and nc states.
## @item ncr
## The desired order of the resulting reduced order controller @var{Kr}.
## If not specified, @var{ncr} is chosen automatically according
## to the description of key @var{'order'}.
## @item @dots{}
## Optional pairs of keys and values.  @code{"key1", value1, "key2", value2}.
## @item opt
## Optional struct with keys as field names.
## Struct @var{opt} can be created directly or
## by function @command{options}.  @code{opt.key1 = value1, opt.key2 = value2}.
## @end table
##
## @strong{Outputs}
## @table @var
## @item Kr
## State-space model of reduced order controller.
## @item info
## Struct containing additional information.
## @table @var
## @item info.ncr
## The order of the obtained reduced order controller @var{Kr}.
## @item info.ncs
## The order of the alpha-stable part of original controller @var{K}.
## @item info.hsvc
## The Hankel singular values of the alpha-stable part of @var{K}.
## The @var{ncs} Hankel singular values are ordered decreasingly.
## @end table
## @end table
##
## @strong{Option Keys and Values}
## @table @var
## @item 'order', 'ncr'
## The desired order of the resulting reduced order controller @var{Kr}.
## If not specified, @var{ncr} is chosen automatically such that states with
## Hankel singular values @var{info.hsvc} > @var{tol1} are retained.
##
## @item 'method'
## Order reduction approach to be used as follows:
## @table @var
## @item 'sr', 'b'
## Use the square-root Balance & Truncate method.
## @item 'bfsr', 'f'
## Use the balancing-free square-root Balance & Truncate method.  Default method.
## @end table
##
## @item 'weight'
## Specifies the type of frequency-weighting as follows:
## @table @var
## @item 'none'
## No weightings are used (V = I, W = I).
##
## @item 'left', 'output'
## Use stability enforcing left (output) weighting
## @tex
## $$ V = (I - G K)^{-1} G,  \qquad W = I $$
## @end tex
## @ifnottex
## @example
##           -1
## V = (I-G*K) *G ,  W = I
## @end example
## @end ifnottex
##
## @item 'right', 'input'
## Use stability enforcing right (input) weighting
## @tex
## $$ V = I,  \qquad W = (I - G K)^{-1} G  $$
## @end tex
## @ifnottex
## @example
##                    -1
## V = I ,  W = (I-G*K) *G
## @end example
## @end ifnottex
##
## @item 'both', 'performance'
## Use stability and performance enforcing weightings
## @tex
## $$ V = (I - G K)^{-1} G,  \qquad W = (I - G K)^{-1}  $$
## @end tex
## @ifnottex
## @example
##           -1                -1
## V = (I-G*K) *G ,  W = (I-G*K)
## @end example
## @end ifnottex
## Default value.
## @end table
##
## @item 'feedback'
## Specifies whether @var{K} is a positive or negative feedback controller:
## @table @var
## @item '+'
## Use positive feedback controller.  Default value.
## @item '-'
## Use negative feedback controller.
## @end table
##
## @item 'alpha'
## Specifies the ALPHA-stability boundary for the eigenvalues
## of the state dynamics matrix @var{K.A}.  For a continuous-time
## controller, ALPHA <= 0 is the boundary value for
## the real parts of eigenvalues, while for a discrete-time
## controller, 0 <= ALPHA <= 1 represents the
## boundary value for the moduli of eigenvalues.
## The ALPHA-stability domain does not include the boundary.
## Default value is 0 for continuous-time controllers and
## 1 for discrete-time controllers.
##
## @item 'tol1'
## If @var{'order'} is not specified, @var{tol1} contains the tolerance for
## determining the order of the reduced controller.
## For model reduction, the recommended value of @var{tol1} is
## c*info.hsvc(1), where c lies in the interval [0.00001, 0.001].
## Default value is info.ncs*eps*info.hsvc(1).
## If @var{'order'} is specified, the value of @var{tol1} is ignored.
##
## @item 'tol2'
## The tolerance for determining the order of a minimal
## realization of the ALPHA-stable part of the given
## controller.  TOL2 <= TOL1.
## If not specified, ncs*eps*info.hsvc(1) is chosen.
##
## @item 'gram-ctrb'
## Specifies the choice of frequency-weighted controllability
## Grammian as follows:
## @table @var
## @item 'standard'
## Choice corresponding to standard Enns' method [1].  Default method.
## @item 'enhanced'
## Choice corresponding to the stability enhanced
## modified Enns' method of [2].
## @end table
##
## @item 'gram-obsv'
## Specifies the choice of frequency-weighted observability
## Grammian as follows:
## @table @var
## @item 'standard'
## Choice corresponding to standard Enns' method [1].  Default method.
## @item 'enhanced'
## Choice corresponding to the stability enhanced
## modified Enns' method of [2].
## @end table
##
## @item 'equil', 'scale'
## Boolean indicating whether equilibration (scaling) should be
## performed on @var{G} and @var{K} prior to order reduction.
## Default value is false if both @code{G.scaled == true, K.scaled == true}
## and true otherwise.
## Note that for @acronym{MIMO} models, proper scaling of both inputs and outputs
## is of utmost importance.  The input and output scaling can @strong{not}
## be done by the equilibration option or the @command{prescale} function
## because these functions perform state transformations only.
## Furthermore, signals should not be scaled simply to a certain range.
## For all inputs (or outputs), a certain change should be of the same
## importance for the model.
## @end table
##
## @strong{Algorithm}@*
## Uses @url{https://github.com/SLICOT/SLICOT-Reference, SLICOT SB16AD},
## Copyright (c) 1996-2025, SLICOT, available under the BSD 3-Clause
## (@url{https://github.com/SLICOT/SLICOT-Reference/blob/main/LICENSE,  License and Disclaimer}).
## @end deftypefn

## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
## Created: December 2011
## Version: 0.1

function [Kr, info] = btaconred (varargin)

  [Kr, info] = __conred_sb16ad__ ("bta", varargin{:});

endfunction


%!shared Mo, Me, Info, HSVCe
%! A =  [ -1.  0.   4.
%!         0.  2.   0.
%!         0.  0.  -3. ];
%!
%! B =  [  1.
%!         1.
%!         1. ];
%!
%! C =  [  1.  1.   1. ];
%!
%! D =  [  0. ];
%!
%! G = ss (A, B, C, D, "scaled", true);
%!
%! AC = [ -26.4000,    6.4023,    4.3868;
%!         32.0000,         0,         0;
%!               0,    8.0000,         0  ];
%!
%! BC = [      -16
%!               0
%!               0 ];
%!
%! CC = [   9.2994    1.1624    0.1090 ];
%!
%! DC = [        0 ];
%!
%! K = ss (AC, BC, CC, DC, "scaled", true);
%!
%! [Kr, Info] = btaconred (G, K, 2, "weight", "input", "feedback", "+");
%!
%! Ae = [   9.1900   0.0000
%!          0.0000 -34.5297 ];
%!
%! Be = [ -11.9593
%!         86.3137 ];
%!
%! Ce = [   2.8955  -1.3566 ];
%!
%! De = [   0.0000 ];
%!
%! # Since btaconred approximates an output controller,
%! # only its input/output behavior is important and is tested
%! # using n first Markov parameters.
%! # The state space representaton might have different signs
%! # of the states.
%! # By multiplying the matrices for the Markov parameters, numeric errors
%! # would propagate, therefor the accuracy of the results are limited to
%! # the accuracy of the given expected results
%!
%! [Ao,Bo,Co,Do] = ssdata (Kr);
%! Ao = round (Ao*1e4)/1e4;
%! Bo = round (Bo*1e4)/1e4;
%! Co = round (Co*1e4)/1e4;
%! Do = round (Do*1e4)/1e4;
%!
%! n = size(Ao,1);
%! m = size(Bo,2);
%! p = size(Co,1);
%! Mo = zeros (p,(n+1)*m);
%! Me = zeros (p,(n+1)*m);
%! Mo(:,1:m) = Do;
%! Me(:,1:m) = De;
%! 
%! Aoi = eye (n,n);
%! Aei = eye (n,n);
%! for i = 1:n
%!  Mo(:,(i-1)*m+1:i*m) = Co*Aoi*Bo;
%!  Me(:,(i-1)*m+1:i*m) = Ce*Aei*Be;
%!  Aoi = Aoi*Ao;
%!  Aei = Aei*Ae;
%! endfor
%!
%! HSVCe = [  3.8253   0.2005 ].';
%!
%!assert (Mo, Me, 1e-4);
%!assert (Info.hsvc, HSVCe, 1e-4);
