Skip to content

Commit 5135107

Browse files
committed
ENH - updates and fixes
1 parent 819ac65 commit 5135107

11 files changed

+876
-6
lines changed

ni2_headmodel.m

+2
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
headmodel.r = 10;
2323
headmodel.c = 1;
2424
headmodel.unit = 'cm';
25+
headmodel.type = 'singlesphere';
2526
headmodel = ft_datatype_headmodel(headmodel);
2627
case 3
2728
headmodel.o = [0 0 0];
2829
headmodel.r = [0.88 0.92 1.00]*10;
2930
headmodel.c = [1 1/80 1];
3031
headmodel.unit = 'cm';
32+
headmodel.type = 'concentricspheres';
3133
headmodel = ft_datatype_headmodel(headmodel);
3234
otherwise
3335
error('number of spheres other than 1 or 3 is not supported');

ni2_leadfield.m

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
cfg.grad = sens;
3030
end
3131
cfg.headmodel = headmodel;
32-
cfg.grid.pos = dippar(:,1:3);
33-
cfg.grid.inside = 1:ndip;
34-
cfg.grid.unit = headmodel.unit;
32+
cfg.sourcemodel.pos = dippar(:,1:3);
33+
cfg.sourcemodel.inside = 1:ndip;
34+
cfg.sourcemodel.unit = headmodel.unit;
3535
cfg.reducerank = 'no';
3636
if strcmp(headmodel.type, 'singleshell')
3737
cfg.singleshell.batchsize = 2500;

ni2_sensors.m

+13-3
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,24 @@
1212
% array.
1313

1414

15-
type = ft_getopt(varargin, 'type', 'eeg');
15+
type = ft_getopt(varargin, 'type', 'eeg');
16+
jitter = ft_getopt(varargin, 'jitter', 0);
17+
n = ft_getopt(varargin, 'n', 162); % number of vertices for the sphere, determines the number of electrodes, this is the old default
1618

1719
switch type
1820
case 'eeg'
1921
% create an eeg electrode array
20-
[chanpos, tri] = icosahedron162;
22+
[chanpos, tri] = mesh_sphere(n);
2123
chanpos = chanpos*10;
2224
chanpos(chanpos(:,3)<0,:) = [];
2325

26+
if jitter
27+
[th,phi,r] = cart2sph(chanpos(:,1), chanpos(:,2), chanpos(:,3));
28+
shift1 = 2*jitter*(rand(numel(th),1) - 1);
29+
shift2 = 2*jitter*(rand(numel(phi),1) - 1);
30+
[chanpos(:,1),chanpos(:,2),chanpos(:,3)] = sph2cart(th+shift1(:),phi+shift2(:),r);
31+
end
32+
2433
sens.chanpos = chanpos;
2534
sens.elecpos = chanpos;
2635
for k = 1:size(chanpos,1)
@@ -29,6 +38,7 @@
2938
end
3039
sens = ft_datatype_sens(sens);
3140

41+
3242
case {'meg_mag' 'meg'}
3343
% create an meg magnetometer array
3444
[chanpos, tri] = icosahedron642;
@@ -78,7 +88,7 @@
7888
% not implemented yet
7989
case 'meg_ctf275'
8090
load('ctf275');
81-
case 'meg_ctf151'
91+
case 'meg_ctf151'
8292
load('ctf151');
8393
case 'meg_bti248'
8494
load('bti248');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
% create some data
2+
[S,time] = ni2_activation;
3+
sens = ni2_sensors('type','eeg','n',64);
4+
5+
% in order to fool around with the reference of the leadfield, we need to
6+
% add an explicit 'tra', otherwise ft_compute_leadfield will subtract the
7+
% mean by default. By adding a tra as Identity matrix, the leadfields will
8+
% be returned 'without' reference. Here we add a reference on the left, 'eeg74'
9+
ref = 25;
10+
sens.tra = eye(numel(sens.label));
11+
sens.tra(:,ref) = sens.tra(:,ref)-1;
12+
13+
% create a volume conductor model
14+
headmodel = ni2_headmodel('type', 'spherical', 'nshell', 3);
15+
16+
% create a 3D grid for the initial gridsearch
17+
sourcemodel = ni2_sourcemodel('type','grid','resolution',1);
18+
19+
% simulate some sensor level data
20+
dippar = [-8./sqrt(2) 0.5 8./sqrt(2) [1 1 1].*(3^(-1/3))];
21+
leadfield = ni2_leadfield(sens, headmodel, dippar);
22+
noise = sens.tra*randn(numel(sens.label),1000)*1e-3;
23+
sensordata = leadfield*S+noise;
24+
assert(all(sensordata(ref,:)==0));
25+
26+
% visualize it
27+
topo_observed = sensordata(:,500);
28+
ni2_topoplot(sens, topo_observed);
29+
30+
data = [];
31+
data.avg = sensordata;
32+
data.time = time;
33+
data.label = sens.label;
34+
data.elec = sens;
35+
data.dimord ='chan_time';
36+
37+
% this is what I think Sarang means, i.e. data with an implicitref present,
38+
% and then svd'ed in order to remove the last component
39+
[u,s,v] = svd(data.avg, 'econ');
40+
montage2.tra = u(:,1:end-1)';
41+
montage2.labelold = data.label;
42+
for k = 1:size(montage2.tra,1)
43+
montage2.labelnew{k,1} = sprintf('comp%02d',k);
44+
end
45+
data_svd = ft_apply_montage(data, montage2);
46+
data_svd.elec = ft_apply_montage(data.elec, montage2);
47+
48+
% this is the data with the reference channel removed
49+
cfg = [];
50+
cfg.channel = data.label;
51+
cfg.channel(ref) = [];
52+
data = ft_selectdata(cfg, data);
53+
54+
% do some referencing by hand to obtain the average referenced data
55+
montage1.tra = eye(numel(data.label))- ones(numel(data.label))./numel(data.label);
56+
montage1.labelold = data.label;
57+
montage1.labelnew = data.label;
58+
data_avg = ft_apply_montage(data, montage1);
59+
data_avg.elec = ft_apply_montage(data.elec, montage1);
60+
61+
cfg = [];
62+
cfg.gridsearch = 'yes';
63+
cfg.model = 'regional';
64+
cfg.headmodel = headmodel;
65+
cfg.sourcemodel = sourcemodel;
66+
cfg.latency = [0.49 0.51];
67+
cfg.nonlinear = 'yes';
68+
cfg.numdipoles = 1;
69+
dip = ft_dipolefitting(cfg, data);
70+
dip_avg = ft_dipolefitting(cfg, data_avg);
71+
dip_svd = ft_dipolefitting(cfg, data_svd);
72+
73+
%ni2_topoplot(sens,dip.Vmodel(:,6));
74+
%ni2_topoplot(sens,dip.Vdata(:,6));
75+
76+
sens_jittered = ni2_sensors('type', 'eeg', 'jitter', 0.1, 'n', 64);
77+
78+
dataj = data;
79+
dataj_avg = data_avg;
80+
dataj_svd = data_svd;
81+
82+
dataj.elec.elecpos = sens_jittered.chanpos;
83+
dipj = ft_dipolefitting(cfg, dataj);
84+
dataj_avg.elec.elecpos = sens_jittered.chanpos;
85+
dipj_avg = ft_dipolefitting(cfg, dataj_avg);
86+
dataj_svd.elec.elecpos = sens_jittered.chanpos;
87+
dipj_svd = ft_dipolefitting(cfg, dataj_svd);
88+

0 commit comments

Comments
 (0)