spm_bireduce.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. function [M0,M1,L1,L2] = spm_bireduce(M,P)
  2. % reduction of a fully nonlinear MIMO system to Bilinear form
  3. % FORMAT [M0,M1,L1,L2] = spm_bireduce(M,P);
  4. %
  5. % M - model specification structure
  6. % Required fields:
  7. % M.f - dx/dt = f(x,u,P,M) {function string or m-file}
  8. % M.g - y(t) = g(x,u,P,M) {function string or m-file}
  9. % M.bi - bilinear form [M0,M1,L1,L2] = bi(M,P) {function string or m-file}
  10. % M.m - m inputs
  11. % M.n - n states
  12. % M.l - l outputs
  13. % M.x - (n x 1) = x(0) = expansion point: defaults to x = 0;
  14. % M.u - (m x 1) = u = expansion point: defaults to u = 0;
  15. %
  16. % M.D - delay operator df/dx -> D*df/dx [optional]
  17. %
  18. % P - model parameters
  19. %
  20. % A Bilinear approximation is returned where the states are
  21. %
  22. % q(t) = [1; x(t) - x(0)]
  23. %
  24. %___________________________________________________________________________
  25. % Returns Matrix operators for the Bilinear approximation to the MIMO
  26. % system described by
  27. %
  28. % dx/dt = f(x,u,P)
  29. % y(t) = g(x,u,P)
  30. %
  31. % evaluated at x(0) = x and u = 0
  32. %
  33. % dq/dt = M0*q + u(1)*M1{1}*q + u(2)*M1{2}*q + ....
  34. % y(i) = L1(i,:)*q + q'*L2{i}*q/2;
  35. %
  36. %--------------------------------------------------------------------------
  37. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  38. % Karl Friston
  39. % $Id: spm_bireduce.m 6856 2016-08-10 17:55:05Z karl $
  40. % set up
  41. %==========================================================================
  42. % create inline functions
  43. %--------------------------------------------------------------------------
  44. try
  45. funx = fcnchk(M.f,'x','u','P','M');
  46. catch
  47. M.f = inline('sparse(0,1)','x','u','P','M');
  48. M.n = 0;
  49. M.x = sparse(0,0);
  50. funx = fcnchk(M.f,'x','u','P','M');
  51. end
  52. % expansion point
  53. %--------------------------------------------------------------------------
  54. x = spm_vec(M.x);
  55. try
  56. u = spm_vec(M.u);
  57. catch
  58. u = sparse(M.m,1);
  59. end
  60. % Partial derivatives for 1st order Bilinear operators
  61. %==========================================================================
  62. % f(x(0),0) and derivatives
  63. %--------------------------------------------------------------------------
  64. if all(isfield(M,{'dfdxu','dfdx','dfdu','f0'}))
  65. dfdxu = M.dfdxu;
  66. dfdx = M.dfdx;
  67. dfdu = M.dfdu;
  68. f0 = M.f0;
  69. else
  70. [dfdxu,dfdx] = spm_diff(funx,M.x,u,P,M,[1 2]);
  71. [dfdu, f0] = spm_diff(funx,M.x,u,P,M,2);
  72. end
  73. f0 = spm_vec(f0);
  74. m = length(dfdxu); % m inputs
  75. n = length(f0); % n states
  76. % delay operator
  77. %--------------------------------------------------------------------------
  78. if isfield(M,'D')
  79. f0 = M.D*f0;
  80. dfdx = M.D*dfdx;
  81. dfdu = M.D*dfdu;
  82. for i = 1:m
  83. dfdxu{i} = M.D*dfdxu{i};
  84. end
  85. end
  86. % Bilinear operators
  87. %==========================================================================
  88. % Bilinear operator - M0
  89. %--------------------------------------------------------------------------
  90. M0 = spm_cat({0 [] ;
  91. (f0 - dfdx*x) dfdx});
  92. % Bilinear operator - M1 = dM0/du
  93. %--------------------------------------------------------------------------
  94. M1 = cell(m,1);
  95. for i = 1:m
  96. M1{i} = spm_cat({0, [] ;
  97. (dfdu(:,i) - dfdxu{i}*x), dfdxu{i}});
  98. end
  99. if nargout < 3, return, end
  100. % Output operators
  101. %==========================================================================
  102. % add observer if not specified
  103. %--------------------------------------------------------------------------
  104. try
  105. fung = fcnchk(M.g,'x','u','P','M');
  106. catch
  107. M.g = inline('spm_vec(x)','x','u','P','M');
  108. M.l = n;
  109. fung = fcnchk(M.g,'x','u','P','M');
  110. end
  111. % g(x(0),0)
  112. %--------------------------------------------------------------------------
  113. [dgdx,g0] = spm_diff(fung,M.x,u,P,M,1);
  114. g0 = spm_vec(g0);
  115. l = length(g0);
  116. % Output matrices - L1
  117. %--------------------------------------------------------------------------
  118. L1 = spm_cat({(spm_vec(g0) - dgdx*x), dgdx});
  119. if nargout < 4, return, end
  120. % Output matrices - L2
  121. %--------------------------------------------------------------------------
  122. dgdxx = spm_diff(fung,M.x,u,P,M,[1 1],'nocat');
  123. for i = 1:l
  124. for j = 1:n
  125. D{i}(j,:) = dgdxx{j}(i,:);
  126. end
  127. end
  128. for i = 1:l
  129. L2{i} = spm_cat(spm_diag({0, D{i}}));
  130. end