-
Notifications
You must be signed in to change notification settings - Fork 27
/
limo_eeglab2fieldtrip.m
277 lines (257 loc) · 9.47 KB
/
limo_eeglab2fieldtrip.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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
function [data] = limo_eeglab2fieldtrip(EEG, fieldbox, transform)
% LIMO_EEGLAB2FIELDTRIP converts an EEGLAB data structure into a FieldTrip data
% structure, which subsequently can be used for dipole fitting and other
% FieldTrip analysis methods.
%
% Use as
% [data] = eeglab2fieldtrip( EEG, fieldbox )
% or
% [data] = eeglab2fieldtrip( EEG, fieldbox, transform )
%
% where the inputs are
% EEG - [struct] EEGLAB structure
% fieldbox - ['preprocessing'|'timelockanalysis'|'componentanalysis'|...
% 'chanloc', 'chanloc_withfid']
% transform - ['none'|'dipfit'] transform channel locations for DIPFIT
% using the transformation matrix in the field 'coord_transform'
% of the dipfit substructure of the EEG structure.
%
% The output is a structure that is compatible with the FieldTrip functions
% PREPROCESSING, TIMELOCKANALYSIS, COMPONENTANALYSIS, or only containing an
% electrode definition.
% Copyright (C) 2004-2006, Robert Oostenveld, FCDC
% Copyright (C) 2004-2006, Arnaud Delorme, SCCN, INC, UCSD
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
% $Log: eeglab2fieldtrip.m,v $
% Revision 1.14 2007/07/07 12:10:00 roboos
% detect matlab version 7.0.1 and 7.0.4 and treat as 7.0
%
% Revision 1.13 2006/12/07 08:37:32 roboos
% compute component activations from only those channels used in the ICA
%
% Revision 1.12 2006/11/23 11:18:42 roboos
% moved the naming of channel labels into the switch (to avoid confusion with componentanalys fieldbox), fixed non-string channel labels (now using sprintf)
%
% Revision 1.11 2006/11/23 10:40:38 roboos
% Arno fixed an important bug how single trials component activation was
% computed (sphering was forgotten). Restructured help
%
% Revision 1.10 2006/11/23 10:15:00 roboos
% Use numeric channel labels if no chanlocs are present. Removed fieldtripchan2eeglab subfunction, since it was not used any more.
%
% Revision 1.9 2006/10/05 09:45:11 roboos
% included matlabversion as subfunction
%
% Revision 1.8 2006/10/05 09:39:56 roboos
% fixes an important bug when you do not use all the channels to run ica (arno),
% included the fixprecision function as subfunction
%
% Revision 1.7 2006/05/29 08:41:22 roboos
% ensure that data is double precision for matlab versions<7
% ensure that labels are returned as a column (thanks to Theresa)
%
% Revision 1.6 2006/04/20 09:58:34 roboos
% updated documentation
%
% Revision 1.5 2006/04/13 09:09:08 roboos
% get the precomputed activations if possible, or alternatively compute them
%
% Revision 1.4 2006/03/20 08:20:41 roboos
% added ; to the end of a line (thanks to arno)
%
% Revision 1.3 2006/02/27 10:02:08 roboos
% added optional transform for channel locations
% added fiducials to channel locations
%
% Revision 1.1 2006/01/20 23:43:18 arno
% Initial revision
%
% renamed for integration in LIMO toolbox: GAR, University of Glasgow, June
% ------------------------------
% Copyright (C) LIMO Team 2019
if nargin < 2
help eeglab2fieldtrip
return;
end;
% start with an empty data object
data = [];
if strcmpi(fieldbox, 'chanloc_withfid')
% also insert the non-data channels (i.e. fiducials) in channel structure
if isfield(EEG.chaninfo, 'nodatchans')
chanlen = length(EEG.chanlocs);
fields = fieldnames( EEG.chaninfo.nodatchans );
for index = 1:length(EEG.chaninfo.nodatchans)
ind = chanlen+index;
for f = 1:length( fields )
EEG.chanlocs = setfield(EEG.chanlocs, { ind }, fields{f}, ...
getfield( EEG.chaninfo.nodatchans, { index }, fields{f}));
end
end
end
end
% get the electrode positions from the EEG structure: in principle, the number of
% channels can be more or less than the number of channel locations, i.e. not
% every channel has a position, or the potential was not measured on every
% position. This is not supported by EEGLAB, but it is supported by FIELDTRIP.
Nchan = length(EEG.chanlocs);
data.elec.pnt = zeros(Nchan,3);
data.elec.label = cell(Nchan,1);
for ind = 1:length( EEG.chanlocs )
data.elec.label{ind} = EEG.chanlocs(ind).labels;
if ~isempty(EEG.chanlocs(ind).X)
% this channel has a position
data.elec.pnt(ind,1) = EEG.chanlocs(ind).X;
data.elec.pnt(ind,2) = EEG.chanlocs(ind).Y;
data.elec.pnt(ind,3) = EEG.chanlocs(ind).Z;
else
% this channel does not have a position
data.elec.pnt(ind,:) = [0 0 0];
end;
end;
if nargin > 2
if strcmpi(transform, 'dipfit')
if ~isempty(EEG.dipfit.coord_transform)
disp('Transforming electrode coordinates to match head model');
transfmat = traditional(EEG.dipfit.coord_transform);
data.elec.pnt = transfmat * [ data.elec.pnt ones(size(data.elec.pnt,1),1) ]';
data.elec.pnt = data.elec.pnt(1:3,:)';
else
disp('Warning: no transformation of electrode coordinates to match head model');
end;
end;
end;
switch fieldbox
case { 'chanloc' 'chanloc_withfid' }
% these have already been processed above
case 'preprocessing'
for index = 1:EEG.trials
data.trial{index} = fixprecision(EEG.data(:,:,index));
data.time{index} = linspace(EEG.xmin, EEG.xmax, EEG.pnts);
end;
if ~isempty(EEG.chanlocs)
% use the channel labels from the EEG structure
data.label = { EEG.chanlocs(1:EEG.nbchan).labels };
else
% construct channel names on the fly
for i=1:EEG.nbchan
data.label{i} = sprintf('chan%03d', i);
end
end
data.label = data.label(:);
data.fsample = EEG.srate;
case 'timelockanalysis'
data.avg = mean(fixprecision(EEG.data), 3);
data.var = std(fixprecision(EEG.data), [], 3).^2;
data.time = linspace(EEG.xmin, EEG.xmax, EEG.pnts);
data.dimord = 'chan_time';
if ~isempty(EEG.chanlocs)
% use the channel labels from the EEG structure
data.label = { EEG.chanlocs(1:EEG.nbchan).labels };
else
% construct channel names on the fly
for i=1:EEG.nbchan
data.label{i} = sprintf('chan%03d', i);
end
end
data.label = data.label(:);
data.fsample = EEG.srate;
case 'componentanalysis'
try,
for index = 1:EEG.trials
% the trials correspond to the raw data trials, except that they contain the component activations
if isempty(EEG.icaact)
data.trial{index} = fixprecision(EEG.icaweights*EEG.icasphere*EEG.data(EEG.icachansind,:,index));
else
data.trial{index} = EEG.icaact(:,:,index);
end;
data.time{index} = linspace(EEG.xmin, EEG.xmax, EEG.pnts); % should be checked in FIELDTRIP
end;
catch, end;
for comp = 1:size(EEG.icawinv,2)
% the labels correspond to the component activations that are stored in data.trial
data.label{comp} = sprintf('ica%03d', comp);
end
% get the spatial distribution and electrode positions
data.topolabel = { EEG.chanlocs(EEG.icachansind).labels };
data.topo = fixprecision(EEG.icawinv);
% ensure that the labels are in colunms
data.label = data.label(:);
data.topolabel = data.topolabel(:);
case 'freqanalysis'
error('freqanalysis fieldbox not implemented yet')
otherwise
error('unsupported fieldbox')
end
try
% get the full name of the function
data.cfg.version.name = mfilename('fullpath');
catch
% required for compatibility with Matlab versions prior to release 13 (6.5)
[st, i] = dbstack;
data.cfg.version.name = st(i);
end
% add the version details of this function call to the configuration
data.cfg.version.id = '$Id: eeglab2fieldtrip.m,v 1.14 2007/07/07 12:10:00 roboos Exp $';
return
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIXPRECISION ensures that the data matrix has a numeric precision that is
% supported by the Matlab version
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [x] = fixprecision(x, precision);
if nargin<2
if matlabversion<7
% Matlab versions prior to 7.0 cannot perform computations on single
% precision numbers
precision = 'double';
else
precision = class(x);
end
end
if ~strcmp(class(x), precision)
% conversion is needed
switch precision
case 'single'
x = single(x);
case 'double'
x = double(x);
otherwise
error('unsupported numeric precision');
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLABVERSION returns the Matlab version as a number
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [v] = matlabversion;
s = ver('matlab');
v = s.Version;
if ischar(v)
% try converting to a number
n = str2num(v);
if isempty(n)
switch v
case '6.5.1'
n = 6.5; % this is accurate enough
case '7.0.1'
n = 7.0; % this is accurate enough
case '7.0.4'
n = 7.0; % this is accurate enough
otherwise
warning('cannot convert matlab version into a number');
v = v;
end
end
v = n;
end