spm_int.m 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. function [y] = spm_int(P,M,U)
  2. % integrates a MIMO bilinear system dx/dt = f(x,u) = A*x + B*x*u + Cu + D;
  3. % FORMAT [y] = spm_int(P,M,U)
  4. % P - model parameters
  5. % M - model structure
  6. % M.delays - sampling delays (s); a vector with a delay for each output
  7. %
  8. % U - input structure or matrix
  9. %
  10. % y - response y = g(x,u,P)
  11. %__________________________________________________________________________
  12. % Integrates the bilinear approximation to the MIMO system described by
  13. %
  14. % dx/dt = f(x,u,P) = A*x + u*B*x + C*u + D
  15. % y = g(x,u,P) = L*x;
  16. %
  17. % at v = M.ns is the number of samples [default v = size(U.u,1)]
  18. %
  19. % spm_int will also handle static observation models by evaluating
  20. % g(x,u,P). It will also handle timing delays if specified in M.delays
  21. %
  22. %--------------------------------------------------------------------------
  23. %
  24. % SPM solvers or integrators
  25. %
  26. % spm_int_ode: uses ode45 (or ode113) which are one and multi-step solvers
  27. % respectively. They can be used for any ODEs, where the Jacobian is
  28. % unknown or difficult to compute; however, they may be slow.
  29. %
  30. % spm_int_J: uses an explicit Jacobian-based update scheme that preserves
  31. % nonlinearities in the ODE: dx = (expm(dt*J) - I)*inv(J)*f. If the
  32. % equations of motion return J = df/dx, it will be used; otherwise it is
  33. % evaluated numerically, using spm_diff at each time point. This scheme is
  34. % infallible but potentially slow, if the Jacobian is not available (calls
  35. % spm_dx).
  36. %
  37. % spm_int_E: As for spm_int_J but uses the eigensystem of J(x(0)) to eschew
  38. % matrix exponentials and inversion during the integration. It is probably
  39. % the best compromise, if the Jacobian is not available explicitly.
  40. %
  41. % spm_int_B: As for spm_int_J but uses a first-order approximation to J
  42. % based on J(x(t)) = J(x(0)) + dJdx*x(t).
  43. %
  44. % spm_int_L: As for spm_int_B but uses J(x(0)).
  45. %
  46. % spm_int_U: like spm_int_J but only evaluates J when the input changes.
  47. % This can be useful if input changes are sparse (e.g., boxcar functions).
  48. % It is used primarily for integrating EEG models
  49. %
  50. % spm_int: Fast integrator that uses a bilinear approximation to the
  51. % Jacobian evaluated using spm_bireduce. This routine will also allow for
  52. % sparse sampling of the solution and delays in observing outputs. It is
  53. % used primarily for integrating fMRI models (see also spm_int_D)
  54. %__________________________________________________________________________
  55. % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
  56. % Karl Friston
  57. % $Id: spm_int.m 6856 2016-08-10 17:55:05Z karl $
  58. % convert U to U.u if necessary
  59. %--------------------------------------------------------------------------
  60. if ~isstruct(U), u.u = U; U = u; end
  61. try, dt = U.dt; catch, U.dt = 1; end
  62. % number of times to sample (v) and number of microtime bins (u)
  63. %--------------------------------------------------------------------------
  64. u = size(U.u,1);
  65. try, v = M.ns; catch, v = u; end
  66. % get expansion point
  67. %--------------------------------------------------------------------------
  68. x = [1; spm_vec(M.x)];
  69. % add [0] states if not specified
  70. %--------------------------------------------------------------------------
  71. try
  72. M.f = spm_funcheck(M.f);
  73. catch
  74. M.f = @(x,u,P,M) sparse(0,1);
  75. M.x = sparse(0,0);
  76. end
  77. % output nonlinearity, if specified
  78. %--------------------------------------------------------------------------
  79. try
  80. g = spm_funcheck(M.g);
  81. catch
  82. g = @(x,u,P,M) x;
  83. M.g = g;
  84. end
  85. % Bilinear approximation (1st order)
  86. %--------------------------------------------------------------------------
  87. [M0,M1] = spm_bireduce(M,P);
  88. m = length(M1); % m inputs
  89. % delays
  90. %--------------------------------------------------------------------------
  91. try
  92. D = max(round(M.delays/U.dt),1);
  93. catch
  94. D = ones(M.l,1)*round(u/v);
  95. end
  96. % Evaluation times (t) and indicator array for inputs (su) and output (sy)
  97. %==========================================================================
  98. % get times that the input changes
  99. %--------------------------------------------------------------------------
  100. i = [1 (1 + find(any(diff(U.u),2))')];
  101. su = sparse(1,i,1,1,u);
  102. % get times that the response is sampled
  103. %--------------------------------------------------------------------------
  104. s = ceil((0:v - 1)*u/v);
  105. for j = 1:M.l
  106. i = s + D(j);
  107. sy(j,:) = sparse(1,i,1:v,1,u);
  108. end
  109. % time in seconds
  110. %--------------------------------------------------------------------------
  111. t = find(su | any(sy));
  112. su = full(su(:,t));
  113. sy = full(sy(:,t));
  114. dt = [diff(t) 0]*U.dt;
  115. % Integrate
  116. %--------------------------------------------------------------------------
  117. y = zeros(M.l,v);
  118. J = M0;
  119. U.u = full(U.u);
  120. for i = 1:length(t)
  121. % input dependent changes in Jacobian
  122. %----------------------------------------------------------------------
  123. if su(:,i)
  124. u = U.u(t(i),:);
  125. J = M0;
  126. for j = 1:m
  127. J = J + u(j)*M1{j};
  128. end
  129. end
  130. % output sampled
  131. %----------------------------------------------------------------------
  132. if any(sy(:,i))
  133. q = spm_unvec(x(2:end),M.x);
  134. q = spm_vec(g(q,u,P,M));
  135. j = find(sy(:,i));
  136. s = sy(j(1),i);
  137. y(j,s) = q(j);
  138. end
  139. % compute updated states x = expm(J*dt)*x;
  140. %----------------------------------------------------------------------
  141. x = spm_expm(J*dt(i),x);
  142. % check for convergence
  143. %----------------------------------------------------------------------
  144. if norm(x,1) > 1e6, break, end
  145. end
  146. y = real(y');