123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- function [M0,M1,L1,L2] = spm_bireduce(M,P)
- % reduction of a fully nonlinear MIMO system to Bilinear form
- % FORMAT [M0,M1,L1,L2] = spm_bireduce(M,P);
- %
- % M - model specification structure
- % Required fields:
- % M.f - dx/dt = f(x,u,P,M) {function string or m-file}
- % M.g - y(t) = g(x,u,P,M) {function string or m-file}
- % M.bi - bilinear form [M0,M1,L1,L2] = bi(M,P) {function string or m-file}
- % M.m - m inputs
- % M.n - n states
- % M.l - l outputs
- % M.x - (n x 1) = x(0) = expansion point: defaults to x = 0;
- % M.u - (m x 1) = u = expansion point: defaults to u = 0;
- %
- % M.D - delay operator df/dx -> D*df/dx [optional]
- %
- % P - model parameters
- %
- % A Bilinear approximation is returned where the states are
- %
- % q(t) = [1; x(t) - x(0)]
- %
- %___________________________________________________________________________
- % Returns Matrix operators for the Bilinear approximation to the MIMO
- % system described by
- %
- % dx/dt = f(x,u,P)
- % y(t) = g(x,u,P)
- %
- % evaluated at x(0) = x and u = 0
- %
- % dq/dt = M0*q + u(1)*M1{1}*q + u(2)*M1{2}*q + ....
- % y(i) = L1(i,:)*q + q'*L2{i}*q/2;
- %
- %--------------------------------------------------------------------------
- % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
- % Karl Friston
- % $Id: spm_bireduce.m 6856 2016-08-10 17:55:05Z karl $
- % set up
- %==========================================================================
- % create inline functions
- %--------------------------------------------------------------------------
- try
- funx = fcnchk(M.f,'x','u','P','M');
- catch
- M.f = inline('sparse(0,1)','x','u','P','M');
- M.n = 0;
- M.x = sparse(0,0);
- funx = fcnchk(M.f,'x','u','P','M');
- end
- % expansion point
- %--------------------------------------------------------------------------
- x = spm_vec(M.x);
- try
- u = spm_vec(M.u);
- catch
- u = sparse(M.m,1);
- end
- % Partial derivatives for 1st order Bilinear operators
- %==========================================================================
- % f(x(0),0) and derivatives
- %--------------------------------------------------------------------------
- if all(isfield(M,{'dfdxu','dfdx','dfdu','f0'}))
- dfdxu = M.dfdxu;
- dfdx = M.dfdx;
- dfdu = M.dfdu;
- f0 = M.f0;
- else
- [dfdxu,dfdx] = spm_diff(funx,M.x,u,P,M,[1 2]);
- [dfdu, f0] = spm_diff(funx,M.x,u,P,M,2);
- end
- f0 = spm_vec(f0);
- m = length(dfdxu); % m inputs
- n = length(f0); % n states
- % delay operator
- %--------------------------------------------------------------------------
- if isfield(M,'D')
- f0 = M.D*f0;
- dfdx = M.D*dfdx;
- dfdu = M.D*dfdu;
- for i = 1:m
- dfdxu{i} = M.D*dfdxu{i};
- end
- end
- % Bilinear operators
- %==========================================================================
- % Bilinear operator - M0
- %--------------------------------------------------------------------------
- M0 = spm_cat({0 [] ;
- (f0 - dfdx*x) dfdx});
- % Bilinear operator - M1 = dM0/du
- %--------------------------------------------------------------------------
- M1 = cell(m,1);
- for i = 1:m
- M1{i} = spm_cat({0, [] ;
- (dfdu(:,i) - dfdxu{i}*x), dfdxu{i}});
- end
- if nargout < 3, return, end
- % Output operators
- %==========================================================================
- % add observer if not specified
- %--------------------------------------------------------------------------
- try
- fung = fcnchk(M.g,'x','u','P','M');
- catch
- M.g = inline('spm_vec(x)','x','u','P','M');
- M.l = n;
- fung = fcnchk(M.g,'x','u','P','M');
- end
- % g(x(0),0)
- %--------------------------------------------------------------------------
- [dgdx,g0] = spm_diff(fung,M.x,u,P,M,1);
- g0 = spm_vec(g0);
- l = length(g0);
- % Output matrices - L1
- %--------------------------------------------------------------------------
- L1 = spm_cat({(spm_vec(g0) - dgdx*x), dgdx});
- if nargout < 4, return, end
- % Output matrices - L2
- %--------------------------------------------------------------------------
- dgdxx = spm_diff(fung,M.x,u,P,M,[1 1],'nocat');
- for i = 1:l
- for j = 1:n
- D{i}(j,:) = dgdxx{j}(i,:);
- end
- end
- for i = 1:l
- L2{i} = spm_cat(spm_diag({0, D{i}}));
- end
-
|