-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspm_soreduce.m
133 lines (111 loc) · 3.87 KB
/
spm_soreduce.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
function [M0,M1,M2,L1,L2] = spm_soreduce(M,P)
% reduction of a fully nonlinear MIMO system to second-order form
% FORMAT [M0,M1,M2,L1,L2] = spm_soreduce(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.x - (n x 1) = x(0) = expansion point: defaults to x = 0;
% M.u - (m x 1) = u = expansion point: defaults to u = 0;
%
% P - model parameters
%
% A second order 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 + ....
% x(1)*M2{1}*q + x(2)*M2{2}*q + ....
% y(i) = L(i,:)*q + ...
%
%--------------------------------------------------------------------------
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
% Karl Friston
% $Id: spm_soreduce.m 5219 2013-01-29 17:07:07Z spm $
% 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
% 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 = M.n;
fung = fcnchk(M.g,'x','u','P','M');
end
% expansion pointt
%--------------------------------------------------------------------------
x = 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
%--------------------------------------------------------------------------
[dfdxx,dfdx,f0] = spm_diff(funx,x,u,P,M,[1 1]);
[dfdxu,dfdx,f0] = spm_diff(funx,x,u,P,M,[1 2]);
dfdu = spm_diff(funx,x,u,P,M,2);
m = length(dfdxu); % m inputs
n = length(f0); % n states
% Bilinear operators
%==========================================================================
% Bilinear operator - M0
%--------------------------------------------------------------------------
M0 = spm_cat({0 [] ;
(f0 - dfdx*spm_vec(x)) dfdx});
% Bilinear operator - M1 = dM0/du
%--------------------------------------------------------------------------
for i = 1:m
M1{i} = spm_cat({0, [] ;
(dfdu(:,i) - dfdxu{i}*spm_vec(x)), dfdxu{i}});
end
% Bilinear operator - M2 = dM0/dx
%--------------------------------------------------------------------------
for i = 1:n
M2{i} = spm_cat({0, [] ;
(dfdx(:,i) - dfdxx{i}*spm_vec(x)), dfdxx{i}});
end
if nargout < 4, return, end
% Output matrices - L1
%==========================================================================
% l(x(0),0)
%--------------------------------------------------------------------------
[dgdx,g0] = spm_diff(fung,x,u,P,M,1);
L1 = spm_cat({(g0 - dgdx*spm_vec(x)), dgdx});
l = length(g0);
if nargout < 5, return, end
% Output matrices - L2
%--------------------------------------------------------------------------
dgdxx = spm_diff(fung,x,u,P,M,[1 1]);
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