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