function [data] = eeglab2fieldtrip(EEG, fieldbox, transform) % 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.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 % if nargin < 2 help eeglab2fieldtrip return; end; % start with an empty data object data = []; % add the objects that are common to all fieldboxes if ~isempty(EEG.chanlocs) data.label = { EEG.chanlocs(1:EEG.nbchan).labels }; else data.label = num2cell(1:EEG.nbchan); end data.label = data.label(:); data.fsample = EEG.srate; 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; 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'; 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(:,:,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.11 2006/11/23 10:40:38 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' % this is accurate enough n = 6.5; otherwise warning('cannot convert matlab version into a number'); v = v; end end v = n; end