-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathcrc_par_iica.m
256 lines (227 loc) · 9.88 KB
/
crc_par_iica.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
function Do = crc_par_iica(Di)
% Pulse artefact rejection with a iICA method.
% ICA is applied multiple times on the same stretch of data:
% at each repetition the artefact-related component are automatically
% selected and removed from the data. The N-different-times corrected data
% are then averaged.
%_______________________________________________________________________
% Copyright (C) 2011 Cyclotron Research Centre
% Written by C. Phillips, 2011.
% Cyclotron Research Centre, University of Liege, Belgium
% $Id$
crcdef = crc_get_defaults('par');
prefiICA = crcdef.iicapref;
% Recover Peaks
Peaks = Di.CRC.EKGPeaks;
% Recover number of iterations
nit = Di.cache.nit;
% Initializaing the cleaned EEG datafile
fn_dat = fullfile(spm_str_manip(fnamedat(Di),'H'), ...
[ prefiICA, spm_str_manip(fnamedat(Di),'t')]);
if exist(fullfile(path(Di), fn_dat),'file')
% This check is because I want append data in the new file
% I have to make sure that it does not exist yet.
delete(fullfile(path(Di), fn_dat))
disp(['!!! WARNING : EXISTING ',fn_dat,' FILE OVERWRITTEN !!!' ])
end
% create empty object
Do = clone(Di,fn_dat);
% Creating a mean BCG template
disp('................................')
disp('.... Creating BCG template .....')
disp('................................')
TEMPLATE = zeros(1,Di.nsamples);
for ipoint = 1:size(Peaks,2)
% use 1/5 sec
TEMPLATE(Peaks(ipoint):Peaks(ipoint)+Di.fsample/5) = 1;
end
% Split good EEG channel, to correct, and others
l_eeg = Di.cache.l2cor;
l_other = 1:Di.nchannels;
l_other(l_eeg) = [];
% Computing the bounds of the sweeps that will be processed 1 by 1
beatstep = ceil(3/2*length(l_eeg).^2);
% x-beat step to scan the data
beatsteplength = 2*beatstep;
% length of EEG data processed by steps (in number of bins)
% #points ~= 3*N.^2
if beatsteplength>Di.nsamples
disp('******************************************')
disp('**** WARNING: Not enough data points ****')
disp('**** to proceed with ICA ! ****')
disp('**** Still calculating but can''t ****')
disp('**** guarantee the results... ****')
disp('******************************************')
% number of steps needed and bounds of chunks
nbeatstep = 1;
CHKDTB = [1 Di.nsamples];
bounds_mean = 1:Di.nsamples;
bounds_keep = Di.nsamples;
else
% number of steps needed and bounds of chunks
nbeatstep = floor(size(TEMPLATE,2)/beatstep);
CHKDTB = [((0:nbeatstep-1)*beatstep)'+1 ...
((0:nbeatstep-1)*beatstep)'+beatsteplength];
CHKDTB(end) = Di.nsamples;
bounds_mean = 1:beatsteplength/2;
bounds_keep = (beatsteplength/2+1):beatsteplength ;
end
% Computing ICA
keepEEG = [];
meanEEG = [];
for jbeatstep = 1:nbeatstep
data = Di(l_eeg, CHKDTB(jbeatstep,1):CHKDTB(jbeatstep,2));
tmpdata = reshape( data, size(data,1), size(data,2));
tmpdata = detrend(tmpdata','constant')'; % zero mean
tmprank = rank(tmpdata(:,1:floor(size(tmpdata,2)/2)));
AV_cleanedEEG = zeros(size(data,1),size(data,2), nit);
% Creating a binary template
% The main BCG artefact should occur within 500 ms after the
% systole starts.
tt = TEMPLATE(1,CHKDTB(jbeatstep,1):CHKDTB(jbeatstep,2));
% '-2' because I get rid of the EOG and EKG
epochlength = round(prctile(diff(Peaks),99)*500/1000);
stag = 1;
nstag = epochlength/stag; % nombre de pas pour couvrir RR
tt = [tt;zeros(nstag-1,size(tt,2))];
for istag = 2:nstag
tt(istag,:) = [zeros(1,stag) tt(istag-1,1:end-stag)];
end
% used later on in the code, for the correlation bit
d_tt = detrend(tt','constant');
ssd_tt = sqrt(sum(d_tt.^2)');
RRbound = max(diff(Peaks));
RRmean = mean(diff(Peaks));
for jnit = 1:nit % nit iterations to get a mean clean set
clc
disp('..............................................')
disp(['.... File ' num2str(ifile) '/' ...
num2str(size(files,1)) '; step ' ...
num2str(jbeatstep) '/' num2str(nbeatstep) ...
'; itération ' num2str(jnit) ' ....'])
disp('.... Computing the independent components ....')
disp('..............................................')
% if there is no rank reduction then, don't use it!
% This avoids some large matrix multiplication
if tmprank == size(tmpdata,1)
[icaweights,icasphere] = runica( tmpdata, ...
'lrate', 0.001 ,'verbose','off' );
else
[icaweights,icasphere] = runica( tmpdata, ...
'lrate', 0.001, 'pca', tmprank ,'verbose','off' );
end
% use the detrended data.
icaact = (icaweights*icasphere)*tmpdata;
invweights = pinv(icaweights*icasphere);
% Choosing the relevant ic automatically
disp('......................................................')
disp('.... Automatically identifying the BCG components ....')
disp('......................................................')
% Initializing correlation variables
CC = zeros(1,size(icaact,1));
for icomp = 1:size(icaact,1)
% Creating the binary sweep ttt, to be compared with the
% binary template tt
dicaact = icaact(icomp,:);
% as data are detrended, mean=0, just look at
% the variances.
QRSidentifier = find(dicaact > 2*std(dicaact));
diff_QRS = diff(QRSidentifier);
ica_QRS = diff_QRS(diff_QRS>60/180*Di.fsample);
% number of point between RR if 180 bpm
%HR = 60sec/min; 200 bpm; Di.Radcpoints/sec
if ~isempty(ica_QRS)
meanicaQRS = prctile(ica_QRS,50);
% If this icomp is a bcg_ica, there should be
% an event nearly at each beat.
% We check that there is no gap of more than
% 5 max(RR intervals) between the elements of ttt
% and that the mean RR is ~= mean RR+- 100 points
if max(ica_QRS) < 5*RRbound && ...
(meanicaQRS < RRmean+100 && meanicaQRS > RRmean-100 )
% create ttt directly for the list of
% useful peak detections.
ttt = zeros(size(tt,2),1);
for ipoint = find(diff_QRS>60/180*Di.fsample)
ttt(QRSidentifier(ipoint):QRSidentifier(ipoint)+Di.fsample/5) = 1;
end
% make things much faster by avoiding
% corrcoef routine and calculating directly the
% coef of interest, for all the stags
% considered at once!
if any(ttt)
d_ttt = ttt-mean(ttt);
cc = (d_tt'*d_ttt)./(ssd_tt*sqrt(d_ttt'*d_ttt));
CC(icomp) = prctile(abs(cc),99);
end
end
end
end
icaoi_index = find(CC> mean(CC) + std(CC)) ;
% skewness of ica_bcg should be high
% calculate skewness only once
sk_icaact = skewness(icaact(icaoi_index,:)');
if any(sk_icaact< 0.33) % ~= prctile(SK,5)
disp('WARNING SOME ICAs were discarded')
icaoi_index(sk_icaact< 0.33) = [];
% 0.3 is the cutoff skewness computed empirically
end
[cleanedEEG] = compvar(data, icaact, ...
invweights, setdiff(1:size(icaact,1),icaoi_index));
cleanedEEG = detrend(cleanedEEG','constant');
% zero mean, to avoid offset avery beatstep
cleanedEEG = cleanedEEG';
AV_cleanedEEG(:,:,jnit) = cleanedEEG;
end % end jnit
p_cleanedEEG = mean(AV_cleanedEEG,3);
% add the other channels, in the same order !!!
cleanedEEG = zeros(Di.nchannels,size(p_cleanedEEG,2));
cleanedEEG(l_eeg,:) = p_cleanedEEG;
cleanedEEG(l_other,:) = Di( l_other, ...
CHKDTB(jbeatstep,1):CHKDTB(jbeatstep,2),1);
% Mean, Keep, Write
% tomean : the first half of the epoch;
% keepEEG = the second half of an epoch
% meanEEG = the mean of the present tomean and the previous keepEEG
if diff(CHKDTB(jbeatstep,:)) < beatstep
% if last cleanEEG smaller than beatstep
tomeanEEG = cleanedEEG;
meanEEG = [(tomeanEEG+keepEEG(:,1:size(tomeanEEG,2)))/2 ...
keepEEG(:,size(tomeanEEG,2)+1:end)];
elseif diff(CHKDTB(jbeatstep,:)) >= beatstep
% if cleanEEG is larger than beatstep but possibly
% smaller than 2*beatstep
if jbeatstep == 1
% if first pass, no keepEEG available, mean = tomean
tomeanEEG = cleanedEEG(:,bounds_mean);
meanEEG = tomeanEEG;
if size(cleanedEEG,2) < beatsteplength
% in case it is a very short EEG bit
keepEEG = cleanedEEG(:,bounds_keep(1):end);
else
keepEEG = cleanedEEG(:,bounds_keep);
end
elseif jbeatstep > 1 && jbeatstep < nbeatstep
% after 1st pass, mean tomean with keepEEG of
% the previous pass
meanEEG = (keepEEG+cleanedEEG(:,bounds_mean))/2;
keepEEG = cleanedEEG(:,bounds_keep);
elseif jbeatstep == nbeatstep
% if last pass, mean tomean and previous keepEEG
% and add the present (remaining) keepEEG
bounds_keep = (beatstep+1):size(cleanedEEG,2);
meanEEG = [(keepEEG+cleanedEEG(:,bounds_mean))/2 ...
cleanedEEG(:,bounds_keep)];
end
end
% detrending to avoid steps in the reconstructed EEG.
% This possibly induces a change in spectrum a period =
% beatstep (11532)/250 = 46 s , i.e. 0.021 Hz
meanEEG = detrend(meanEEG','constant');
meanEEG = meanEEG';
% writing the first part of cleanedEEG == meanEEG
% CLEANEEG.data.scale = ones(size(eeg.data, 1), 1);
Do(:,CHKDTB(jbeatstep,1):CHKDTB(jbeatstep,2)) = meanEEG;
% fwrite(fpd_clean, meanEEG, 'float32');
end % jbeatstep
return