changeset 9680:4e45e115b943 octave-forge

control-devel: add system identification draft code
author paramaniac
date Tue, 13 Mar 2012 19:33:44 +0000
parents 2a7cc21d79c9
children ffcea825b6f7
files extra/control-devel/src/slib01bd.cc
diffstat 1 files changed, 308 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extra/control-devel/src/slib01bd.cc	Tue Mar 13 19:33:44 2012 +0000
@@ -0,0 +1,308 @@
+/*
+
+Copyright (C) 2012   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/>.
+
+TODO
+Uses SLICOT IB01BD by courtesy of NICONET e.V.
+<http://www.slicot.org>
+
+Author: Lukas Reichlin <lukas.reichlin@gmail.com>
+Created: March 2012
+Version: 0.1
+
+*/
+
+#include <octave/oct.h>
+#include <f77-fcn.h>
+#include "common.h"
+
+extern "C"
+{ 
+    int F77_FUNC (ib01bd, IB01BD)
+                 (char& METH, char& ALG, char& JOBD,
+                  char& BATCH, char& CONCT, char& CTRL,
+                  int& NOBR, int& M, int& L,
+                  int& NSMP,
+                  double* U, int& LDU,
+                  double* Y, int& LDY,
+                  int& N,
+                  double* R, int& LDR,
+                  double* SV,
+                  double& RCOND, double& TOL,
+                  int* IWORK,
+                  double* DWORK, int& LDWORK,
+                  int& IWARN, int& INFO);
+}
+
+// PKG_ADD: autoload ("slib01bd", "devel_slicot_functions.oct");
+DEFUN_DLD (slib01bd, args, nargout,
+   "-*- texinfo -*-\n\
+Slicot IB01BD Release 5.0\n\
+No argument checking.\n\
+For internal use only.")
+{
+    int nargin = args.length ();
+    octave_value_list retval;
+    
+    if (nargin != 11)
+    {
+        print_usage ();
+    }
+    else
+    {
+        // arguments in
+        char meth;
+        char alg;
+        char jobd;
+        char batch;
+        char conct;
+        char ctrl;
+        
+        Matrix y = args(0).matrix_value ();
+        Matrix u = args(1).matrix_value ();
+        int nobr = args(2).int_value ();
+        
+        const int imeth = args(3).int_value ();
+        const int ialg = args(4).int_value ();
+        const int ijobd = args(5).int_value ();
+        const int ibatch = args(6).int_value ();
+        const int iconct = args(7).int_value ();
+        const int ictrl = args(8).int_value ();
+        
+        double rcond = args(9).double_value ();
+        double tol = args(10).double_value ();
+        
+
+        if (imeth == 0)
+            meth = 'M';
+        else
+            meth = 'N';
+
+        switch (ialg)
+        {
+            case 0:
+                alg = 'C';
+                break;
+            case 1:
+                alg = 'F';
+                break;
+            case 2:
+                alg = 'Q';
+                break;
+            default:
+                error ("slib01bd: argument 'alg' invalid");
+        }
+        
+        if (ijobd == 0)
+            jobd = 'M';
+        else
+            jobd = 'N';
+        
+        switch (ibatch)
+        {
+            case 0:
+                batch = 'F';
+                break;
+            case 1:
+                batch = 'I';
+                break;
+            case 2:
+                batch = 'L';
+                break;
+            case 3:
+                batch = 'O';
+                break;
+            default:
+                error ("slib01bd: argument 'batch' invalid");
+        }
+
+        if (iconct == 0)
+            conct = 'C';
+        else
+            conct = 'N';
+
+        if (ictrl == 0)
+            ctrl = 'C';
+        else
+            ctrl = 'N';
+
+
+        int m = u.columns ();   // m: number of inputs
+        int l = y.columns ();   // l: number of outputs
+        int nsmp = y.rows ();   // nsmp: number of samples
+        // y.rows == u.rows  is checked by iddata class
+        // TODO: check minimal nsmp size
+        
+        int ldu;
+        
+        if (m == 0)
+            ldu = 1;
+        else                    // m > 0
+            ldu = nsmp;
+
+        int ldy = nsmp;
+
+        // arguments out
+        int n;
+        int ldr;
+        
+        if (meth == 'M' && jobd == 'M')
+            ldr = max (2*(m+l)*nobr, 3*m*nobr);
+        else if (meth == 'N' || (meth == 'M' && jobd == 'N'))
+            ldr = 2*(m+l)*nobr;
+        else
+            error ("slib01bd: could not handle 'ldr' case");
+        
+        Matrix r (ldr, 2*(m+l)*nobr);
+        ColumnVector sv (l*nobr);
+
+        // workspace
+        int liwork;
+
+        if (meth == 'N')            // if METH = 'N'
+            liwork = (m+l)*nobr;
+        else if (alg == 'F')        // if METH = 'M' and ALG = 'F'
+            liwork = m+l;
+        else                        // if METH = 'M' and ALG = 'C' or 'Q'
+            liwork = 0;
+
+        // TODO: Handle 'k' for DWORK
+
+        int ldwork;
+
+        ldwork = 0;
+
+        if (alg == 'C' && (batch == 'F' || batch == 'I') && conct = 'C')
+            ldwork = (4*nobr-2)*(m+l);
+        else if (alg == 'C' && (batch == 'F' || batch == 'I') && conct = 'N')
+            ldwork = 1;
+        else if (meth == 'M' && alg == 'C' && batch == 'L' && conct == 'C')
+            ldwork = max ((4*nobr-2)*(m+l), 5*l*nobr);
+        else if ((meth == 'M' && jobd = 'M' && alg == 'C' && batch == 'O') || (batch == 'L' && conct == 'N'))
+            ldwork = max ((2*m-1)*nobr, (m+l)*nobr, 5*l*nobr);
+        else if ((meth == 'M' && jobd == 'N' && alg == 'C' && batch == 'O') || (batch == 'L' && conct == 'N'))
+            ldwork = 5*l*nobr;
+
+        // FIXME : two times  || (batch == 'L' && conct == 'N') doesn't make sense
+
+C             LDWORK >= 5*(M+L)*NOBR+1, if METH = 'N', ALG = 'C', and
+C                             BATCH = 'L' or 'O';
+C             LDWORK >= (M+L)*2*NOBR*(M+L+3), if ALG = 'F',
+C                             BATCH <> 'O' and CONCT = 'C';
+C             LDWORK >= (M+L)*2*NOBR*(M+L+1), if ALG = 'F',
+C                             BATCH = 'F', 'I' and CONCT = 'N';
+C             LDWORK >= (M+L)*4*NOBR*(M+L+1)+(M+L)*2*NOBR, if ALG = 'F',
+C                             BATCH = 'L' and CONCT = 'N', or
+C                             BATCH = 'O';
+C             LDWORK >= 4*(M+L)*NOBR, if ALG = 'Q', BATCH = 'F', and
+C                             LDR >= NS = NSMP - 2*NOBR + 1;
+C             LDWORK >= max(4*(M+L)*NOBR, 5*L*NOBR), if METH = 'M',
+C                             ALG = 'Q', BATCH = 'O', and LDR >= NS;
+C             LDWORK >= 5*(M+L)*NOBR+1, if METH = 'N', ALG = 'Q',
+C                             BATCH = 'O', and LDR >= NS;
+C             LDWORK >= 6*(M+L)*NOBR, if ALG = 'Q', (BATCH = 'F' or 'O',
+C                             and LDR < NS), or (BATCH = 'I' or
+C                             'L' and CONCT = 'N');
+C             LDWORK >= 4*(NOBR+1)*(M+L)*NOBR, if ALG = 'Q', BATCH = 'I'
+C                             or 'L' and CONCT = 'C'.
+C             The workspace used for ALG = 'Q' is
+C                       LDRWRK*2*(M+L)*NOBR + 4*(M+L)*NOBR,
+C             where LDRWRK = LDWORK/(2*(M+L)*NOBR) - 2; recommended
+C             value LDRWRK = NS, assuming a large enough cache size.
+C             For good performance,  LDWORK  should be larger.
+
+
+
+        OCTAVE_LOCAL_BUFFER (int, iwork, liwork);
+        OCTAVE_LOCAL_BUFFER (double, dwork, ldwork);
+        
+        // error indicators
+        int iwarn = 0;
+        int info = 0;
+
+
+        // SLICOT routine IB01BD
+        F77_XFCN (ib01bd, IB01BD,
+                 (meth, alg, jobd,
+                  batch, conct, ctrl,
+                  nobr, m, l,
+                  nsmp,
+                  u.fortran_vec (), ldu,
+                  y.fortran_vec (), ldy,
+                  n,
+                  r.fortran_vec (), ldr,
+                  sv.fortran_vec (),
+                  rcond, tol,
+                  iwork,
+                  dwork, ldwork,
+                  iwarn, info));
+
+
+        if (f77_exception_encountered)
+            error ("ident: exception in SLICOT subroutine IB01BD");
+
+        static const char* err_msg[] = {
+            "0: OK",
+            "1: error message not specified",
+            "2: the singular value decomposition (SVD) algorithm did "
+                "not converge",
+            "3: a singular upper triangular matrix was found",
+            "4: matrix A is (numerically) singular in discrete-"
+                "time case",
+            "5: the Hamiltonian or symplectic matrix H cannot be "
+                "reduced to real Schur form",
+            "6: the real Schur form of the Hamiltonian or "
+                "symplectic matrix H cannot be appropriately ordered",
+            "7: the Hamiltonian or symplectic matrix H has less "
+                "than N stable eigenvalues",
+            "8: the N-th order system of linear algebraic "
+                "equations, from which the solution matrix X would "
+                "be obtained, is singular to working precision",
+            "9: the QR algorithm failed to complete the reduction "
+                "of the matrix Ac to Schur canonical form, T",
+            "10: the QR algorithm did not converge"};
+
+        static const char* warn_msg[] = {
+            "0: OK",
+            "1: warning message not specified",
+            "2: warning message not specified",
+            "3: warning message not specified",
+            "4: a least squares problem to be solved has a "
+                "rank-deficient coefficient matrix",
+            "5: the computed covariance matrices are too small. "
+                "The problem seems to be a deterministic one; the "
+                "gain matrix is set to zero"};
+
+
+        error_msg ("ident", info, 10, err_msg);
+        warning_msg ("ident", iwarn, 5, warn_msg);
+
+
+        // resize
+        int rs = 2*(m+l)*nobr;
+        r.resize (rs, rs);
+
+        
+        // return values
+        retval(0) = octave_value (n);
+        retval(1) = r;
+        retval(2) = sv;
+    }
+    
+    return retval;
+}