-
Notifications
You must be signed in to change notification settings - Fork 67
/
VBA_simulate.m
211 lines (176 loc) · 5.8 KB
/
VBA_simulate.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
function [y,x,x0,eta,e,u] = VBA_simulate (n_t,f_fname,g_fname,theta,phi,u,alpha,sigma,options,x0,fb)
% samples times series from sDCM generative model
% [y,x,x0,dTime,eta,eta0] =
% VBA_simulate (n_t,f_fname,g_fname,theta,phi,u,alpha,sigma,options,x0)
%
% This function creates the time series of hidden-states and measurements
% under the following nonlinear state-space model:
% x_t = f(x_t-1,Theta,u_t) + f_t
% y_t = g(x_t,Phi,u_t) + e_t
% where f and g are the evolution and observation, respectively.
% IN:
% - n_t: the number of time bins for the time series of hidden-states and
% observations, i.e. the time indices satisfy: 1<= t < n_t
% - f_fname/g_fname: evolution/observation function names.
% - theta/phi: evolution/observation parameters values.
% - u: the mxt input matrix
% - alpha: precision of the stochastic innovations
% - sigma: precision of the measurement error
% - options: structure variable containing the following fields:
% .inF
% .inG
% - x0: the initial conditions
% - fb: an optional feedback struture that contains the following fields:
% .h_fname: the name/handle of the function that implements the
% feedback mapping, i.e. that maps the system's output y_t to its
% feedback h(y_t,t,inH)
% .inH: an optional entry structure for the feedback mapping
% .indy: the vector of indices that are used to address the previous
% system output (y_t-1) within the current input (u_t)
% .indfb: the vector of indices that are used to address the feedback
% h(y_t-1,t-1,inH) to the previous system output within the current
% input (u_t)
% OUT:
% - y: the pxt (noisy) measurement time series
% - x: the nxt (noisy) hidden-states time series
% - x0: the nx1 initial conditions
% - eta: the nxt stochastic innovations time series
% - e: the pxt measurement errors (e:=y-<y>)
% 27/03/2007: JD.
% === Some verifications
try
x0;
n=numel(x0);
catch
try
n = numel(options.priors.muX0);
catch
n = 0;
end
end
feedback = exist('fb','var');
if feedback
try
u(fb.indy,1);
u(fb.indfb,1);
catch
error('*** Simulation with feedback requires allocated inputs');
end
end
% --- check dimensions
options = VBA_check_struct(options, ...
'dim' , struct, ...
'priors', struct ...
) ;
dim = options.dim;
dim = VBA_check_struct(dim, ...
'n_theta' , length(theta) , ...
'n_phi' , length(phi) , ...
'n' , n , ...
'n_t' , n_t ...
);
try, options.inG; catch, options.inG = struct (); end
try, U = u(:,1); catch, U = zeros(size(u,1),1); end
dim.p = size(g_fname(zeros(dim.n,1),phi,U,options.inG),1);
options.dim = dim;
% --- check priors
options.priors = VBA_check_struct (options.priors, ...
'a_alpha', 1, ...
'b_alpha', 1 ...
) ;
if isempty (options.priors.a_alpha) || (isinf (options.priors.a_alpha) && isequal (options.priors.b_alpha, 0))
options.priors.a_alpha = 1;
options.priors.b_alpha = 1;
end
% --- check options
[options, u, dim] = VBA_check (zeros (dim.p, dim.n_t), u, f_fname, g_fname, dim, options);
% === Prepare simulation
% Get covariance structure
iQy = options.priors.iQy;
iQx = options.priors.iQx;
% Get time
et0 = clock;
% pre-allocate variables
x = zeros (dim.n, dim.n_t);
eta = zeros (dim.n, dim.n_t);
e = zeros (dim.p, dim.n_t);
y = zeros (dim.p, dim.n_t);
% muxer
n_sources = numel (options.sources);
sgi = find ([options.sources(:).type] == 0) ;
% === Simulate timeseries
% Initial hidden-states value
if dim.n > 0
try
x0;
assert(~ VBA_isWeird(x0));
catch
x0 = VBA_random ('Gaussian', options.priors.muX0, options.priors.SigmaX0);
end
else
x0 = zeros(dim.n,1);
end
% stack X0
x = [x0 x];
% Display progress
VBA_disp({ ...
'Simulating SDE...' , ...
sprintf('%6.2f %%%%',0) ...
}, options, false);
%-- Loop over time points
for t = 1:dim.n_t
% Evaluate evolution function at past hidden state
if dim.n > 0
% stochastic innovation
Cx = VBA_inv (iQx{t}) / alpha ;
eta(:, t) = VBA_random ('Gaussian', zeros (dim.n, 1), Cx) ;
% evolution
x(:, t + 1) = ...
VBA_evalFun ('f', x(:, t), theta, u(:, t), options, dim, t) ...
+ eta(:, t);
end
% Evaluate observation function at current hidden state
gt = VBA_evalFun ('g', x(:, t + 1), phi, u(:, t), options, dim, t);
for i = 1 : n_sources
s_idx = options.sources(i).out;
switch options.sources(i).type
% gaussian
case 0
C = VBA_inv (iQy{t, sgi == i}) / sigma(sgi == i) ;
y(s_idx,t) = VBA_random ('Gaussian', gt(s_idx), C) ;
% binomial
case 1
y(s_idx, t) = VBA_random ('Bernoulli', gt(s_idx));
% multinomial
case 2
y(s_idx, t) = VBA_random ('Multinomial', 1, gt(s_idx));
end
end
e(:,t) = y(:,t) - gt;
% fill in next input with last output and feedback
if feedback && t < dim.n_t
% get feedback on system's output
if ~ isempty (fb.h_fname)
u(fb.indfb, t + 1) = fb.h_fname (y(:, t), t, fb.inH);
end
u(fb.indy, t + 1) = y(:, t);
end
% Display progress
if mod(100*t/dim.n_t,10) <1
VBA_disp({ ...
repmat('\b',1,8) , ...
sprintf('%6.2f %%%%',floor(100*t/dim.n_t)), ...
}, options, false);
end
end
%unstack X0
x(:, 1) = [];
% checks
if VBA_isWeird (x)
error('VBA_simulate: evolution function produced weird values!');
end
% Display progress
VBA_disp({ ...
repmat('\b',1,8) ,...
[' OK (took ',num2str(etime(clock,et0)),' seconds).'] ...
},options);