Contents

MORLAB Demo: Additive Decomposition

This demo script contains the application of the MORLAB additive decomposition routines.

See also ml_ct_d_ss_adtf, ml_ct_d_dss_adtf, ml_dt_d_ss_adtf.

%
% This file is part of the MORLAB toolbox
% (https://www.mpi-magdeburg.mpg.de/projects/morlab).
% Copyright (C) 2006-2023 Peter Benner, Jens Saak, and Steffen W. R. Werner
% All rights reserved.
% License: BSD 2-Clause License (see COPYING)
%

Standard System Case

The MORLAB toolbox implements additive decomposition methods for first-order system types, e.g., considering the dynamical system

x'(t) = A*x(t) + B*u(t),
 y(t) = C*x(t) + D*u(t),

with the matrix A having possible stable and anti-stable eigenvalues. The corresponding transfer function to this system is then given by

G(s) = C*inv(s*I - A)*B + D.

In additive decomposition, the system is transformed in a way such that

G(s) = G_s(s) + G_a(s),

with G_s(s) the transfer function with the stable system part and G_a(s) the transfer function of the anti-stable part.

For demonstration reasons we load a prepared data file containing an unstable standard system:

if exist('OCTAVE_VERSION', 'builtin')
    orig_warn = warning('off', 'Octave:data-file-in-path');
    load morlab_data_std_unstab.mat;
    warning(orig_warn);
else
    load morlab_data_std_unstab.mat;
end

The matrix A has 90 stable and 10 anti-stable eigenvalues. The additive decomposition is performed by calling the appropriate MORLAB routine. Therefore, we are constructing first the system as struct.

sys = struct( ...
    'A', A, ...
    'B', B, ...
    'C', C, ...
    'D', D);

[sys_dec, info] = ml_ct_d_ss_adtf(sys);

The struct sys_dec now contains the matrices corresponding to the stable and anti-stable parts and info is a struct with information about the underlying methods.

disp(sys_dec);
disp(info);
     A: [90×90 double]
     B: [90×3 double]
     C: [2×90 double]
     D: [2×3 double]
    Au: [10×10 double]
    Bu: [10×3 double]
    Cu: [2×10 double]

    infoSTABSIGNM: [1×1 struct]
     infoSTABSYLV: [1×1 struct]
               Ns: 90
               Nu: 10
                V: []
                W: []

We see in the info struct that the method found the 90 stable and 10 anti-stable eigenvalues. The corresponding system matrices are in sys_dec as the stable part denoted like the original system with A, B, C, and D, and the anti-stable part with Au, Bu and Cu.

We saw in the info struct also the fields T and W. In these the underlying transformation matrices can be stored. Therefore, we need to activate the optional parameter StoreProjection.

opts = struct('StoreProjection', 1);

[sys_dec, info] = ml_ct_d_ss_adtf(sys, opts);

disp(info);
    infoSTABSIGNM: [1×1 struct]
     infoSTABSYLV: [1×1 struct]
               Ns: 90
               Nu: 10
                V: [100×100 double]
                W: [100×100 double]

Now the T and W matrices are stored in info and can be used as state-space transformation such that

blkdiag(sys_dec.A, sys_dec.Au) = info.W' * (sys.A * info.V)
[sys_dec.B; sys_dec.Bu]        = info.W' * sys.B
[sys_dec.C, sys_dec.Cu]        = sys.C * info.V.

Descriptor System Case

The additive decomposition changes a bit in case of descriptor systems, e.g.,

E*x'(t) = A*x(t) + B*u(t),
   y(t) = C*x(t) + D*u(t),

with the matrix pencil s*E-A having possible stable, anti-stable and infinite eigenvalues. The corresponding transfer function to this system is then given by

G(s) = C*inv(s*E - A)*B + D.

In additive decomposition, those systems are transformed in a way such that

G(s) = G_s(s) + G_a(s) + P(s),

with G_s(s) the transfer function with the stable system part, G_a(s) the transfer function of the anti-stable part and P(s) the polynomial part.

For demonstration reasons we load a prepared data file containing an unstable descriptor system:

if exist('OCTAVE_VERSION', 'builtin')
    orig_warn = warning('off', 'Octave:data-file-in-path');
    load morlab_data_desc_infunstab.mat;
    warning(orig_warn);
else
    load morlab_data_desc_infunstab.mat;
end

The pencil s*E-A has 80 stable, 10 anti-stable and 10 infinite eigenvalues. As in the standard case, we need to construct the system as struct and call the additive decomposition routine.

sys = struct( ...
    'A', A, ...
    'B', B, ...
    'C', C, ...
    'D', D, ...
    'E', E);

[sys_dec2, info] = ml_ct_d_dss_adtf(sys);

disp(sys_dec2);
disp(info);
       A: [80×80 double]
       B: [80×3 double]
       C: [2×80 double]
       D: [2×3 double]
       E: [80×80 double]
    Ainf: [10×10 double]
    Einf: [10×10 double]
    Binf: [10×3 double]
    Cinf: [2×10 double]
      Au: [10×10 double]
      Eu: [10×10 double]
      Bu: [10×3 double]
      Cu: [2×10 double]

      infoINFDISK: [1×1 struct]
    infoSTABSIGNM: [1×1 struct]
             Ninf: 10
               Ns: 80
               Nu: 10
                V: []
                W: []

We can see in the info struct that the algorithm found the appropriate numbers of eigenvalues and the sys_desc2 is containing now the following groups of matrices: A, B, C, D, E is the stable system part, Au, Bu, Cu, Eu is the anti-stable and Ainf, Binf, Cinf, Einf the polynomial one with Einf being nilpotent.

As in the standard case, we can get the transformation matrices by setting the optional parameter StoreProjection.

opts = struct('StoreProjection', 1);

[sys_dec2, info] = ml_ct_d_dss_adtf(sys, opts);

disp(info);
      infoINFDISK: [1×1 struct]
    infoSTABSIGNM: [1×1 struct]
             Ninf: 10
               Ns: 80
               Nu: 10
                V: [100×100 double]
                W: [100×100 double]

Using the T and W matrices from the info struct as state-space transformation then gives:

blkdiag(sys_dec2.A, sys_dec2.Au, sys_dec2.Ainf) = info.W' * (sys.A * info.V)
[sys_dec2.B; sys_dec2.Bu; sysa_dec2.Binf]       = info.W' * sys.B
[sys_dec2.C, sys_dec2.Cu, sys_dec2.Cinf]        = sys.C * info.V
blkdiag(sys_dec2.E, sys_dec2.Eu, sys_dec2.Einf) = info.W' * (sys.E * info.V)

Remarks