12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636 |
- % EEG = eeg_SASICA(EEG,cfg)
- %
- % Suggest components to reject from an EEG dataset with ICA decomposition.
- %
- % Inputs: EEG: EEGlab structure with ICA fields.
- % cfg: structure describing which methods are to use for suggesting
- % bad components (see structure called def, in the code below)
- % Available methods are:
- % Autocorrelation: detects noisy components with weak
- % autocorrelation (muscle artifacts usually)
- % Focal components: detects components that are too focal and
- % thus unlikely to correspond to neural
- % activity (bad channel or muscle usually).
- % Focal trial activity: detects components with focal trial
- % activity, with same algorhithm as focal
- % components above. Results similar to trial
- % variability.
- % Signal to noise ratio: detects components with weak signal
- % to noise ratio between arbitrary baseline
- % and interest time windows.
- % Dipole fit residual variance: detects components with high
- % residual variance after subtraction of the
- % forward dipole model. Note that the inverse
- % dipole modeling using DIPFIT2 in EEGLAB
- % must have been computed to use this
- % measure.
- % EOG correlation: detects components whose time course
- % correlates with EOG channels.
- % Bad channel correlation: detects components whose time course
- % correlates with any channel(s).
- % ADJUST selection: use ADJUST routines to select components
- % (see Mognon, A., Jovicich, J., Bruzzone,
- % L., & Buiatti, M. (2011). ADJUST: An
- % automatic EEG artifact detector based on
- % the joint use of spatial and temporal
- % features. Psychophysiology, 48(2), 229-240.
- % doi:10.1111/j.1469-8986.2010.01061.x)
- % FASTER selection: use FASTER routines to select components
- % (see Nolan, H., Whelan, R., & Reilly, R. B.
- % (2010). FASTER: Fully Automated Statistical
- % Thresholding for EEG artifact Rejection.
- % Journal of Neuroscience Methods, 192(1),
- % 152-162. doi:16/j.jneumeth.2010.07.015)
- % MARA selection: use MARA classification engine to select components
- % (see Winkler I, Haufe S, Tangermann M.
- % 2011. Automatic Classification of
- % Artifactual ICA-Components for Artifact
- % Removal in EEG Signals. Behavioral and
- % Brain Functions. 7:30.)
- %
- % Options: noplot: just compute and store result in EEG. Do
- % not make any plots.
- %
- % If you use this program in your research, please cite the following
- % article:
- % Chaumon M, Bishop DV, Busch NA. A Practical Guide to the Selection of
- % Independent Components of the Electroencephalogram for Artifact
- % Correction. Journal of neuroscience methods. 2015
- %
- % SASICA is a software that helps select independent components of
- % the electroencephalogram based on various signal measures.
- % Copyright (C) 2014 Maximilien Chaumon
- %
- % 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 3 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, see <http://www.gnu.org/licenses/>.
- function [EEG, cfg,h] = myeeg_SASICA(EEG,cfg)
- if nargin < 1
- error('Need at least one input argument')
- end
- % deal with calling pop_prop_ADJ or pop_prop_FST here
- if ischar(cfg) && strncmp(cfg,'pop_prop',8)
- [~,h,EEG] = evalc(cfg);
- return
- end
- if ~exist('cfg','var')
- cfg = struct;
- end
- %
- PLOTPERFIG = 35;
- % get SASICA defs
- % def = SASICA('getdefs');
- def.autocorr.enable = true;
- def.autocorr.dropautocorr = 'auto';
- def.autocorr.autocorrint = 20;% will compute autocorrelation with this many milliseconds lag
- def.focalcomp.enable = true;
- def.focalcomp.focalICAout = 'auto';
- def.trialfoc.enable = true;
- def.trialfoc.focaltrialout = 'auto';
- def.resvar.enable = false;
- def.resvar.thresh = 15;% %residual variance allowed
- def.SNR.enable = false;
- def.SNR.snrPOI = [0 Inf];% period of interest (signal)
- def.SNR.snrBL = [-Inf 0];% period of no interest (noise)
- def.SNR.snrcut = 1;% SNR below this threshold will be dropped
- def.EOGcorr.enable = true;
- def.EOGcorr.corthreshV = 'auto 4';% threshold correlation with vertical EOG
- def.EOGcorr.Veogchannames = [];% vertical channel(s)
- def.EOGcorr.corthreshH = 'auto 4';% threshold correlation with horizontal EOG
- def.EOGcorr.Heogchannames = [];% horizontal channel(s)
- def.chancorr.enable = false;
- def.chancorr.corthresh = 'auto 4';% threshold correlation
- def.chancorr.channames = [];% channel(s)
- def.FASTER.enable = true;
- def.FASTER.blinkchans = [];
- def.ADJUST.enable = true;
- def.MARA.enable = false;
- def.opts.FontSize = 14;
- def.opts.noplot = 0;
- cfg = setdef(cfg,def);
- if isempty(EEG.icawinv)
- errordlg('No ica weights in the current EEG dataset! Compute ICA on your data first.')
- error('No ica weights! Compute ICA on your data first.')
- end
- struct2ws(cfg.opts);
- rejfields = {'icarejautocorr' 'Autocorrelation' [ 0 0 1.0000]
- 'icarejfocalcomp' 'Focal components' [ 0 0.5000 0]
- 'icarejtrialfoc' 'Focal trial activity' [ 0.7500 0 0.7500]
- 'icarejSNR' 'Signal to noise ' [ 0.8000 0 0]
- 'icarejresvar' 'Residual variance' [ 0 0.7500 0.7500]
- 'icarejchancorr' 'Correlation with channels' [ 0.7500 0.7500 0]
- 'icarejADJUST' 'ADJUST selections' [ .3 .3 .3]
- 'icarejFASTER' 'FASTER selections' [ 0 .7 0]
- 'icarejMARA' 'MARA selections' [ .5 .5 0]
- };
- rejects = zeros(size(rejfields,1),1);
- if numel(noplot) == 1
- noplot = noplot * ones(1,size(rejfields,1));
- end
- if any(~noplot)
- figure(321541);clf;% just a random number so we always work in the same figure
- BACKCOLOR = [.93 .96 1];
- set(gcf,'numbertitle', 'off','name','Automatic component rejection measures','color',BACKCOLOR)
- isubplot = 1;
- end
- ncomp= size(EEG.icawinv,2); % ncomp is number of components
- icaacts = eeg_getdatact(EEG,'component',1:ncomp);
- EEG.icaact = icaacts;
- EEG.reject.SASICA = [];
- for ifield = 1:size(rejfields,1)
- % EEG.reject.SASICA.(rejfields{ifield}) = false(1,ncomp);
- EEG.reject.SASICA.([rejfields{ifield} 'col']) = rejfields{ifield,3};
- end
- fprintf('Computing selection methods...\n')
- if cfg.autocorr.enable
- rejects(1) = 1;
- disp('Autocorrelation.')
- %% Autocorrelation
- % Identifying noisy components
- %----------------------------------------------------------------
- struct2ws(cfg.autocorr);
-
- Ncorrint=round(autocorrint/(1000/EEG.srate)); % number of samples for lag
- rej = false(1,ncomp);
- for k=1:ncomp
- y=icaacts(k,:,:);
- yy=xcorr(mean(y,3),Ncorrint,'coeff');
- autocorr(k) = yy(1);
- end
- dropautocorr = readauto(dropautocorr,autocorr,'-');
- for k = 1:ncomp
- if autocorr(k) < dropautocorr
- rej(k)=true;
- end
- end
- EEG.reject.SASICA.(strrep(rejfields{1,1},'rej','')) = autocorr;
- EEG.reject.SASICA.(strrep(rejfields{1,1},'rej','thresh')) = dropautocorr;
- EEG.reject.SASICA.(rejfields{1,1}) = logical(rej);
- %----------------------------------------------------------------
- if cfg.focalcomp.enable
- rejects(2) = 1;
- disp('Focal components.')
- %% Focal activity
- %----------------------------------------------------------------
- struct2ws(cfg.focalcomp);
- rej = false(1,ncomp);
- clear mywt
- for k=1:ncomp
- mywt(:,k) = sort(abs(zscore(EEG.icawinv(:,k))),'descend'); %sorts standardized weights in descending order
- end
- focalICAout = readauto(focalICAout,mywt(1,:),'+');
- for k = 1:ncomp
- if mywt(1,k) > focalICAout
- rej(k)=true;
- end
- end
- EEG.reject.SASICA.(strrep(rejfields{2,1},'rej','')) = mywt(1,:);
- EEG.reject.SASICA.(strrep(rejfields{2,1},'rej','thresh')) = focalICAout;
- EEG.reject.SASICA.(rejfields{2,1}) = logical(rej);
- end
- %----------------------------------------------------------------
- if cfg.trialfoc.enable
- rejects(3) = 1;
- disp('Focal trial activity.');
- %% Focal trial activity
- % Find components with focal trial activity (those that have activity
- % on just a few trials and are almost zero on others)
- %----------------------------------------------------------------
- if ndims(icaacts) < 3
- error('This method cannot be used on continuous data (no ''trials''!)');
- end
- struct2ws(cfg.trialfoc);
- myact =sort(abs(zscore(range(icaacts,2),[],3)),3,'descend'); % sorts standardized range of trial activity
- focaltrialout = readauto(focaltrialout,myact(:,:,1)','+');
- % in descending order
- rej = myact(:,:,1) > focaltrialout;
- EEG.reject.SASICA.(strrep(rejfields{3,1},'rej','')) = myact(:,:,1)';
- EEG.reject.SASICA.(strrep(rejfields{3,1},'rej','thresh')) = focaltrialout;
- EEG.reject.SASICA.(rejfields{3,1}) = rej';
-
- %----------------------------------------------------------------
- end
- if cfg.SNR.enable
- rejects(4) = 1;
- disp('Signal to noise ratio.')
- %% Low Signal to noise components
- struct2ws(cfg.SNR);
- rejfields{4,2} = ['Signal to noise Time of interest ' num2str(snrPOI,'%g ') ' and Baseline ' num2str(snrBL,'%g ') ' ms.'];
-
- POIpts = timepts(snrPOI);
- BLpts = timepts(snrBL);
-
- zz = zscore(icaacts,[],2);% zscore along time
- av1 = mean(zz(:,POIpts,:),3); % average activity in POI across trials
- av2 = mean(zz(:,BLpts,:),3); % activity in baseline acros trials
- SNR = std(av1,[],2)./std(av2,[],2); % ratio of the standard deviations of activity and baseline
- snrcut = readauto(snrcut,SNR,'-');
- rej = SNR < snrcut;
- EEG.reject.SASICA.(strrep(rejfields{4,1},'rej','')) = SNR';
- EEG.reject.SASICA.(strrep(rejfields{4,1},'rej','thresh')) = snrcut;
- EEG.reject.SASICA.(rejfields{4,1}) = rej';
-
- %----------------------------------------------------------------
- end
- if cfg.resvar.enable
- rejects(5) = 1;
- disp('Residual variance thresholding.')
- %% High residual variance
- struct2ws(cfg.resvar);
-
- resvar = 100*[EEG.dipfit.model.rv];
- rej = resvar > thresh;
-
- EEG.reject.SASICA.(strrep(rejfields{5,1},'rej','')) = resvar;
- EEG.reject.SASICA.(strrep(rejfields{5,1},'rej','thresh')) = thresh;
- EEG.reject.SASICA.(rejfields{5,1}) = rej;
-
- %----------------------------------------------------------------
- end
- if cfg.EOGcorr.enable
- rejects(6) = 1;
- disp('Correlation with EOGs.');
- %% Correlation with EOG
- struct2ws(cfg.EOGcorr);
- noV = 0;noH = 0;
- try
- Veogchan = chnb(Veogchannames);
- catch
- Veogchan = [];
- end
- try
- Heogchan = chnb(Heogchannames);
- catch
- Heogchan = [];
- end
- if numel(Veogchan) == 1
- VEOG = EEG.data(Veogchan,:,:);
- elseif numel(Veogchan) == 2
- VEOG = EEG.data(Veogchan(1),:,:) - EEG.data(Veogchan(2),:,:);
- else
- disp('no Vertical EOG channels...');
- noV = 1;
- end
- if numel(Heogchan) == 1
- HEOG = EEG.data(Heogchan,:,:);
- elseif numel(Heogchan) == 2
- HEOG = EEG.data(Heogchan(1),:,:) - EEG.data(Heogchan(2),:,:);
- else
- disp('no Horizontal EOG channels...');
- noH = 1;
- end
- ICs = icaacts(:,:)';
- if ~noV
- VEOG = VEOG(:);
- cV = abs(corr(ICs,VEOG))';
- corthreshV = readauto(corthreshV,cV,'+');
- rejV = cV > corthreshV ;
- else
- cV = NaN(1,size(ICs,2));
- corthreshV = 0;
- rejV = false(size(cV));
- end
- if ~noH
- HEOG = HEOG(:);
- cH = abs(corr(ICs,HEOG))';
- corthreshH = readauto(corthreshH,cH,'+');
- rejH = cH > corthreshH;
- else
- cH = NaN(1,size(ICs,2));
- corthreshH = 0;
- rejH = false(size(cH));
- end
-
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','') 'VEOG']) = cV;
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','thresh') 'VEOG']) = corthreshV;
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','') 'HEOG']) = cH;
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','thresh') 'HEOG']) = corthreshH;
- EEG.reject.SASICA.(rejfields{6,1}) = [rejV|rejH];
-
- %----------------------------------------------------------------
- end
- if cfg.chancorr.enable
- rejects(6) = 1;
- disp('Correlation with other channels.')
- %% Correlation with other channels
- struct2ws(cfg.chancorr);
- if ~cfg.EOGcorr.enable
- rejH = false(1,ncomp);
- rejV = false(1,ncomp);
- end
- if ~isempty(channames)
- try
- [chan cellchannames channames] = chnb(channames);
- end
- chanEEG = EEG.data(chan,:)';
- ICs = icaacts(:,:)';
- c = abs(corr(ICs,chanEEG))';
- corthresh = mean(readauto(corthresh,c,'+'));
- rej = c > corthresh ;
- if size(rej,1) > 1
- rej = sum(rej)>=1;
- end
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','') 'chans']) = c;
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','thresh') 'chans']) = corthresh;
- EEG.reject.SASICA.(rejfields{6,1}) = [rej|rejH|rejV];
- else
- noplot(6) = 1;
- disp('Could not find the channels to compute correlation.');
- c = NaN(1,ncomp);
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','') 'chans']) = c;
- EEG.reject.SASICA.([strrep(rejfields{6,1},'rej','thresh') 'chans']) = corthresh;
- rej = false(1,ncomp);
- EEG.reject.SASICA.(rejfields{6,1}) = [rej|rejV|rejH];
- end
-
- %----------------------------------------------------------------
- end
- if cfg.ADJUST.enable
- rejects(7) = 1;
- disp('ADJUST methods selection')
- %% ADJUST
- struct2ws(cfg.ADJUST);
-
- [art, horiz, vert, blink, disc,...
- soglia_DV, diff_var, soglia_K, med2_K, meanK, soglia_SED, med2_SED, SED, soglia_SAD, med2_SAD, SAD, ...
- soglia_GDSF, med2_GDSF, GDSF, soglia_V, med2_V, nuovaV, soglia_D, maxdin] = ADJUST (EEG);
-
- ADJ.art = art;ADJ.horiz = horiz;ADJ.vert = vert;ADJ.blink = blink;ADJ.disc = disc;
-
- ADJ.soglia_DV = soglia_DV; ADJ.diff_var = diff_var;
- ADJ.soglia_K = soglia_K;ADJ.med2_K = med2_K; ADJ.meanK = meanK;
- ADJ.soglia_SED = soglia_SED; ADJ.med2_SED = med2_SED;ADJ.SED = SED;
- ADJ.med2_SAD = med2_SAD;ADJ.soglia_SAD = soglia_SAD;ADJ.SAD = SAD;
- ADJ.soglia_GDSF = soglia_GDSF; ADJ.med2_GDSF = med2_GDSF;ADJ.GDSF = GDSF;
- ADJ.soglia_V = soglia_V;ADJ.med2_V = med2_V;ADJ.nuovaV = nuovaV;
- ADJ.soglia_D = soglia_D; ADJ.maxdin = maxdin;
-
- rej = false(1,size(EEG.icaact,1));
- rej([ADJ.art ADJ.horiz ADJ.vert ADJ.blink ADJ.disc]) = true;
-
- EEG.reject.SASICA.(strrep(rejfields{7,1},'rej','')) = ADJ;
- EEG.reject.SASICA.(rejfields{7,1}) = rej;
- %----------------------------------------------------------------
- end
- if cfg.FASTER.enable
- rejects(8) = 1;
- disp('FASTER methods selection')
- %% FASTER
- struct2ws(cfg.FASTER);
- blinkchans = chnb(blinkchans);
- listprops = component_properties(EEG,blinkchans);
- FST.rej = min_z(listprops)' ~= 0;
- FST.listprops = listprops;
-
- EEG.reject.SASICA.(strrep(rejfields{8,1},'rej','')) = FST;
- EEG.reject.SASICA.(rejfields{8,1}) = FST.rej;
-
- %----------------------------------------------------------------
- end
- if cfg.MARA.enable
- rejects(9) = 1;
- disp('MARA methods selection')
- %% MARA
- struct2ws(cfg.MARA);
- [rej info] = MARA(EEG);
- MR.rej = false(1,size(EEG.icaact,1));
- MR.rej(rej) = true;
- MR.info = info;
-
- EEG.reject.SASICA.(strrep(rejfields{9,1},'rej','')) = MR;
- EEG.reject.SASICA.(rejfields{9,1}) = MR.rej;
-
- %----------------------------------------------------------------
- end
- EEG.reject.SASICA.var = var(EEG.icaact(:,:),[],2);% variance of each component
- if (cfg.ADJUST.enable||cfg.FASTER.enable) && any(~noplot)
- h = uicontrol('style','text','string','for ADJUST or FASTER results, click on component buttons in the other window(s)','units','normalized','position',[0 0 1 .05],'backgroundcolor',get(gcf,'color'));
- uistack(h,'bottom')
- end
- % Final computations
- % combine in gcompreject field and pass to pop_selectcomps
- EEG.reject.gcompreject = false(1,ncomp);
- for ifield = 1:size(rejfields,1)
- if rejects(ifield)
- EEG.reject.gcompreject = [EEG.reject.gcompreject ; EEG.reject.SASICA.(rejfields{ifield})];
- end
- end
- EEG.reject.gcompreject = sum(EEG.reject.gcompreject) >= 1;
- end
- % pop_prop() - plot the properties of a channel or of an independent
- % component.
- % Usage:
- % >> pop_prop( EEG); % pops up a query window
- % >> pop_prop( EEG, typecomp); % pops up a query window
- % >> pop_prop( EEG, typecomp, chanorcomp, winhandle,spectopo_options);
- %
- % Inputs:
- % EEG - EEGLAB dataset structure (see EEGGLOBAL)
- %
- % Optional inputs:
- % typecomp - [0|1] 1 -> display channel properties
- % 0 -> component properties {default: 1 = channel}
- % chanorcomp - channel or component number[s] to display {default: 1}
- %
- % winhandle - if this parameter is present or non-NaN, buttons
- % allowing the rejection of the component are drawn.
- % If non-zero, this parameter is used to back-propagate
- % the color of the rejection button.
- % spectopo_options - [cell array] optional cell arry of options for
- % the spectopo() function.
- % For example { 'freqrange' [2 50] }
- %
- % Author: Arnaud Delorme, CNL / Salk Institute, 2001
- %
- % See also: pop_runica(), eeglab()
- % Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
- %
- % 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
- function [fh,EEG] = pop_prop(EEG, typecomp, chanorcomp, winhandle, spec_opt,ID, flag_fig)
- if exist('flag_fig','var') == 0 || isempty(flag_fig)
- flag_fig = 1;
- end
- % assumed input is chanorcomp
- % -------------------------
- try, icadefs;
- catch,
- BACKCOLOR = [0.8 0.8 0.8];
- GUIBUTTONCOLOR = [0.8 0.8 0.8];
- end;
- basename = ['Component_' int2str(chanorcomp) ];
- if flag_fig
-
- fh = figure('name', ['SetID_' num2str(ID) '_' basename],...
- 'color', BACKCOLOR,...
- 'numbertitle', 'off',...
- 'visible', 'on',...
- 'PaperPositionMode','auto',...
- 'ToolBar', 'none',...
- 'MenuBar','none');
-
- pos = get(fh,'position');
- set(fh,'Position', [pos(1) pos(2)-700+pos(4) 600 800], 'visible', 'on');
- pos = get(gca,'position'); % plot relative to current axes
- hh = gca;
- q = [pos(1) pos(2) 0 0];
- s = [pos(3) pos(4) pos(3) pos(4)]./100;
- delete(gca);
- p = panel();
- p.margin = [10 10 10 10];
- p.pack('v',{.3 .25 []});
- p(1).margin = [5 5 5 5];
- p(1).pack('h',{.4 [] .01});
-
- % ---
- if ~exist('winhandle') || isempty(winhandle) || isnan(winhandle)
- winhandle = NaN;
- p(2).pack('v',{.98 [] })
- else
- p(2).pack('v',{.8 []})
- end;
- p(2,1).pack('h',{.01,[]});
- p(2,1).margin = [10 10 0 0 ] ;%[10 15 0 55];
- p(2,1,1).margin = 0;
- %p(2,1,3).margin = 0;
- p(2,1,2).pack('v',{.2 []});
- p(2,1,2,1).margin = 0;
- p(2,1,2,2).margintop = 5;
- p(2,1,2,2).select();
-
- % --- plot time series ---
- [dat, time] = choose_ts_seg(EEG,chanorcomp);
- plot(time,dat');
-
- axis on;
- box on;
- grid on;
- tstitle_h = title('Component Time Series', 'fontsize', 14,'fontweight','bold');
-
- % ---
- if ~exist('winhandle') || isempty(winhandle) || isnan(winhandle)
- winhandle = NaN;
- p(3).pack('v',{.98 [] })
- else
- p(3).pack('v',{.8 []})
- end;
- p(3,1).pack('h',{.005,[],.005});
- p(3,1).margin = [10 0 0 0 ] ;%[10 15 0 55];
- p(3,1,1).margin = 0;
- p(3,1,3).margin = 0;
- p(3,1,2).pack('v',{.001 []});
- p(3,1,2,1).margin = 0;
- p(3,1,2,2).margintop = 3;
- % ---
-
- % plotting topoplot
- p(1,1).select()
- p(1,1).margin = [25 25 20 25];
- scalpmap_norm = EEG.icawinv(:,chanorcomp)/sqrt(sum(EEG.icawinv(:,chanorcomp).^2));
- [~,Zi,plotrad] = topoplotFast( scalpmap_norm, EEG.chanlocs, 'chaninfo', EEG.chaninfo, ...
- 'shading', 'interp', 'numcontour', 3,'electrodes','on'); axis square;
- EEG.reject.SASICA.topo(chanorcomp,:) = Zi(~isnan(Zi));
- EEG.reject.SASICA.plotrad(chanorcomp)= plotrad;
- % h = title(basename, 'fontsize', 14);
- % set(h,'position',get(h,'position')+[0 1 0]);
- % set(gca,'fontSize',14);
-
- if ~isfield(EEG.reject.SASICA, 'icarejresvar'), rv = 'NA'; else, rv = num2str(EEG.dipfit.model(chanorcomp).rv*100); end;
-
- h = title({'Residual Variance:'; [rv '%']},'fontsize', 16,'Units','Normalized');
- pos = get(h,'position');
-
- h2 = text(0.10,0.95,[num2str(ID,'%06d') '_' num2str(chanorcomp,'%03d')],'Units', 'Normalized','Fontsize', 12);
-
- % % plotting erpimage
- %--------------------
- p(1,2).margin = [30 30 25 25];
- set(h,'position',pos+[0 -1.28 0],'fontsize', 14);
- set(h2,'Position',[0.35,1.15],'Interpreter','none')
- p(1,2).select();
- eeglab_options;
- if EEG.trials > 1
- % put title at top of erpimage
- axis off
- EEG.times = linspace(EEG.xmin, EEG.xmax, EEG.pnts);
- if EEG.trials < 6
- ei_smooth = 1;
- else
- ei_smooth = 3;
- end
- icaacttmp = eeg_getdatact(EEG, 'component', chanorcomp);
- offset = nan_mean(icaacttmp(:));
- era = nan_mean(squeeze(icaacttmp)')-offset;
- era_limits=get_era_limits(era);
- [~,~,~,~,axhndls] = myerpimage( icaacttmp-offset, ones(1,EEG.trials)*10000, EEG.times*1000, ...
- '', ei_smooth, 1, 'caxis', 2/3, 'cbar','erp', 'yerplabel', '','erp_vltg_ticks',era_limits);
- % title(sprintf('%s activity \\fontsize{10}(global offset %3.3f)', basename, offset));
- title('Epoched Data', 'fontsize', 14 );
-
- else
- % put title at top of erpimage
- EI_TITLE = 'Continous data';
- ERPIMAGELINES = 200; % show 200-line erpimage
- while size(EEG.data,2) < ERPIMAGELINES*EEG.srate
- ERPIMAGELINES = 0.9 * ERPIMAGELINES;
- end
- ERPIMAGELINES = round(ERPIMAGELINES);
- if ERPIMAGELINES > 2 % give up if data too small
- if ERPIMAGELINES < 10
- ei_smooth = 1;
- else
- ei_smooth = 3;
- end
- erpimageframes = floor(size(EEG.data,2)/ERPIMAGELINES);
- erpimageframestot = erpimageframes*ERPIMAGELINES;
- eegtimes = linspace(0, erpimageframes-1, EEG.srate/1000);
- if typecomp == 1 % plot channel
- offset = nan_mean(EEG.data(chanorcomp,:));
- % Note: we don't need to worry about ERP limits, since ERPs
- % aren't visualized for continuous data
- [~,~,~,~,axhndls] = myerpimage( reshape(EEG.data(chanorcomp,1:erpimageframestot),erpimageframes,ERPIMAGELINES)-offset, ones(1,ERPIMAGELINES)*10000, eegtimes , ...
- EI_TITLE, ei_smooth, 1, 'caxis', 2/3, 'cbar');
- else % plot component
- icaacttmp = eeg_getdatact(EEG, 'component', chanorcomp);
- offset = nan_mean(icaacttmp(:));
- [~,~,~,~,axhndls] = myerpimage(reshape(icaacttmp(:,1:erpimageframestot),erpimageframes,ERPIMAGELINES)-offset,ones(1,ERPIMAGELINES)*10000, eegtimes , ...
- EI_TITLE, ei_smooth, 1, 'caxis', 2/3, 'cbar','yerplabel', '');
- end
- else
- axis off;
- text(0.1, 0.3, [ 'No erpimage plotted' 10 'for small continuous data']);
- end;
- end;
- axhndls{1}.FontSize = 12;
- axhndls{1}.YLabel.FontSize = 14;
- axhndls{3}.FontSize = 12;
- axhndls{3}.XLabel.FontSize =14;
- set(tstitle_h,'FontSize',15);
- p(2,1,2,2).select();
- set(gca,'FontSize',12);
- set(gca,'Xlabel');
- xlabel('Time (s)','fontsize', 13);
- ylabel('\muV');
-
- % plotting spectrum
- % -----------------s
- p(3,1,2,2).select();
- try
- spectopo( EEG.icaact(chanorcomp,:), EEG.pnts, EEG.srate, 'mapnorm', EEG.icawinv(:,chanorcomp), spec_opt{:} );
- % set( get(gca, 'ylabel'), 'string', 'Power 10*log_{10}(\muV^{2}/Hz)', 'fontsize', 12);
- % set( get(gca, 'xlabel'), 'string', 'Frequency (Hz)', 'fontsize', 12);
- axis on;
- box on;
- grid on;
- xlim([3 80]);
- xlabel('Frequency (Hz)')
- clc
- text(0.35,1.04,'Activity power spectrum','units','normalized', 'fontsize', 15);
- catch
- axis off;
- lasterror
- text(0.1, 0.3, [ 'Error: no spectrum plotted' 10 ' make sure you have the ' 10 'signal processing toolbox']);
- end;
- else
- fh = [];
- scalpmap_norm = EEG.icawinv(:,chanorcomp)/sqrt(sum(EEG.icawinv(:,chanorcomp).^2));
- [~,Zi,plotrad] = topoplotFast( scalpmap_norm, EEG.chanlocs, 'chaninfo', EEG.chaninfo, ...
- 'shading', 'interp', 'numcontour', 3,'electrodes','on','noplot','on');
- EEG.reject.SASICA.topo(chanorcomp,:) = Zi(~isnan(Zi));
- EEG.reject.SASICA.plotrad(chanorcomp)= plotrad;
- end
- function out = nan_mean(in)
- nans = find(isnan(in));
- in(nans) = 0;
- sums = sum(in);
- nonnans = ones(size(in));
- nonnans(nans) = 0;
- nonnans = sum(nonnans);
- nononnans = find(nonnans==0);
- nonnans(nononnans) = 1;
- out = sum(in)./nonnans;
- out(nononnans) = NaN;
- function era_limits=get_era_limits(era)
- %function era_limits=get_era_limits(era)
- %
- % Returns the minimum and maximum value of an event-related
- % activation/potential waveform (after rounding according to the order of
- % magnitude of the ERA/ERP)
- %
- % Inputs:
- % era - [vector] Event related activation or potential
- %
- % Output:
- % era_limits - [min max] minimum and maximum value of an event-related
- % activation/potential waveform (after rounding according to the order of
- % magnitude of the ERA/ERP)
- mn=min(era);
- mx=max(era);
- mn=orderofmag(mn)*round(mn/orderofmag(mn));
- mx=orderofmag(mx)*round(mx/orderofmag(mx));
- era_limits=[mn mx];
- function ord=orderofmag(val)
- %function ord=orderofmag(val)
- %
- % Returns the order of magnitude of the value of 'val' in multiples of 10
- % (e.g., 10^-1, 10^0, 10^1, 10^2, etc ...)
- % used for computing erpimage trial axis tick labels as an alternative for
- % plotting sorting variable
- val=abs(val);
- if val>=1
- ord=1;
- val=floor(val/10);
- while val>=1,
- ord=ord*10;
- val=floor(val/10);
- end
- return;
- else
- ord=1/10;
- val=val*10;
- while val<1,
- ord=ord/10;
- val=val*10;
- end
- return;
- end
- function thresh = readauto(thresh,dat,comp)
- % if thresh starts with 'auto'
- % compute auto threshold as mean(dat) +/- N std(dat)
- % with N read in the string thresh = 'auto N'
- % if not, use thresh as a value
- if isstr(thresh) && strncmp(thresh,'auto',4)
- if numel(thresh) > 4
- threshsigma = str2num(thresh(5:end));
- else
- threshsigma = 2;
- end
- thresh = eval(['mean(dat,2)' comp 'threshsigma * std(dat,[],2)']);
- end
- function [nb,channame,strnames] = chnb(channame, varargin)
- % chnb() - return channel number corresponding to channel names in an EEG
- % structure
- %
- % Usage:
- % >> [nb] = chnb(channameornb);
- % >> [nb,names] = chnb(channameornb,...);
- % >> [nb,names,strnames] = chnb(channameornb,...);
- % >> [nb] = chnb(channameornb, labels);
- %
- % Input:
- % channameornb - If a string or cell array of strings, it is assumed to
- % be (part of) the name of channels to search. Either a
- % string with space separated channel names, or a cell
- % array of strings.
- % Note that regular expressions can be used to match
- % several channels. See regexp.
- % If only one channame pattern is given and the string
- % 'inv' is attached to it, the channels NOT matching the
- % pattern are returned.
- % labels - Channel names as found in {EEG.chanlocs.labels}.
- %
- % Output:
- % nb - Channel numbers in labels, or in the EEG structure
- % found in the caller workspace (i.e. where the function
- % is called from) or in the base workspace, if no EEG
- % structure exists in the caller workspace.
- % names - Channel names, cell array of strings.
- % strnames - Channel names, one line character array.
- error(nargchk(1,2,nargin));
- if nargin == 2
- labels = varargin{1};
- else
-
- try
- EEG = evalin('caller','EEG');
- catch
- try
- EEG = evalin('base','EEG');
- catch
- error('Could not find EEG structure');
- end
- end
- if not(isfield(EEG,'chanlocs'))
- error('No channel list found');
- end
- EEG = EEG(1);
- labels = {EEG.chanlocs.labels};
- end
- if iscell(channame) || ischar(channame)
-
- if ischar(channame) || iscellstr(channame)
- if iscellstr(channame) && numel(channame) == 1 && isempty(channame{1})
- channame = '';
- end
- tmp = regexp(channame,'(\S*) ?','tokens');
- channame = {};
- for i = 1:numel(tmp)
- if iscellstr(tmp{i}{1})
- channame{i} = tmp{i}{1}{1};
- else
- channame{i} = tmp{i}{1};
- end
- end
- if isempty(channame)
- nb = [];
- return
- end
- end
- if numel(channame) == 1 && not(isempty(strmatch('inv',channame{1})))
- cmd = 'exactinv';
- channame{1} = strrep(channame{1},'inv','');
- else
- channame{1} = channame{1};
- cmd = 'exact';
- end
- nb = regexpcell(labels,channame,[cmd 'ignorecase']);
-
- elseif isnumeric(channame)
- nb = channame;
- if nb > numel(labels)
- nb = [];
- end
- end
- channame = labels(nb);
- strnames = sprintf('%s ',channame{:});
- if not(isempty(strnames))
- strnames(end) = [];
- end
- function idx = regexpcell(c,pat, cmds)
- % idx = regexpcell(c,pat, cmds)
- %
- % Return indices idx of cells in c that match pattern(s) pat (regular expression).
- % Pattern pat can be char or cellstr. In the later case regexpcell returns
- % indexes of cells that match any pattern in pat.
- %
- % cmds is a string that can contain one or several of these commands:
- % 'inv' return indexes that do not match the pattern.
- % 'ignorecase' will use regexpi instead of regexp
- % 'exact' performs an exact match (regular expression should match the whole strings in c).
- % 'all' (default) returns all indices, including repeats (if several pat match a single cell in c).
- % 'unique' will return unique sorted indices.
- % 'intersect' will return only indices in c that match ALL the patterns in pat.
- %
- % v1 Maximilien Chaumon 01/05/09
- % v1.1 Maximilien Chaumon 24/05/09 - added ignorecase
- % v2 Maximilien Chaumon 02/03/2010 changed input method.
- % inv,ignorecase,exact,combine are replaced by cmds
- error(nargchk(2,3,nargin))
- if not(iscellstr(c))
- error('input c must be a cell array of strings');
- end
- if nargin == 2
- cmds = '';
- end
- if not(isempty(regexpi(cmds,'inv', 'once' )))
- inv = true;
- else
- inv = false;
- end
- if not(isempty(regexpi(cmds,'ignorecase', 'once' )))
- ignorecase = true;
- else
- ignorecase = false;
- end
- if not(isempty(regexpi(cmds,'exact', 'once' )))
- exact = true;
- else
- exact = false;
- end
- if not(isempty(regexpi(cmds,'unique', 'once' )))
- combine = 2;
- elseif not(isempty(regexpi(cmds,'intersect', 'once' )))
- combine = 3;
- else
- combine = 1;
- end
- if ischar(pat)
- pat = cellstr(pat);
- end
- if exact
- for i_pat = 1:numel(pat)
- pat{i_pat} = ['^' pat{i_pat} '$'];
- end
- end
- for i_pat = 1:length(pat)
- if ignorecase
- trouv = regexpi(c,pat{i_pat}); % apply regexp on each pattern
- else
- trouv = regexp(c,pat{i_pat}); % apply regexp on each pattern
- end
- idx{i_pat} = [];
- for i = 1:numel(trouv)
- if not(isempty(trouv{i}))% if there is a match, store index
- idx{i_pat}(end+1) = i;
- end
- end
- end
- switch combine
- case 1
- idx = [idx{:}];
- case 2
- idx = unique([idx{:}]);
- case 3
- for i_pat = 2:length(pat)
- idx{1} = intersect(idx{1},idx{i_pat});
- end
- idx = idx{1};
- end
- if inv % if we want to invert result, then do so.
- others = 1:numel(trouv);
- others(idx) = [];
- idx = others;
- end
- function s = setdef(s,d)
- % s = setdef(s,d)
- % Merges the two structures s and d recursively.
- % Adding the default field values from d into s when not present or empty.
- if isstruct(s) && not(isempty(s))
- fields = fieldnames(d);
- for i_f = 1:numel(fields)
- if isfield(s,fields{i_f})
- s.(fields{i_f}) = setdef(s.(fields{i_f}),d.(fields{i_f}));
- else
- s.(fields{i_f}) = d.(fields{i_f});
- end
- end
- elseif not(isempty(s))
- s = s;
- elseif isempty(s);
- s = d;
- end
- function struct2ws(s,varargin)
- % struct2ws(s,varargin)
- %
- % Description : This function returns fields of scalar structure s in the
- % current workspace
- % __________________________________
- % Inputs :
- % s (scalar structure array) : a structure that you want to throw in
- % your current workspace.
- % re (string optional) : a regular expression. Only fields
- % matching re will be returned
- % Outputs :
- % No output : variables are thrown directly in the caller workspace.
- %
- %
- % _____________________________________
- % See also : ws2struct ; regexp
- %
- % Maximilien Chaumon v1.0 02/2007
- if nargin == 0
- cd('d:\Bureau\work')
- s = dir('pathdef.m');
- end
- if length(s) > 1
- error('Structure should be scalar.');
- end
- if not(isempty(varargin))
- re = varargin{1};
- else
- re = '.*';
- end
- vars = fieldnames(s);
- vmatch = regexp(vars,re);
- varsmatch = [];
- for i = 1:length(vmatch)
- if isempty(vmatch{i})
- continue
- end
- varsmatch(end+1) = i;
- end
- for i = varsmatch
- assignin('caller',vars{i},s.(vars{i}));
- end
- function [sortie] = ws2struct(varargin)
- % [s] = ws2struct(varargin)
- %
- % Description : This function returns a structure containing variables
- % of the current workspace.
- % __________________________________
- % Inputs :
- % re (string optional) : a regular expression matching the variables to
- % be returned.
- % Outputs :
- % s (structure array) : a structure containing all variables of the
- % calling workspace. If re input is specified,
- % only variables matching re are returned.
- % _____________________________________
- % See also : struct2ws ; regexp
- %
- % Maximilien Chaumon v1.0 02/2007
- if not(isempty(varargin))
- re = varargin{1};
- else
- re = '.*';
- end
- vars = evalin('caller','who');
- vmatch = regexp(vars,re);
- varsmatch = [];
- for i = 1:length(vmatch)
- if isempty(vmatch{i}) || not(vmatch{i} == 1)
- continue
- end
- varsmatch{end+1} = vars{i};
- end
- for i = 1:length(varsmatch)
- dat{i} = evalin('caller',varsmatch{i});
- end
- sortie = cell2struct(dat,varsmatch,2);
- function [tpts tvals] = timepts(timein, varargin)
- % timepts() - return time points corresponding to a certain latency range
- % in an EEG structure.
- %
- % Usage:
- % >> [tpts] = timepts(timein);
- % >> [tpts tvals] = timepts(timein, times);
- % Note: this last method also works with any type of numeric
- % data entered under times (ex. frequencies, trials...)
- %
- % Input:
- % timein - latency range [start stop] (boundaries included). If
- % second argument 'times' is not provided, EEG.times will
- % be evaluated from the EEG structure found in the caller
- % workspace (or base if not in caller).
- % times - time vector as found in EEG.times
- %
- % Output:
- % tpts - index numbers corresponding to the time range.
- % tvals - values of EEG.times at points tpts
- %
- error(nargchk(1,2,nargin));
- if nargin == 2
- times = varargin{1};
- else
-
- try
- EEG = evalin('caller','EEG');
- catch
- try
- EEG = evalin('base','EEG');
- catch
- error('Could not find EEG structure');
- end
- end
- if not(isfield(EEG,'times'))
- error('No time list found');
- end
- times = EEG.times;
- if isempty(times)
- times = EEG.xmin:1/EEG.srate:EEG.xmax;
- end
- end
- if isempty(times)
- error('could not find times');
- end
- if numel(timein) == 1
- [dum tpts] = min(abs(times - timein));% find the closest one
- if tpts == numel(times)
- warning('Strange time is last index of times')
- end
- elseif numel(timein) == 2
- tpts = find(times >= timein(1) & times <= timein(2));% find times within bounds
- else
- error('timein should be a scalar or a 2 elements vector');
- end
- tvals = times(tpts);
- function tw = strwrap(t,n)
- % tw = strwrap(t,n)
- %
- % wrap text array t at n characters taking non alphanumeric characters as
- % breaking characters (i.e. not cutting words strangely).
- t = deblank(t(:)');
- seps = '[\s-]';
- tw = '';
- while not(isempty(t))
- breaks = regexp(t,seps);
- breaks(end+1) = numel(t);
- idx = 1:min(n,breaks(find(breaks < n, 1,'last')));
- if isempty(idx)
- idx = 1:min(n,numel(t));
- end
- tw(end+1,:) = char(padarray(double(t(idx)),[0 n-numel(idx)],32,'post'));
- t(idx)= [];
- t = strtrim(t);
- end
- function h = hline(y,varargin)
- % h = hline(y,varargin)
- % add horizontal line(s) on the current axes at y
- % all varargin arguments are passed to plot...
- y = y(:);
- ho = ishold;
- hold on
- h = plot(repmat(xlim,numel(y),1)',[y y]',varargin{:});
- if not(ho)
- hold off
- end
- if nargout == 0
- clear h
- end
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% BELOW IS ADJUST CODE%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % ADJUST() - Automatic EEG artifact Detector
- % with Joint Use of Spatial and Temporal features
- %
- % Usage:
- % >> [art, horiz, vert, blink, disc,...
- % soglia_DV, diff_var, soglia_K, med2_K, meanK, soglia_SED, med2_SED, SED, soglia_SAD, med2_SAD, SAD, ...
- % soglia_GDSF, med2_GDSF, GDSF, soglia_V, med2_V, nuovaV, soglia_D, maxdin]=ADJUST (EEG,out)
- %
- % Inputs:
- % EEG - current dataset structure or structure array (has to be epoched)
- % out - (string) report file name
- %
- % Outputs:
- % art - List of artifacted ICs
- % horiz - List of HEM ICs
- % vert - List of VEM ICs
- % blink - List of EB ICs
- % disc - List of GD ICs
- % soglia_DV - SVD threshold
- % diff_var - SVD feature values
- % soglia_K - TK threshold
- % meanK - TK feature values
- % soglia_SED - SED threshold
- % SED - SED feature values
- % soglia_SAD - SAD threshold
- % SAD - SAD feature values
- % soglia_GDSF- GDSF threshold
- % GDSF - GDSF feature values
- % soglia_V - MEV threshold
- % nuovaV - MEV feature values
- %
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % ADJUST
- % Automatic EEG artifact Detector based on the Joint Use of Spatial and Temporal features
- %
- % Developed 2007-2014
- % Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % Last update: 02/05/2014 by Marco Buiatti
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Reference paper:
- % Mognon A, Bruzzone L, Jovicich J, Buiatti M,
- % ADJUST: An Automatic EEG artifact Detector based on the Joint Use of Spatial and Temporal features.
- % Psychophysiology 48 (2), 229-240 (2011).
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % VERSIONS LOG
- %
- % 02/05/14: Modified text in Report.txt (MB).
- %
- % 30/03/14: Removed 'message to the user' (redundant). (MB)
- %
- % 22/03/14: kurtosis is replaced by kurt for compatibility if signal processing
- % toolbox is missing (MB).
- %
- % V2 (07 OCTOBER 2010) - by Andrea Mognon
- % Added input 'nchannels' to compute_SAD and compute_SED_NOnorm;
- % this is useful to differentiate the number of ICs (n) and the number of
- % sensors (nchannels);
- % bug reported by Guido Hesselman on October, 1 2010.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % function [art, horiz, vert, blink, disc,...
- % soglia_DV, diff_var, soglia_K, meanK, soglia_SED, SED, soglia_SAD, SAD, ...
- % soglia_GDSF, GDSF, soglia_V, nuovaV, soglia_D, maxdin]=ADJUST (EEG,out)
- function [art, horiz, vert, blink, disc,...
- soglia_DV, diff_var, soglia_K, med2_K, meanK, soglia_SED, med2_SED, SED, soglia_SAD, med2_SAD, SAD, ...
- soglia_GDSF, med2_GDSF, GDSF, soglia_V, med2_V, nuovaV, soglia_D, maxdin]=ADJUST (EEG)
- %% Settings
- % ----------------------------------------------------
- % | Change experimental settings in this section |
- % ----------------------------------------------------
- % ----------------------------------------------------
- % | Initial message to user: |
- % ----------------------------------------------------
- %
- % disp(' ')
- % disp('Detects Horizontal and Vertical eye movements,')
- % disp('Blinks and Discontinuities in dataset:')
- % disp([EEG.filename])
- % disp(' ')
- % ----------------------------------------------------
- % | Collect useful data from EEG structure |
- % ----------------------------------------------------
- %number of ICs=size(EEG.icawinv,1);
- %number of time points=size(EEG.data,2);
- if length(size(EEG.data))==3
-
- num_epoch=size(EEG.data,3);
-
- else
-
- num_epoch=1;
-
- end
- % Check the presence of ICA activations
- EEG.icaact = eeg_getica(EEG);
- topografie=EEG.icawinv'; %computes IC topographies
- % Topographies and time courses normalization
- %
- % disp(' ');
- % disp('Normalizing topographies...')
- % disp('Scaling time courses...')
- for i=1:size(EEG.icawinv,2) % number of ICs
-
- ScalingFactor=norm(topografie(i,:));
-
- topografie(i,:)=topografie(i,:)/ScalingFactor;
-
- if length(size(EEG.data))==3
- EEG.icaact(i,:,:)=ScalingFactor*EEG.icaact(i,:,:);
- else
- EEG.icaact(i,:)=ScalingFactor*EEG.icaact(i,:);
- end
-
- end
- %
- % disp('Done.')
- % disp(' ')
- % Variables memorizing artifacted ICs indexes
- blink=[];
- horiz=[];
- vert=[];
- disc=[];
- %% Check EEG channel position information
- nopos_channels=[];
- if iscolumn(EEG.chanlocs)
- EEG.chanlocs = EEG.chanlocs';
- end
- for el=1:length(EEG.chanlocs)
- if(any((isempty(EEG.chanlocs(1,el).X)|isempty(EEG.chanlocs(1,el).Y)|isempty(EEG.chanlocs(1,el).Z))&(isempty(EEG.chanlocs(1,el).theta)|isempty(EEG.chanlocs(1,el).radius)))) % !!! changed by LUCA 7/30/15
- nopos_channels=[nopos_channels el];
- end;
- end
- if ~isempty(nopos_channels)
- disp(['Warning : Channels ' num2str(nopos_channels) ' have incomplete location information. They will NOT be used to compute ADJUST spatial features']);
- disp(' ');
- end;
- pos_channels=setdiff(1:length(EEG.chanlocs),nopos_channels);
- pos_channels = intersect(pos_channels,EEG.icachansind); % Luca 10/15/15
- %% Feature extraction
- disp(' ')
- disp('Features Extraction:')
- %GDSF - General Discontinuity Spatial Feature
- disp('GDSF - General Discontinuity Spatial Feature...')
- GDSF = compute_GD_feat(topografie,EEG.chanlocs(1,pos_channels),size(EEG.icawinv,2));
- %SED - Spatial Eye Difference
- disp('SED - Spatial Eye Difference...')
- [SED,medie_left,medie_right]=computeSED_NOnorm(topografie,EEG.chanlocs(1,pos_channels),size(EEG.icawinv,2));
- %SAD - Spatial Average Difference
- disp('SAD - Spatial Average Difference...')
- try
- [SAD,var_front,var_back,mean_front,mean_back]=computeSAD(topografie,EEG.chanlocs(1,pos_channels),size(EEG.icawinv,2));
- catch
- [SAD,var_front,var_back,mean_front,mean_back] = deal(nan(1, size(EEG.icawinv,2))); % Luca
- end
- %SVD - Spatial Variance Difference between front zone and back zone
- diff_var=var_front-var_back;
- %epoch dynamic range, variance and kurtosis
- K=zeros(num_epoch,size(EEG.icawinv,2)); %kurtosis
- Kloc=K;
- Vmax=zeros(num_epoch,size(EEG.icawinv,2)); %variance
- % disp('Computing variance and kurtosis of all epochs...')
- for i=1:size(EEG.icawinv,2) % number of ICs
-
- for j=1:num_epoch
- Vmax(j,i)=var(EEG.icaact(i,:,j));
- % Kloc(j,i)=kurtosis(EEG.icaact(i,:,j));
- K(j,i)=kurt(EEG.icaact(i,:,j));
- end
- end
- % check that kurt and kurtosis give the same values:
- % [a,b]=max(abs(Kloc(:)-K(:)))
- %TK - Temporal Kurtosis
- disp('Temporal Kurtosis...')
- meanK=zeros(1,size(EEG.icawinv,2));
- for i=1:size(EEG.icawinv,2)
- if num_epoch>100
- meanK(1,i)=trim_and_mean(K(:,i));
- else meanK(1,i)=mean(K(:,i));
- end
-
- end
- %MEV - Maximum Epoch Variance
- disp('Maximum epoch variance...')
- maxvar=zeros(1,size(EEG.icawinv,2));
- meanvar=zeros(1,size(EEG.icawinv,2));
- for i=1:size(EEG.icawinv,2)
- if num_epoch>100
- maxvar(1,i)=trim_and_max(Vmax(:,i)');
- meanvar(1,i)=trim_and_mean(Vmax(:,i)');
- else
- maxvar(1,i)=max(Vmax(:,i));
- meanvar(1,i)=mean(Vmax(:,i));
- end
- end
- % MEV in reviewed formulation:
- nuovaV=maxvar./meanvar;
- %% Thresholds computation
- disp('Computing EM thresholds...')
- % soglia_K=EM(meanK);
- %
- % soglia_SED=EM(SED);
- %
- % soglia_SAD=EM(SAD);
- %
- % soglia_GDSF=EM(GDSF);
- %
- % soglia_V=EM(nuovaV);
- [soglia_K,med1_K,med2_K]=EM(meanK);
- [soglia_SED,med1_SED,med2_SED]=EM(SED);
- [soglia_SAD,med1_SAD,med2_SAD]=EM(SAD);
- [soglia_GDSF,med1_GDSF,med2_GDSF]=EM(GDSF);
- [soglia_V,med1_V,med2_V]=EM(nuovaV);
- %% Horizontal eye movements (HEM)
- horiz=intersect(intersect(find(SED>=soglia_SED),find(medie_left.*medie_right<0)),...
- (find(nuovaV>=soglia_V)));
- %% Vertical eye movements (VEM)
- vert=intersect(intersect(find(SAD>=soglia_SAD),find(medie_left.*medie_right>0)),...
- intersect(find(diff_var>0),find(nuovaV>=soglia_V)));
- %% Eye Blink (EB)
- blink=intersect ( intersect( find(SAD>=soglia_SAD),find(medie_left.*medie_right>0) ) ,...
- intersect ( find(meanK>=soglia_K),find(diff_var>0) ));
- %% Generic Discontinuities (GD)
- disc=intersect(find(GDSF>=soglia_GDSF),find(nuovaV>=soglia_V));
- %compute output variable
- art = nonzeros( union (union(blink,horiz) , union(vert,disc)) )'; %artifact ICs
- % these three are old outputs which are no more necessary in latest ADJUST version.
- soglia_D=0;
- soglia_DV=0;
- maxdin=zeros(1,size(EEG.icawinv,2));
- return
- % compute_GD_feat() - Computes Generic Discontinuity spatial feature
- %
- % Usage:
- % >> res = compute_GD_feat(topografie,canali,num_componenti);
- %
- % Inputs:
- % topografie - topographies vector
- % canali - EEG.chanlocs struct
- % num_componenti - number of components
- %
- % Outputs:
- % res - GDSF values
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function res = compute_GD_feat(topografie,canali,num_componenti)
- % Computes GDSF, discontinuity spatial feature
- % topografie is the topography weights matrix
- % canali is the structure EEG.chanlocs
- % num_componenti is the number of ICs
- % res is GDSF values
- xpos=[canali.X];ypos=[canali.Y];zpos=[canali.Z];
- pos=[xpos',ypos',zpos'];
- res=zeros(1,num_componenti);
- for ic=1:num_componenti
-
- % consider the vector topografie(ic,:)
-
- aux=[];
-
- for el=1:length(canali)-1
-
- P=pos(el,:); %position of current electrode
- d=pos-repmat(P,length(canali),1);
- %d=pos-repmat(P,62,1);
- dist=sqrt(sum((d.*d),2));
-
- [y,I]=sort(dist);
- repchas=I(2:11); % list of 10 nearest channels to el
- weightchas=exp(-y(2:11)); % respective weights, computed wrt distance
-
- aux=[aux abs(topografie(ic,el)-mean(weightchas.*topografie(ic,repchas)'))];
- % difference between el and the average of 10 neighbors
- % weighted according to weightchas
- end
-
- res(ic)=max(aux);
-
- end
- % computeSAD() - Computes Spatial Average Difference feature
- %
- % Usage:
- % >> [rapp,var_front,var_back,mean_front,mean_back]=computeSAD(topog,chanlocs,n);
- %
- % Inputs:
- % topog - topographies vector
- % chanlocs - EEG.chanlocs struct
- % n - number of ICs
- % nchannels - number of channels
- %
- % Outputs:
- % rapp - SAD values
- % var_front - Frontal Area variance values
- % var_back - Posterior Area variance values
- % mean_front - Frontal Area average values
- % mean_back - Posterior Area average values
- %
- %
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function [rapp,var_front,var_back,mean_front,mean_back]=computeSAD(topog,chanlocs,n)
- nchannels=length(chanlocs);
- %% Define scalp zones
- % Find electrodes in Frontal Area (FA)
- dimfront=0; %number of FA electrodes
- index1=zeros(1,nchannels); %indexes of FA electrodes
- for k=1:nchannels
- if (abs(chanlocs(1,k).theta)<60) && (chanlocs(1,k).radius>0.40) %electrodes are in FA
- dimfront=dimfront+1; %count electrodes
- index1(1,dimfront)=k;
- end
- end
- % Find electrodes in Posterior Area (PA)
- dimback=0;
- index3=zeros(1,nchannels);
- for h=1:nchannels
- if (abs(chanlocs(1,h).theta)>110)
- dimback=dimback+1;
- index3(1,dimback)=h;
- end
- end
- if dimfront*dimback==0
- disp('ERROR: no channels included in some scalp areas.')
- disp('Check channels distribution and/or change scalp areas definitions in computeSAD.m and computeSED_NOnorm.m')
- disp('ADJUST session aborted.')
- return
- end
- %% Outputs
- rapp=zeros(1,n); % SAD
- mean_front=zeros(1,n); % FA electrodes mean value
- mean_back=zeros(1,n); % PA electrodes mean value
- var_front=zeros(1,n); % FA electrodes variance value
- var_back=zeros(1,n); % PA electrodes variance value
- %% Output computation
- for i=1:n % for each topography
-
- %create FA electrodes vector
- front=zeros(1,dimfront);
- for h=1:dimfront
- front(1,h)=topog(i,index1(1,h));
- end
-
- %create PA electrodes vector
- back=zeros(1,dimback);
- for h=1:dimback
- back(1,h)=topog(i,index3(1,h));
- end
-
-
-
- %compute features
-
- rapp(1,i)=abs(mean(front))-abs(mean(back)); % SAD
- mean_front(1,i)=mean(front);
- mean_back(1,i)=mean(back);
- var_back(1,i)=var(back);
- var_front(1,i)=var(front);
-
- end
- % computeSED_NOnorm() - Computes Spatial Eye Difference feature
- % without normalization
- %
- % Usage:
- % >> [out,medie_left,medie_right]=computeSED_NOnorm(topog,chanlocs,n);
- %
- % Inputs:
- % topog - topographies vector
- % chanlocs - EEG.chanlocs struct
- % n - number of ICs
- % nchannels - number of channels
- %
- % Outputs:
- % out - SED values
- % medie_left - Left Eye area average values
- % medie_right- Right Eye area average values
- %
- %
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function [out,medie_left,medie_right]=computeSED_NOnorm(topog,chanlocs,n)
- nchannels=length(chanlocs);
- %% Define scalp zones
- % Find electrodes in Left Eye area (LE)
- dimleft=0; %number of LE electrodes
- index1=zeros(1,nchannels); %indexes of LE electrodes
- for k=1:nchannels
- if (-61<chanlocs(1,k).theta) && (chanlocs(1,k).theta<-35) && (chanlocs(1,k).radius>0.30) %electrodes are in LE
- dimleft=dimleft+1; %count electrodes
- index1(1,dimleft)=k;
- end
- end
- % Find electrodes in Right Eye area (RE)
- dimright=0; %number of RE electrodes
- index2=zeros(1,nchannels); %indexes of RE electrodes
- for g=1:nchannels
- if (34<chanlocs(1,g).theta) && (chanlocs(1,g).theta<61) && (chanlocs(1,g).radius>0.30) %electrodes are in RE
- dimright=dimright+1; %count electrodes
- index2(1,dimright)=g;
- end
- end
- % Find electrodes in Posterior Area (PA)
- dimback=0;
- index3=zeros(1,nchannels);
- for h=1:nchannels
- if (abs(chanlocs(1,h).theta)>110)
- dimback=dimback+1;
- index3(1,dimback)=h;
- end
- end
- if dimleft*dimright*dimback==0
- disp('ERROR: no channels included in some scalp areas.')
- disp('Check channels distribution and/or change scalp areas definitions in computeSAD.m and computeSED_NOnorm.m')
- disp('ADJUST session aborted.')
- return
- end
- %% Outputs
- out=zeros(1,n); %memorizes SED
- medie_left=zeros(1,n); %memorizes LE mean value
- medie_right=zeros(1,n); %memorizes RE mean value
- %% Output computation
- for i=1:n % for each topography
- %create LE electrodes vector
- left=zeros(1,dimleft);
- for h=1:dimleft
- left(1,h)=topog(i,index1(1,h));
- end
-
- %create RE electrodes vector
- right=zeros(1,dimright);
- for h=1:dimright
- right(1,h)=topog(i,index2(1,h));
- end
-
- %create PA electrodes vector
- back=zeros(1,dimback);
- for h=1:dimback
- back(1,h)=topog(i,index3(1,h));
- end
-
-
-
- %compute features
- out1=abs(mean(left)-mean(right));
- out2=var(back);
- out(1,i)=out1; % SED not notmalized
- medie_left(1,i)=mean(left);
- medie_right(1,i)=mean(right);
-
-
- end
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % EM - ADJUST package
- %
- % Performs automatic threshold on the digital numbers
- % of the input vector 'vec'; based on Expectation - Maximization algorithm
- % Reference paper:
- % Bruzzone, L., Prieto, D.F., 2000. Automatic analysis of the difference image
- % for unsupervised change detection.
- % IEEE Trans. Geosci. Remote Sensing 38, 1171:1182
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Usage:
- % >> [last,med1,med2,var1,var2,prior1,prior2]=EM(vec);
- %
- % Input: vec (row vector, to be thresholded)
- %
- % Outputs: last (threshold value)
- % med1,med2 (mean values of the Gaussian-distributed classes 1,2)
- % var1,var2 (variance of the Gaussian-distributed classes 1,2)
- % prior1,prior2 (prior probabilities of the Gaussian-distributed classes 1,2)
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function [last,med1,med2,var1,var2,prior1,prior2]=EM(vec)
- if size(vec,2)>1
- len=size(vec,2); %number of elements
- else
- vec=vec';
- len=size(vec,2);
- end
- c_FA=1; % False Alarm cost
- c_MA=1; % Missed Alarm cost
- med=mean(vec);
- standard=std(vec);
- mediana=(max(vec)+min(vec))/2;
- alpha1=0.01*(max(vec)-mediana); % initialization parameter/ righthand side
- alpha2=0.01*(mediana-min(vec)); % initialization parameter/ lefthand side
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % EXPECTATION
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- train1=[]; % Expectation of class 1
- train2=[];
- train=[]; % Expectation of 'unlabeled' samples
- for i=1:(len)
- if (vec(i)<(mediana-alpha2))
- train2=[train2 vec(i)];
- elseif (vec(i)>(mediana+alpha1))
- train1=[train1 vec(i)];
- else
- train=[train vec(i)];
- end
- end
- n1=length(train1);
- n2=length(train2);
- med1=mean(train1);
- med2=mean(train2);
- prior1=n1/(n1+n2);
- prior2=n2/(n1+n2);
- var1=var(train1);
- var2=var(train2);
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % MAXIMIZATION
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- count=0;
- dif_med_1=1; % difference between current and previous mean
- dif_med_2=1;
- dif_var_1=1; % difference between current and previous variance
- dif_var_2=1;
- dif_prior_1=1; % difference between current and previous prior
- dif_prior_2=1;
- stop=0.0001;
- while((dif_med_1>stop)&&(dif_med_2>stop)&&(dif_var_1>stop)&&(dif_var_2>stop)&&(dif_prior_1>stop)&&(dif_prior_2>stop))
-
- count=count+1;
-
- med1_old=med1;
- med2_old=med2;
- var1_old=var1;
- var2_old=var2;
- prior1_old=prior1;
- prior2_old=prior2;
- prior1_i=[];
- prior2_i=[];
-
- % FOLLOWING FORMULATION IS ACCORDING TO REFERENCE PAPER:
-
- for i=1:len
- prior1_i=[prior1_i prior1_old*Bayes(med1_old,var1_old,vec(i))/...
- (prior1_old*Bayes(med1_old,var1_old,vec(i))+prior2_old*Bayes(med2_old,var2_old,vec(i)))];
- prior2_i=[prior2_i prior2_old*Bayes(med2_old,var2_old,vec(i))/...
- (prior1_old*Bayes(med1_old,var1_old,vec(i))+prior2_old*Bayes(med2_old,var2_old,vec(i)))];
- end
-
-
- prior1=sum(prior1_i)/len;
- prior2=sum(prior2_i)/len;
- med1=sum(prior1_i.*vec)/(prior1*len);
- med2=sum(prior2_i.*vec)/(prior2*len);
- var1=sum(prior1_i.*((vec-med1_old).^2))/(prior1*len);
- var2=sum(prior2_i.*((vec-med2_old).^2))/(prior2*len);
-
- dif_med_1=abs(med1-med1_old);
- dif_med_2=abs(med2-med2_old);
- dif_var_1=abs(var1-var1_old);
- dif_var_2=abs(var2-var2_old);
- dif_prior_1=abs(prior1-prior1_old);
- dif_prior_2=abs(prior2-prior2_old);
-
- end
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % THRESHOLDING
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- k=c_MA/c_FA;
- a=(var1-var2)/2;
- b= ((var2*med1)-(var1*med2));
- c=(log((k*prior1*sqrt(var2))/(prior2*sqrt(var1)))*(var2*var1))+(((((med2)^2)*var1)-(((med1)^2)*var2))/2);
- rad=(b^2)-(4*a*c);
- if rad<0
- disp('Negative Discriminant!');
- return;
- end
- soglia1=(-b+sqrt(rad))/(2*a);
- soglia2=(-b-sqrt(rad))/(2*a);
- if ((soglia1<med2)||(soglia1>med1))
- last=soglia2;
- else
- last=soglia1;
- end
- if isnan(last) % TO PREVENT CRASHES
- last=mediana;
- end
- return
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- function prob=Bayes(med,var,point)
- if var==0
- prob=1;
- else
- prob=((1/(sqrt(2*pi*var)))*exp((-1)*((point-med)^2)/(2*var)));
- end
- % trim_and_max() - Computes maximum value from vector 'vettore'
- % after removing the top 1% of the values
- % (to be outlier resistant)
- %
- % Usage:
- % >> valore=trim_and_max(vettore);
- %
- % Inputs:
- % vettore - row vector
- %
- % Outputs:
- % valore - result
- %
- %
- % Author: Andrea Mognon, Center for Mind/Brain Sciences, University of
- % Trento, 2009
- % Motivation taken from the following comment to our paper:
- % "On page 11 the authors motivate the use of the max5 function when computing
- % Maximum Epoch Variance because the simple maximum would be too sensitive
- % to spurious outliers. This is a good concern, however the max5 function would
- % still be sensitive to spurious outliers for very large data sets. In other words, if
- % the data set is large enough, one will be very likely to record more than five
- % outliers. The authors should use a trimmed max function that computes the
- % simple maximum after the top say .1% of the values have been removed from
- % consideration. This rejection criteria scales appropriately with the size of the data
- % set."
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function valore=trim_and_max(vettore)
- dim=floor(.01*size(vettore,2)); % = 1% of vector length
- tmp=sort(vettore);
- valore= tmp(length(vettore)-dim);
- % trim_and_mean() - Computes average value from vector 'vettore'
- % after removing the top .1% of the values
- % (to be outlier resistant)
- %
- % Usage:
- % >> valore=trim_and_mean(vettore);
- %
- % Inputs:
- % vettore - row vector
- %
- % Outputs:
- % valore - result
- %
- % Copyright (C) 2009-2014 Andrea Mognon (1) and Marco Buiatti (2),
- % (1) Center for Mind/Brain Sciences, University of Trento, Italy
- % (2) INSERM U992 - Cognitive Neuroimaging Unit, Gif sur Yvette, France
- %
- % 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
- function valore=trim_and_mean(vettore)
- dim=floor(.01*size(vettore,2)); % = 1% of vector length
- tmp=sort(vettore);
- valore= mean (tmp(1:(length(vettore)-dim)));
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% END ADJUST CODE%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% BELOW IS FASTER CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- function list_properties = component_properties(EEG,blink_chans,lpf_band)
- % Copyright (C) 2010 Hugh Nolan, Robert Whelan and Richard Reilly, Trinity College Dublin,
- % Ireland
- % nolanhu@tcd.ie, robert.whelan@tcd.ie
- %
- % 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
- list_properties = [];
- %
- if isempty(EEG.icaweights)
- fprintf('No ICA data.\n');
- return;
- end
- if ~exist('lpf_band','var') || length(lpf_band)~=2 || ~any(lpf_band)
- ignore_lpf=1;
- else
- ignore_lpf=0;
- end
- delete_activations_after=0;
- if ~isfield(EEG,'icaact') || isempty(EEG.icaact)
- delete_activations_after=1;
- EEG.icaact = eeg_getica(EEG);
- end
- try
- checkfunctionmatlab('pwelch', 'signal_toolbox')
- end
- for u = 1:size(EEG.icaact,1)
- [spectra(u,:) freqs] = pwelch(EEG.icaact(u,:),[],[],(EEG.srate),EEG.srate);
- end
- list_properties = zeros(size(EEG.icaact,1),5); %This 5 corresponds to number of measurements made.
- for u=1:size(EEG.icaact,1)
- measure = 1;
- % TEMPORAL PROPERTIES
-
- % 1 Median gradient value, for high frequency stuff
- list_properties(u,measure) = median(diff(EEG.icaact(u,:)));
- measure = measure + 1;
-
- % 2 Mean slope around the LPF band (spectral)
- if ignore_lpf
- list_properties(u,measure) = 0;
- else
- list_properties(u,measure) = mean(diff(10*log10(spectra(u,find(freqs>=lpf_band(1),1):find(freqs<=lpf_band(2),1,'last')))));
- end
- measure = measure + 1;
-
- % SPATIAL PROPERTIES
-
- % 3 Kurtosis of spatial map (if v peaky, i.e. one or two points high
- % and everywhere else low, then it's probably noise on a single
- % channel)
- list_properties(u,measure) = kurt(EEG.icawinv(:,u));
- measure = measure + 1;
-
- % OTHER PROPERTIES
-
- % 4 Hurst exponent
- list_properties(u,measure) = hurst_exponent(EEG.icaact(u,:));
- measure = measure + 1;
-
- % 10 Eyeblink correlations
- if (exist('blink_chans','var') && ~isempty(blink_chans))
- for v = 1:length(blink_chans)
- if ~(max(EEG.data(blink_chans(v),:))==0 && min(EEG.data(blink_chans(v),:))==0);
- f = corrcoef(EEG.icaact(u,:),EEG.data(blink_chans(v),:));
- x(v) = abs(f(1,2));
- else
- x(v) = v;
- end
- end
- list_properties(u,measure) = max(x);
- measure = measure + 1;
- end
- end
- for u = 1:size(list_properties,2)
- list_properties(isnan(list_properties(:,u)),u)=nanmean(list_properties(:,u));
- list_properties(:,u) = list_properties(:,u) - median(list_properties(:,u));
- end
- if delete_activations_after
- EEG.icaact=[];
- end
- % The Hurst exponent
- %--------------------------------------------------------------------------
- % This function does dispersional analysis on a data series, then does a
- % Matlab polyfit to a log-log plot to estimate the Hurst exponent of the
- % series.
- %
- % This algorithm is far faster than a full-blown implementation of Hurst's
- % algorithm. I got the idea from a 2000 PhD dissertation by Hendrik J
- % Blok, and I make no guarantees whatsoever about the rigor of this approach
- % or the accuracy of results. Use it at your own risk.
- %
- % Bill Davidson
- % 21 Oct 2003
- function [hurst] = hurst_exponent(data0) % data set
- data=data0; % make a local copy
- [M,npoints]=size(data0);
- yvals=zeros(1,npoints);
- xvals=zeros(1,npoints);
- data2=zeros(1,npoints);
- index=0;
- binsize=1;
- while npoints>4
-
- y=std(data);
- index=index+1;
- xvals(index)=binsize;
- yvals(index)=binsize*y;
-
- npoints=fix(npoints/2);
- binsize=binsize*2;
- for ipoints=1:npoints % average adjacent points in pairs
- data2(ipoints)=(data(2*ipoints)+data((2*ipoints)-1))*0.5;
- end
- data=data2(1:npoints);
-
- end % while
- xvals=xvals(1:index);
- yvals=yvals(1:index);
- logx=log(xvals);
- logy=log(yvals);
- p2=polyfit(logx,logy,1);
- hurst=p2(1); % Hurst exponent is the slope of the linear fit of log-log plot
- return;
- function [lengths] = min_z(list_properties, rejection_options)
- if (~exist('rejection_options', 'var'))
- rejection_options.measure = ones(1, size(list_properties, 2));
- rejection_options.z = 3*ones(1, size(list_properties, 2));
- end
- rejection_options.measure = logical(rejection_options.measure);
- zs = list_properties - repmat(mean(list_properties, 1), size(list_properties, 1), 1);
- zs = zs./repmat(std(zs, [], 1), size(list_properties, 1), 1);
- zs(isnan(zs)) = 0;
- all_l = abs(zs) > repmat(rejection_options.z, size(list_properties, 1), 1);
- lengths = any(all_l(:, rejection_options.measure), 2);
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% END FASTER CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% BEGIN MARA CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % MARA() - Automatic classification of multiple artifact components
- % Classies artifactual ICs based on 6 features from the time domain,
- % the frequency domain, and the pattern
- %
- % Usage:
- % >> [artcomps, info] = MARA(EEG);
- %
- % Inputs:
- % EEG - input EEG structure
- %
- % Outputs:
- % artcomps - array containing the numbers of the artifactual
- % components
- % info - struct containing more information about MARA classification
- % .posterior_artefactprob : posterior probability for each
- % IC of being an artefact
- % .normfeats : <6 x nIC > features computed by MARA for each IC,
- % normalized by the training data
- % The features are: (1) Current Density Norm, (2) Range
- % in Pattern, (3) Local Skewness of the Time Series,
- % (4) Lambda, (5) 8-13 Hz, (6) FitError.
- %
- % For more information see:
- % I. Winkler, S. Haufe, and M. Tangermann, Automatic classification of artifactual ICA-components
- % for artifact removal in EEG signals, Behavioral and Brain Functions, 7, 2011.
- %
- % See also: processMARA()
- % Copyright (C) 2013 Irene Winkler and Eric Waldburger
- % Berlin Institute of Technology, Germany
- %
- % 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
- function [artcomps, info] = MARA(EEG)
- %%%%%%%%%%%%%%%%%%%%
- %% Calculate features from the pattern (component map)
- %%%%%%%%%%%%%%%%%%%%
- % extract channel labels
- clab = {};
- for i=1:length(EEG.chanlocs)
- clab{i} = EEG.chanlocs(i).labels;
- end
- % cut to channel labels common with training data
- addpath SASICA-master
- load('fv_training_MARA'); %load struct fv_tr
- [clab_common i_te i_tr ] = intersect(upper(clab), upper(fv_tr.clab));
- clab_common = fv_tr.clab(i_tr);
- if length(clab_common) == 0
- error(['There were no matching channeldescriptions found.' , ...
- 'MARA needs channel labels of the form Cz, Oz, F3, F4, Fz, etc. Aborting.'])
- end
- patterns = (EEG.icawinv(i_te,:));
- [M100 idx] = get_M100_ADE(clab_common); %needed for Current Density Norm
- disp('MARA is computing features. Please wait');
- %standardize patterns
- patterns = patterns./repmat(std(patterns,0,1),length(patterns(:,1)),1);
- %compute current density norm
- feats(1,:) = log(sqrt(sum((M100*patterns(idx,:)).^2)));
- %compute spatial range
- feats(2,:) = log(max(patterns) - min(patterns));
- %%%%%%%%%%%%%%%%%%%%
- %% Calculate time and frequency features
- %%%%%%%%%%%%%%%%%%%%
- %compute time and frequency features (Current Density Norm, Range Within Pattern,
- %Average Local Skewness, Band Power 8 - 13 Hz)
- feats(3:6,:) = extract_time_freq_features(EEG);
- disp('Features ready');
- %%%%%%%%%%%%%%%%%%%%%%
- %% Adapt train features to clab
- %%%%%%%%%%%%%%%%%%%%
- fv_tr.pattern = fv_tr.pattern(i_tr, :);
- fv_tr.pattern = fv_tr.pattern./repmat(std(fv_tr.pattern,0,1),length(fv_tr.pattern(:,1)),1);
- fv_tr.x(2,:) = log(max(fv_tr.pattern) - min(fv_tr.pattern));
- fv_tr.x(1,:) = log(sqrt(sum((M100 * fv_tr.pattern).^2)));
- %%%%%%%%%%%%%%%%%%%%
- %% Classification
- %%%%%%%%%%%%%%%%%%%%
- [C, foo, posterior] = classify(feats',fv_tr.x',fv_tr.labels(1,:));
- artcomps = find(C == 0)';
- info.posterior_artefactprob = posterior(:, 1)';
- info.normfeats = (feats - repmat(mean(fv_tr.x, 2), 1, size(feats, 2)))./ ...
- repmat(std(fv_tr.x,0, 2), 1, size(feats, 2));
- function features = extract_time_freq_features(EEG)
- % - 1st row: Average Local Skewness
- % - 2nd row: lambda
- % - 3rd row: Band Power 8 - 13 Hz
- % - 4rd row: Fit Error
- %
- data = EEG.data(EEG.icachansind,:,:);
- fs = EEG.srate; %sampling frequency
- % transform epoched data into continous data
- data = data(:,:);
- %downsample (to 100-200Hz)
- factor = max(floor(EEG.srate/100),1);
- data = data(:, 1:factor:end);
- fs = round(fs/factor);
- %compute icaactivation and standardise variance to 1
- icacomps = (EEG.icaweights * EEG.icasphere * data)';
- icacomps = icacomps./repmat(std(icacomps,0,1),length(icacomps(:,1)),1);
- icacomps = icacomps';
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Calculate featues
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- for ic=1:size(icacomps,1) %for each component
- fprintf('.');
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Proc Spectrum for Channel
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- [pxx, freq] = pwelch(icacomps(ic,:), ones(1, fs), [], fs, fs);
- pxx = 10*log10(pxx * fs/2);
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % The average log band power between 8 and 13 Hz
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- p = 0;
- for i = 8:13
- p = p + pxx(find(freq == i,1));
- end
- Hz8_13 = p / (13-8+1);
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % lambda and FitError: deviation of a component's spectrum from
- % a protoptypical 1/frequency curve
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- p1.x = 2; %first point: value at 2 Hz
- p1.y = pxx(find(freq == p1.x,1));
-
- p2.x = 3; %second point: value at 3 Hz
- p2.y = pxx(find(freq == p2.x,1));
-
- %third point: local minimum in the band 5-13 Hz
- p3.y = min(pxx(find(freq == 5,1):find(freq == 13,1)));
- p3.x = freq(find(pxx == p3.y,1));
-
- %fourth point: min - 1 in band 5-13 Hz
- p4.x = p3.x - 1;
- p4.y = pxx(find(freq == p4.x,1));
-
- %fifth point: local minimum in the band 33-39 Hz
- p5.y = min(pxx(find(freq == 33,1):find(freq == 39,1)));
- p5.x = freq(find(pxx == p5.y,1));
-
- %sixth point: min + 1 in band 33-39 Hz
- p6.x = p5.x + 1;
- p6.y = pxx(find(freq == p6.x,1));
-
- pX = [p1.x; p2.x; p3.x; p4.x; p5.x; p6.x];
- pY = [p1.y; p2.y; p3.y; p4.y; p5.y; p6.y];
-
- myfun = @(x,xdata)(exp(x(1))./ xdata.^exp(x(2))) - x(3);
- xstart = [4, -2, 54];
- fittedmodel = lsqcurvefit(myfun,xstart,double(pX),double(pY), [], [], optimset('Display', 'off'));
-
- %FitError: mean squared error of the fit to the real spectrum in the band 2-40 Hz.
- ts_8to15 = freq(find(freq == 8) : find(freq == 15));
- fs_8to15 = pxx(find(freq == 8) : find(freq == 15));
- fiterror = log(norm(myfun(fittedmodel, ts_8to15)-fs_8to15)^2);
-
- %lambda: parameter of the fit
- lambda = fittedmodel(2);
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Averaged local skewness 15s
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- interval = 15;
- abs_local_scewness = [];
- for i=1:interval:length(icacomps(ic,:))/fs-interval
- abs_local_scewness = [abs_local_scewness, abs(skewness(icacomps(ic, i * fs:(i+interval) * fs)))];
- end
-
- if isempty(abs_local_scewness)
- % error('MARA needs at least 15ms long ICs to compute its features.')
- mean_abs_local_scewness_15 = nan;
- else
- mean_abs_local_scewness_15 = log(mean(abs_local_scewness));
- end;
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %Append Features
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- features(:,ic)= [mean_abs_local_scewness_15, lambda, Hz8_13, fiterror];
- end
- disp('.');
- function [M100, idx_clab_desired] = get_M100_ADE(clab_desired)
- % [M100, idx_clab_desired] = get_M100_ADEC(clab_desired)
- %
- % IN clab_desired - channel setup for which M100 should be calculated
- % OUT M100
- % idx_clab_desired
- % M100 is the matrix such that feature = norm(M100*ica_pattern(idx_clab_desired), 'fro')
- %
- % (c) Stefan Haufe
- lambda = 100;
- load inv_matrix_icbm152; %L (forward matrix 115 x 2124 x 3), clab (channel labels)
- [cl_ ia idx_clab_desired] = intersect(clab, clab_desired);
- F = L(ia, :, :); %forward matrix for desired channels labels
- [n_channels m foo] = size(F); %m = 2124, number of dipole locations
- F = reshape(F, n_channels, 3*m);
- %H - matrix that centralizes the pattern, i.e. mean(H*pattern) = 0
- H = eye(n_channels) - ones(n_channels, n_channels)./ n_channels;
- %W - inverse of the depth compensation matrix Lambda
- W = sloreta_invweights(L);
- L = H*F*W;
- %We have inv(L'L +lambda eye(size(L'*L))* L' = L'*inv(L*L' + lambda
- %eye(size(L*L')), which is easier to calculate as number of dimensions is
- %much smaller
- %calulate the inverse of L*L' + lambda * eye(size(L*L')
- [U D] = eig(L*L');
- d = diag(D);
- di = d+lambda;
- di = 1./di;
- di(d < 1e-10) = 0;
- inv1 = U*diag(di)*U'; %inv1 = inv(L*L' + lambda *eye(size(L*L'))
- %get M100
- M100 = L'*inv1*H;
- function W = sloreta_invweights(LL)
- % inverse sLORETA-based weighting
- %
- % Synopsis:
- % W = sloreta_invweights(LL);
- %
- % Arguments:
- % LL: [M N 3] leadfield tensor
- %
- % Returns:
- % W: [3*N 3*N] block-diagonal matrix of weights
- %
- % Stefan Haufe, 2007, 2008
- %
- % License
- %
- % 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 3 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, see http://www.gnu.org/licenses/.
- [M N NDUM]=size(LL);
- L=reshape(permute(LL, [1 3 2]), M, N*NDUM);
- L = L - repmat(mean(L, 1), M, 1);
- T = L'*pinv(L*L');
- W = spalloc(N*NDUM, N*NDUM, N*NDUM*NDUM);
- for ivox = 1:N
- W(NDUM*(ivox-1)+(1:NDUM), NDUM*(ivox-1)+(1:NDUM)) = (T(NDUM*(ivox-1)+(1:NDUM), :)*L(:, NDUM*(ivox-1)+(1:NDUM)))^-.5;
- end
- ind = [];
- for idum = 1:NDUM
- ind = [ind idum:NDUM:N*NDUM];
- end
- W = W(ind, ind);
- function [i_te, i_tr] = findconvertedlabels(pos_3d, chanlocs)
- % IN pos_3d - 3d-positions of training channel labels
- % chanlocs - EEG.chanlocs structure of data to be classified
- %compute spherical coordinates theta and phi for the training channel
- %label
- [theta, phi, r] = cart2sph(pos_3d(1,:),pos_3d(2,:), pos_3d(3,:));
- theta = theta - pi/2;
- theta(theta < -pi) = theta(theta < -pi) + 2*pi;
- theta = theta*180/pi;
- phi = phi * 180/pi;
- theta(find(pos_3d(1,:) == 0 & pos_3d(2,:) == 0)) = 0; %exception for Cz
- clab_common = {};
- i_te = [];
- i_tr = [];
- %For each channel in EEG.chanlocs, try to find matching channel in
- %training data
- for chan = 1:length(chanlocs)
- if not(isempty(chanlocs(chan).sph_phi))
- idx = find((theta <= chanlocs(chan).sph_theta + 6) ...
- & (theta >= chanlocs(chan).sph_theta - 6) ...
- & (phi <= chanlocs(chan).sph_phi + 6) ...
- & (phi >= chanlocs(chan).sph_phi - 6));
- if not(isempty(idx))
- i_tr = [i_tr, idx(1)];
- i_te = [i_te, chan];
- end
- end
- end
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%% END MARA CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|