Authored by Anthony Boyer

Re-work of spikedetection so it can deal with inconsistent sampling frequencies.

... ... @@ -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,58 +88,134 @@ function ImaGIN_SpikesDetection(S)
end
end
%% Create the new monopolar baseline object
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{:}];
all_coordinates = cell2mat(channels.(global_montage{nn}).coordinates(:));
[lines cols] = find(~isnan(all_coordinates));
coordinates_with_values = all_coordinates(unique(lines),:);
if isempty(coordinates_with_values)
coordinates(nn,:) = NaN(1,3);
elseif sum(all(coordinates_with_values == coordinates_with_values(1,:))) == 3
coordinates(nn,:) = coordinates_with_values(1,:);
%% 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)
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),:);
if isempty(coordinates_with_values)
coordinates(nn,:) = NaN(1,3);
elseif sum(all(coordinates_with_values == coordinates_with_values(1,:))) == 3
coordinates(nn,:) = coordinates_with_values(1,:);
else
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 electrodes coordinates between cropped files.');
end
end
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);
D(:,:,1) = timeseries;
save(D);
save(D);
%% 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
... ...