...
|
...
|
@@ -2,8 +2,8 @@ function ImaGIN_SpikesDetection(S) |
|
|
% This function extracts and concatenates the baselines from cropped, qualitatively controlled, stimulation files.
|
|
|
% It runs Delphos' spike detection on extracted baselines after bipolar montage computation.
|
|
|
% It then computes corrected spike rates for each bipolar recording channel.
|
|
|
% /!\ Cropped files CAN have a variable number of channels and thus the monopolar <-> bipolar mapping has to be established for each cropped file
|
|
|
% and taken into account during baseline concatenation for consistency. /!\
|
|
|
% /!\ Cropped files CAN have a variable number of channels AND different sampling rates, the monopolar <-> bipolar mapping has to be established for each cropped file
|
|
|
% and taken into account during baseline concatenation for consistency AND cropped files with the same sampling rate have to be concatenated together. /!\
|
|
|
|
|
|
%% Vars parsing
|
|
|
stims_files = S.stims_files;
|
...
|
...
|
@@ -88,11 +88,16 @@ function ImaGIN_SpikesDetection(S) |
|
|
end
|
|
|
end
|
|
|
|
|
|
%% Create the new monopolar baseline object
|
|
|
%% Create monopolar baseline objects
|
|
|
unique_srates = unique(sampling);
|
|
|
|
|
|
for ss=1:numel(unique_srates)
|
|
|
clear srate labels timeseries zeroed coordinates;
|
|
|
srate = unique_srates(ss);
|
|
|
for nn=1:numel(global_montage)
|
|
|
channel{nn} = global_montage{nn};
|
|
|
timeseries(nn,:) = [channels.(global_montage{nn}).timeserie{:}];
|
|
|
zeroed(nn,:) = [channels.(global_montage{nn}).zeroed{:}];
|
|
|
labels{nn} = global_montage{nn};
|
|
|
timeseries(nn,:) = [channels.(global_montage{nn}).timeserie{find(sampling==srate)}];
|
|
|
zeroed(nn,:) = [channels.(global_montage{nn}).zeroed{find(sampling==srate)}];
|
|
|
all_coordinates = cell2mat(channels.(global_montage{nn}).coordinates(:));
|
|
|
[lines cols] = find(~isnan(all_coordinates));
|
|
|
coordinates_with_values = all_coordinates(unique(lines),:);
|
...
|
...
|
@@ -104,33 +109,104 @@ function ImaGIN_SpikesDetection(S) |
|
|
error('Inconsistent electrodes coordinates between cropped files.');
|
|
|
end
|
|
|
end
|
|
|
rates_tables{ss} = spikes_from_monopolar(srate,labels,timeseries,zeroed,coordinates,path_out);
|
|
|
end
|
|
|
|
|
|
rates_labels = {};
|
|
|
rates_scores = [];
|
|
|
for rr=1:numel(rates_tables)
|
|
|
rates_labels = [rates_labels rates_tables{rr}{:,1}];
|
|
|
current_rates = rates_tables{rr}{:,2};
|
|
|
current_rates(isinf(current_rates)) = NaN;
|
|
|
rates_scores = [rates_scores current_rates];
|
|
|
end
|
|
|
|
|
|
for ll=1:size(rates_labels,1)
|
|
|
if all(strcmp(rates_labels(ll,:),rates_labels{ll,1})==1)
|
|
|
bipolar_labels{ll} = rates_labels{ll,1};
|
|
|
else
|
|
|
error('Inconsistent labels between bipolar baselines');
|
|
|
end
|
|
|
end
|
|
|
mean_rates = mean(rates_scores,2,'omitnan');
|
|
|
|
|
|
% Store rate table in an individual files for easy extraction
|
|
|
rate_table_file = 'SPK_bBaseline_rates.mat';
|
|
|
spike_rates = [bipolar_labels',num2cell(mean_rates)];
|
|
|
save(fullfile(path_out,rate_table_file), 'spike_rates');
|
|
|
|
|
|
% Ending step
|
|
|
set_final_status('OK');
|
|
|
disp('Done');
|
|
|
|
|
|
end
|
|
|
|
|
|
function channels_map = monopolar_to_bipolar_mapping(monopolar_file,path_out)
|
|
|
mono_stimulation_obj = spm_eeg_load(monopolar_file);
|
|
|
monopolar_sensors = sensors(mono_stimulation_obj,'EEG');
|
|
|
[mono_path,mono_name,mono_ext] = fileparts(monopolar_file);
|
|
|
Sbp.Fname = monopolar_file;
|
|
|
Sbp.FileOut = fullfile(path_out,['b' mono_name]);
|
|
|
bp_stimulation_obj = ImaGIN_BipolarMontage(Sbp);
|
|
|
for cc=1:nchannels(bp_stimulation_obj)
|
|
|
bipolar_chan = chanlabels(bp_stimulation_obj,cc);
|
|
|
mono_chans = regexp(bipolar_chan,'-','split');
|
|
|
channels_map(cc).bp_chan = bipolar_chan;
|
|
|
channels_map(cc).bp_idx = cc;
|
|
|
channels_map(cc).mono_chan1 = mono_chans{1}{1};
|
|
|
channels_map(cc).mono_chan2 = mono_chans{1}{2};
|
|
|
% Get the monopolar channels idxes.
|
|
|
chan1_idx = find(strcmp(monopolar_sensors.label,mono_chans{1}{1}));
|
|
|
chan2_idx = find(strcmp(monopolar_sensors.label,mono_chans{1}{2}));
|
|
|
% Test and correct for duplicated labels in the monopolar object
|
|
|
if numel(chan1_idx) == 0
|
|
|
error('Could not find the monopolar channel from the bipolar montage.');
|
|
|
elseif numel(chan1_idx) == 1 % If 1 match, as expected, do nothing
|
|
|
%pass
|
|
|
else
|
|
|
error('2 or more channels with the same label')
|
|
|
end
|
|
|
% Same logic as for chan1_idx
|
|
|
if numel(chan2_idx) == 0
|
|
|
error('Could not find the monopolar channel from the bipolar montage.');
|
|
|
elseif numel(chan2_idx) == 1
|
|
|
%pass
|
|
|
else
|
|
|
error('2 or more channels with the same label')
|
|
|
end
|
|
|
channels_map(cc).mono_idx1 = chan1_idx;
|
|
|
channels_map(cc).mono_idx2 = chan2_idx;
|
|
|
end
|
|
|
delete([Sbp.FileOut '.mat']);delete([Sbp.FileOut '.dat']);delete([Sbp.FileOut '_log.txt']);
|
|
|
end
|
|
|
|
|
|
function rates_table = spikes_from_monopolar(srate,labels,timeseries,zeroed,coordinates,path_out)
|
|
|
|
|
|
% Create the new sensor
|
|
|
new_sensors_info.balance.current = 'none';
|
|
|
new_sensors_info.chanpos = coordinates;
|
|
|
new_sensors_info.chantype = cell(1,numel(global_montage)); new_sensors_info.chantype(:) = {'eeg'};
|
|
|
new_sensors_info.chanunit = cell(1,numel(global_montage)); new_sensors_info.chanunit(:) = {'V'};
|
|
|
new_sensors_info.chantype = cell(1,numel(labels)); new_sensors_info.chantype(:) = {'eeg'};
|
|
|
new_sensors_info.chanunit = cell(1,numel(labels)); new_sensors_info.chanunit(:) = {'V'};
|
|
|
new_sensors_info.elecpos = coordinates;
|
|
|
new_sensors_info.label = channel;
|
|
|
new_sensors_info.label = labels;
|
|
|
new_sensors_info.type = 'ctf';
|
|
|
new_sensors_info.unit = 'mm';
|
|
|
|
|
|
% Create the new files
|
|
|
file_header = fullfile(path_out,'monopolar_baseline.mat');
|
|
|
file_data = fullfile(path_out,'monopolar_baseline.dat');
|
|
|
file_header = fullfile(path_out,['monopolar_baseline_' num2str(srate) 'Hz.mat']);
|
|
|
file_data = fullfile(path_out,['monopolar_baseline_' num2str(srate) 'Hz.dat']);
|
|
|
if exist(file_header, 'file') == 2
|
|
|
delete(file_header);
|
|
|
end
|
|
|
if exist(file_data, 'file') == 2
|
|
|
delete(file_data);
|
|
|
end
|
|
|
|
|
|
% Create the new object
|
|
|
D = meeg(size(timeseries,1),size(timeseries,2),1);
|
|
|
D = fname(D,'monopolar_baseline');
|
|
|
D = fname(D,['monopolar_baseline_' num2str(srate) 'Hz']);
|
|
|
D = path(D,path_out);
|
|
|
if all(sampling == sampling(1))
|
|
|
D = fsample(D,sampling(1));
|
|
|
else
|
|
|
error('Inconsistent sampling frequency across cropped files.');
|
|
|
end
|
|
|
D = fsample(D,srate);
|
|
|
D = sensors(D,'EEG',new_sensors_info)
|
|
|
D = blank(D) ;
|
|
|
D = link(D,file_data);
|
...
|
...
|
@@ -139,7 +215,7 @@ function ImaGIN_SpikesDetection(S) |
|
|
|
|
|
%% Compute bipolar montage on baseline object to get the bipolar baseline object
|
|
|
Sbp.Fname = file_header;
|
|
|
Sbp.FileOut = fullfile(path_out,'bipolar_baseline');
|
|
|
Sbp.FileOut = fullfile(path_out,['bipolar_baseline_' num2str(srate) 'Hz']);
|
|
|
bp_baseline_obj = ImaGIN_BipolarMontage(Sbp);
|
|
|
global_mapping = monopolar_to_bipolar_mapping(Sbp.Fname,path_out);
|
|
|
|
...
|
...
|
@@ -179,53 +255,6 @@ function ImaGIN_SpikesDetection(S) |
|
|
spkFile.markers = spks_table;
|
|
|
spkFile.baseline = ['Total duration of ' num2str((nsamples(bp_baseline_obj)/fsample(bp_baseline_obj))/60) ' minutes'];
|
|
|
spkFile.comment = 'Spike rate is number of spikes per minute whithin a bipolar channel';
|
|
|
save(fullfile(path_out,spkFileName), 'spkFile');
|
|
|
|
|
|
% Store rate table in an individual files for easy extraction
|
|
|
rate_table_file = 'SPK_bBaseline_rates.mat';
|
|
|
spike_rates = [chans,num2cell(rates)];
|
|
|
save(fullfile(path_out,rate_table_file), 'spike_rates');
|
|
|
|
|
|
% Ending step
|
|
|
set_final_status('OK');
|
|
|
disp('Done');
|
|
|
end
|
|
|
|
|
|
function channels_map = monopolar_to_bipolar_mapping(monopolar_file,path_out)
|
|
|
mono_stimulation_obj = spm_eeg_load(monopolar_file);
|
|
|
monopolar_sensors = sensors(mono_stimulation_obj,'EEG');
|
|
|
[mono_path,mono_name,mono_ext] = fileparts(monopolar_file);
|
|
|
Sbp.Fname = monopolar_file;
|
|
|
Sbp.FileOut = fullfile(path_out,['b' mono_name]);
|
|
|
bp_stimulation_obj = ImaGIN_BipolarMontage(Sbp);
|
|
|
for cc=1:nchannels(bp_stimulation_obj)
|
|
|
bipolar_chan = chanlabels(bp_stimulation_obj,cc);
|
|
|
mono_chans = regexp(bipolar_chan,'-','split');
|
|
|
channels_map(cc).bp_chan = bipolar_chan;
|
|
|
channels_map(cc).bp_idx = cc;
|
|
|
channels_map(cc).mono_chan1 = mono_chans{1}{1};
|
|
|
channels_map(cc).mono_chan2 = mono_chans{1}{2};
|
|
|
% Get the monopolar channels idxes.
|
|
|
chan1_idx = find(strcmp(monopolar_sensors.label,mono_chans{1}{1}));
|
|
|
chan2_idx = find(strcmp(monopolar_sensors.label,mono_chans{1}{2}));
|
|
|
% Test and correct for duplicated labels in the monopolar object
|
|
|
if numel(chan1_idx) == 0
|
|
|
error('Could not find the monopolar channel from the bipolar montage.');
|
|
|
elseif numel(chan1_idx) == 1 % If 1 match, as expected, do nothing
|
|
|
%pass
|
|
|
else
|
|
|
error('2 or more channels with the same label')
|
|
|
end
|
|
|
% Same logic as for chan1_idx
|
|
|
if numel(chan2_idx) == 0
|
|
|
error('Could not find the monopolar channel from the bipolar montage.');
|
|
|
elseif numel(chan2_idx) == 1
|
|
|
%pass
|
|
|
else
|
|
|
error('2 or more channels with the same label')
|
|
|
end
|
|
|
channels_map(cc).mono_idx1 = chan1_idx;
|
|
|
channels_map(cc).mono_idx2 = chan2_idx;
|
|
|
end
|
|
|
delete([Sbp.FileOut '.mat']);delete([Sbp.FileOut '.dat']);delete([Sbp.FileOut '_log.txt']);
|
|
|
results_file = fullfile(path_out,spkFileName);
|
|
|
save(results_file, 'spkFile');
|
|
|
end |
...
|
...
|
|