-
Notifications
You must be signed in to change notification settings - Fork 7
/
bf_inverse_lcmv_multicov.m
146 lines (110 loc) · 4.48 KB
/
bf_inverse_lcmv_multicov.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
function res = bf_inverse_lcmv_multicov(BF, S)
% Computes LCMV filters using spm_pca_order to constrain inverse of data
% cov matrix. Based on the paper:
% MEG beamforming using Bayesian PCA for adaptive data covariance matrix regularization.
% Woolrich M, Hunt L, Groves A, Barnes G.
% Neuroimage. 2011 Aug 15;57(4)
%
% and allowing for multiple covariance matrices, e.g. associated with
% multiple states:
% Dynamic State Allocation for MEG Source Reconstruction
% Neuroimage. Woolrich et al. 2013.
%
% Mark Woolrich
%--------------------------------------------------------------------------
if nargin == 0
pca_order = cfg_entry;
pca_order.tag = 'pca_order';
pca_order.name = 'PCA order';
pca_order.val = {};
bilateral = cfg_entry;
bilateral.tag = 'bilateral';
bilateral.name = 'Do bilateral beamformer';
bilateral.val = {};
type = cfg_menu;
type.tag = 'type';
type.name = 'Beamformer type';
type.help = {'Select Scalar or Vector'};
type.labels = {'Vector', 'Scalar'};
type.values = {'Vector', 'Scalar'};
type.val = {'Scalar'};
lcmv_multicov = cfg_branch;
lcmv_multicov.tag = 'lcmv_multicov';
lcmv_multicov.name = 'LCMV use multiple covariance and PCA order';
lcmv_multicov.val = {pca_order,bilateral,type};
res = lcmv_multicov;
return
elseif nargin < 2
error('Two input arguments are required');
end
inverse=[];
if isfield(BF.features, S.modality)
%reduce_rank = S.reduce_rank;
reduce_rank = BF.sources.reduce_rank.(S.modality(1:3));
if isfield(BF.features.(S.modality),'class'),
class = BF.features.(S.modality).class;
else
class={};
class{1} = BF.features.(S.modality);
end;
% multiple covariances -do separate weights for each one
for kk=1:length(class),
if ~sum(isnan(squash(class{kk}.C))),
[invCy, pca_order_used] = pinv_plus(class{kk}.C, S.pca_order); % rank maybe not be detected properly by just using pinv - MWW
else
warning(['Nans in covariance matrix for class ' num2str(kk)]);
end;
L = S.L;
W = cell(size(L));
nvert = numel(W);
spm('Pointer', 'Watch');drawnow;
spm_progress_bar('Init', nvert, ['Computing ' S.modality ' filters']); drawnow;
if nvert > 100, Ibar = floor(linspace(1, nvert,100));
else Ibar = 1:nvert; end
for i = 1:nvert
if ~sum(isnan(squash(L{i}))) && ~sum(isnan(squash(class{kk}.C))),
lf = L{i};
lf_single = lf;
do_lat=0;
if S.bilateral, % beamform bilateral dipoles together
if(BF.sources.mni.bilateral_index(i)~=i),
do_lat=1;
lf_lat=L{BF.sources.mni.bilateral_index(i)};
lf=[lf_single, lf_lat];
end;
end;
switch lower(S.type)
case 'scalar'
tmp=lf' * invCy *lf;
nn=size(lf_single,2);
[u, ~] = svd(real(pinv_plus(tmp(1:nn,1:nn),reduce_rank,0)),'econ'); % this is faster, - MWW
eta = u(:,1);
lf_single = lf_single * eta;
if do_lat,
[u, ~] = svd(real(pinv_plus(tmp(nn+1:2*nn,nn+1:2*nn),reduce_rank,0)),'econ'); % this is faster, - MWW
eta = u(:,1);
lf_lat = lf_lat * eta;
lf=[lf_single, lf_lat];
tmp2 = pinv_plus(lf' * invCy * lf) * lf' * invCy;
W{i}=tmp2(1,:);
else
lf=lf_single;
% construct the spatial filter
%W{i} = pinv(lf' * invCy * lf) * lf' * invCy;
W{i} = lf'*invCy/(lf' * invCy * lf); % this is faster - MWW
end;
case 'vector'
W{i} = pinv_plus(lf' * invCy * lf,reduce_rank) * lf' * invCy; % - AB
end
else
W{i} = NaN;
end
if ismember(i, Ibar)
spm_progress_bar('Set', i); drawnow;
end
end
inverse.class{kk}.W = W;
inverse.class{kk}.L = L;
end;
end
res = inverse;