Authored by Anthony Boyer

New detects c3,p3,c4,p4 duplicates and excludes the scalp channels.

@@ -145,20 +145,9 @@ for i0 = 1:size(t,1) @@ -145,20 +145,9 @@ for i0 = 1:size(t,1)
145 (any(Sensors.label{i1} == '''') && strcmp(strrep(upper(Sensors.label{i1}), '''', 'p'), Name{iChanPos})) 145 (any(Sensors.label{i1} == '''') && strcmp(strrep(upper(Sensors.label{i1}), '''', 'p'), Name{iChanPos}))
146 disp(['ImaGIN> WARNING: Channel name conflict: ' Sensors.label{i1} ' matched with ' Name{iChanPos} ', ' chMatchLog{iPrevious,1} ' discarded.']); 146 disp(['ImaGIN> WARNING: Channel name conflict: ' Sensors.label{i1} ' matched with ' Name{iChanPos} ', ' chMatchLog{iPrevious,1} ' discarded.']);
147 chMatchLog(iPrevious,:) = []; 147 chMatchLog(iPrevious,:) = [];
148 - % If both labels are the same regardless of the case, pick the one with uppercase (intra-recording). 148 + % If both labels are the same regardless of the case, raises an error.
149 elseif strcmpi(chMatchLog{iPrevious,1},Sensors.label{i1}) 149 elseif strcmpi(chMatchLog{iPrevious,1},Sensors.label{i1})
150 - uppercase_label = find([sum(isstrprop(chMatchLog{iPrevious,1},'upper'))>0 sum(isstrprop(Sensors.label{i1},'upper'))>0]);  
151 - if numel(uppercase_label) == 1  
152 - disp(['ImaGIN> WARNING: Channel name conflict: ' Sensors.label{i1} ' matched with ' Name{iChanPos} ', ' chMatchLog{iPrevious,1} ' discarded.']);  
153 - % Rename the scalp electrode and remove the coordinates  
154 - scalp_idx = find(strcmp(SpmMat.D.sensors.eeg.label,chMatchLog{iPrevious,1}));  
155 - Sensors.elecpos(scalp_idx,:) = nan(1,3);  
156 - Sensors.chanpos(scalp_idx,:) = nan(1,3);  
157 - Sensors.label{scalp_idx} = ['SCALP' Sensors.label{scalp_idx}];  
158 - chMatchLog(iPrevious,:) = [];  
159 - else  
160 - error(['Duplicated label found: ' Sensors.label{i1}]);  
161 - end 150 + error(['Duplicated label found: ' Sensors.label{i1}]);
162 else 151 else
163 disp(['ImaGIN> WARNING: Channel name conflict: ' chMatchLog{iPrevious,1} ' matched with ' Name{iChanPos} ', ' Sensors.label{i1} ' discarded.']); 152 disp(['ImaGIN> WARNING: Channel name conflict: ' chMatchLog{iPrevious,1} ' matched with ' Name{iChanPos} ', ' Sensors.label{i1} ' discarded.']);
164 iChanPos = []; 153 iChanPos = [];
@@ -178,7 +178,11 @@ for i = 1:length(AllNames) @@ -178,7 +178,11 @@ for i = 1:length(AllNames)
178 continue; 178 continue;
179 elseif isSEEG && ismember(lower(AllNames{i}), {'o1','o2'}) && ~any(ismember({'o3','o4','o4','o5','o6','o7','o8','o9','o10','o11','o12','o13','o14','o15','o16','o17','o18'}, lower(AllNames))) 179 elseif isSEEG && ismember(lower(AllNames{i}), {'o1','o2'}) && ~any(ismember({'o3','o4','o4','o5','o6','o7','o8','o9','o10','o11','o12','o13','o14','o15','o16','o17','o18'}, lower(AllNames)))
180 continue; 180 continue;
181 - % Otherwise: accept 181 + elseif isSEEG && ismember(lower(AllNames{i}), {'c3','p3','c4','p4'}) && numel(find(ismember(lower(AllNames),lower(AllNames(i)))))>1 && is_scalp(i,AllNames,AllTags)
  182 + disp(['Excluding: ' AllNames{i} ' -> detected as a SCALP channel.']);
  183 + continue; % if c3 exists more than once AND is NOT preceded by c2 OR c5, is considered a scalp channel and will not be selected. Same for p3, c4, p4.
  184 +
  185 + % Otherwise: accept
182 else 186 else
183 iSel(end+1) = i; 187 iSel(end+1) = i;
184 end 188 end
@@ -201,3 +205,21 @@ iSel = [iSel(iOrderSel), iEcg]; @@ -201,3 +205,21 @@ iSel = [iSel(iOrderSel), iEcg];
201 % Return lists of selected channels and electrode names 205 % Return lists of selected channels and electrode names
202 chTags = AllTags; 206 chTags = AllTags;
203 chInd = AllInd; 207 chInd = AllInd;
  208 +end
  209 +
  210 +function scalp_bool = is_scalp(i,AllNames,AllTags)
  211 + %% For a given (duplicated) label X, checks if X2 OR X5 exist. If not, is considered as a scalp label.
  212 + duplicate_label_idxs = find(ismember(lower(AllNames),lower(AllNames(i)))); % List of duplicates
  213 + current_duplicate_idx = find(duplicate_label_idxs == i); % Duplicate being evaluated (infers i is always a duplicate index when this function is called)
  214 + if current_duplicate_idx == numel(duplicate_label_idxs) % Last duplicate in the duplicate_label_idxs list
  215 + upper_range = i+1:numel(AllNames);
  216 + else
  217 + upper_range = i+1:duplicate_label_idxs(current_duplicate_idx+1);
  218 + end
  219 + if current_duplicate_idx == 1 % First duplicate in the duplicate_label_idxs list
  220 + lower_range = 1:i-1;
  221 + else
  222 + lower_range = duplicate_label_idxs(current_duplicate_idx-1):i-1;
  223 + end
  224 + scalp_bool = ~(ismember(lower([AllTags{i} '2']),lower(AllNames(lower_range))) || ismember(lower([AllTags{i} '5']),lower(AllNames(upper_range))));
  225 +end