spm_int_E.m 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. function [y] = spm_int_E(P,M,U)
  2. % integrates a MIMO nonlinear system using a bilinear eigenreduced Jacobian
  3. % FORMAT [y] = spm_int_E(P,M,U)
  4. % P - model parameters
  5. % M - model structure
  6. % U - input structure or matrix
  7. %
  8. % y - (v x l) response y = g(x,u,P)
  9. %__________________________________________________________________________
  10. %
  11. % Integrates the MIMO system described by
  12. %
  13. % dx/dt = f(x,u,P,M)
  14. % y = g(x,u,P,M)
  15. %
  16. % using the update scheme:
  17. %
  18. % x(t + dt) = x(t) + U*dx(t)/dt
  19. %
  20. % U = (expm(dt*J) - I)*inv(J)
  21. % J = df/dx
  22. %
  23. % at input times. This integration scheme evaluates the update matrix (Q)
  24. % at each time point
  25. %
  26. %--------------------------------------------------------------------------
  27. %
  28. % SPM solvers or integrators
  29. %
  30. % spm_int_ode: uses ode45 (or ode113) which are one and multi-step solvers
  31. % respectively. They can be used for any ODEs, where the Jacobian is
  32. % unknown or difficult to compute; however, they may be slow.
  33. %
  34. % spm_int_J: uses an explicit Jacobian-based update scheme that preserves
  35. % nonlinearities in the ODE: dx = (expm(dt*J) - I)*inv(J)*f. If the
  36. % equations of motion return J = df/dx, it will be used; otherwise it is
  37. % evaluated numerically, using spm_diff at each time point. This scheme is
  38. % infallible but potentially slow, if the Jacobian is not available (calls
  39. % spm_dx).
  40. %
  41. % spm_int_E: As for spm_int_J but uses the eigensystem of J(x(0)) to eschew
  42. % matrix exponentials and inversion during the integration. It is probably
  43. % the best compromise, if the Jacobian is not available explicitly.
  44. %
  45. % spm_int_B: As for spm_int_J but uses a first-order approximation to J
  46. % based on J(x(t)) = J(x(0)) + dJdx*x(t).
  47. %
  48. % spm_int_L: As for spm_int_B but uses J(x(0)).
  49. %
  50. % spm_int_U: like spm_int_J but only evaluates J when the input changes.
  51. % This can be useful if input changes are sparse (e.g., boxcar functions).
  52. %
  53. % spm_int: Fast integrator that uses a bilinear approximation to the
  54. % Jacobian evaluated using spm_bireduce. This routine will also allow for
  55. % sparse sampling of the solution and delays in observing outputs. It is
  56. % used primarily for integrating fMRI models
  57. %___________________________________________________________________________
  58. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  59. % Karl Friston
  60. % $Id: spm_int_E.m 5219 2013-01-29 17:07:07Z spm $
  61. % convert U to U.u if necessary
  62. %--------------------------------------------------------------------------
  63. if ~isstruct(U)
  64. u.u = U;
  65. U = u;
  66. end
  67. try
  68. dt = U.dt;
  69. catch
  70. dt = 1;
  71. end
  72. try
  73. ns = M.ns;
  74. catch
  75. ns = length(U.u);
  76. end
  77. % state equation; add [0] states if not specified
  78. %--------------------------------------------------------------------------
  79. try
  80. f = fcnchk(M.f,'x','u','P','M');
  81. catch
  82. f = inline('sparse(0,1)','x','u','P','M');
  83. M.n = 0;
  84. M.x = sparse(0,0);
  85. end
  86. % and output nonlinearity
  87. %--------------------------------------------------------------------------
  88. try
  89. g = fcnchk(M.g,'x','u','P','M');
  90. end
  91. % Initial states and inputs
  92. %--------------------------------------------------------------------------
  93. u = U.u(1,:);
  94. try
  95. x = M.x;
  96. catch
  97. x = sparse(0,1);
  98. M.x = x;
  99. end
  100. % check for delay operator
  101. %--------------------------------------------------------------------------
  102. try
  103. [fx,dfdx D] = f(x,u,P,M);
  104. catch
  105. D = 1;
  106. end
  107. % get Jacobian and its derivatives
  108. %--------------------------------------------------------------------------
  109. [dJdx,J] = spm_diff(f,x,u,P,M,[1 1]);
  110. [dJdu,J] = spm_diff(f,x,u,P,M,[1 2]);
  111. % eigensytem
  112. %--------------------------------------------------------------------------
  113. [V,S] = eig(full(D*J));
  114. i = find(diag(abs(real(S))) > exp(-16));
  115. V = V(:,i);
  116. S = S(i,i);
  117. iV = pinv(V);
  118. J = diag(S);
  119. for i = 1:length(dJdx)
  120. dJdx{i} = diag(iV*D*dJdx{i}*V);
  121. end
  122. for i = 1:length(dJdu)
  123. dJdu{i} = diag(iV*D*dJdu{i}*V);
  124. end
  125. % integrate
  126. %==========================================================================
  127. x0 = spm_vec(M.x);
  128. I = speye(length(J));
  129. for i = 1:ns
  130. % input
  131. %----------------------------------------------------------------------
  132. u = U.u(i,:);
  133. % motion
  134. %----------------------------------------------------------------------
  135. fx = f(x,u,P,M);
  136. % dx(t)/dt and Jacobian df/dx
  137. %----------------------------------------------------------------------
  138. dx = spm_vec(x) - x0;
  139. dfdx = J;
  140. for j = 1:length(dJdx)
  141. dfdx = dfdx + dJdx{j}*dx(j);
  142. end
  143. for j = 1:length(dJdu)
  144. dfdx = dfdx + dJdu{j}*u(j);
  145. end
  146. % update dx = (expm(dt*J) - I)*inv(J)*fx
  147. %----------------------------------------------------------------------
  148. dx = V*diag( (exp(dfdx*dt) - 1)./dfdx )*iV*D*fx;
  149. x = spm_unvec(spm_vec(x) + real(dx),x);
  150. % output - implement g(x)
  151. %----------------------------------------------------------------------
  152. try
  153. y(:,i) = spm_vec(g(x,u,P,M));
  154. catch
  155. y(:,i) = spm_vec(x);
  156. end
  157. end
  158. % transpose
  159. %--------------------------------------------------------------------------
  160. y = real(y');