123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- function varargout = findIntSpikes(data, varargin)
- %% Find interneuron action potentials
- % This function is designed to find interneuron spikes and seperate them
- % from noise and other fast changes in the membrane potential. The function
- % is capable of finding most of the interneuon spikes with amplitudes down
- % to approximately 1 mV. If requested, a plot can be created showing all
- % spikes that were detected by the function for validation purposes.
- % -------------------------------------------------------------------------
- % Input [optional input arguments are name-value-pairs]
- % -----
- % data: data to be analysed, type: vector
- % PlotFlag: select if a plot should be created for each trial
- % (optional) showing the detected peaks. 0 (no plots, default),
- % 1 (plots)
- % ------
- % Output
- % ------
- % varargout{1}: peak values [mV]
- % varargout{2}: peak locations [datapoints]
- % -------------------------------------------------------------------------
- % Program by: Bjarne Schultze [last modified: 01.03.2022]
- % -------------------------------------------------------------------------
- %% Preparations
- % parse the user input
- p = inputParser;
- addRequired(p,'data', @(x) isvector(x))
- addParameter(p,'PlotFlag', [], @(x) isequal(x,1)||isequal(x,0))
- parse(p, data, varargin{:})
- dataIN = p.Results.data;
- plotflag = p.Results.PlotFlag;
- % load additional file
- load("../AdditionalFiles/standard_stimulus.mat", "standard_stimulus")
- %% Main calculations
- [peak_values, locations, ~, prom] = findpeaks(dataIN,...
- 'Annotate','extents', 'WidthReference','halfprom',...
- 'MinPeakProminence', 1,'MaxPeakWidth',200);
- % preassign a vector to gather the quater prominence width
- qprom_width = zeros(length(peak_values),1);
- % measure the peak width at one quarter of the prominence for each
- % spike (default would be half prom)
- for spike = 1:length(peak_values)
- % set the quarter prom as reference value for width measurement
- measure_level = peak_values(spike) - 0.25*prom(spike);
- % select a window of 100 datapoints around the current spike if
- % possible, otherwise a one-sided smaller window
- if locations(spike) < 51
- spikeData = dataIN(1:locations(spike)+50);
- spikeLoc = locations(spike);
- elseif locations(spike)+50 > locations(end)
- spikeData = dataIN(locations(spike)-50:end);
- spikeLoc = 51;
- else
- spikeData = dataIN(locations(spike)-50:locations(spike)+50);
- spikeLoc = 51;
- end
- % devide the points in left and right of the peak
- dataL = spikeData(1:spikeLoc);
- dataR = spikeData(spikeLoc+1:end);
- % take the points (left and right) that are closest to the
- % measure level of a quarter of the prominence
- [~,minL] = min((dataL - measure_level), [], ...
- 'ComparisonMethod','abs');
- [~,minR] = min((dataR - measure_level), [], ...
- 'ComparisonMethod','abs');
- % calculate the final width at quarter peak prominence
- qprom_width(spike) = minR + spikeLoc - minL;
- end
- % sort and select the all found peaks in a 3-step algorithm
- % 1st step: exclude every peak beneath the overall mean +1 mV
- select_peaks = peak_values > mean(dataIN)+1;
- peaks_subset1 = peak_values(select_peaks);
- % select the corresponding values/properties
- locs_subset1 = locations(select_peaks);
- qprom_width_subset1 = qprom_width(select_peaks);
- prom_subset1 = prom(select_peaks);
- % 2nd step: select only peaks with a quarter peak prom over 4 and
- % under 45
- select_peaks = 4 < qprom_width_subset1 & qprom_width_subset1 < 45;
- peaks_subset2 = peaks_subset1(select_peaks);
- % select the coorresponding values/properties
- locs_subset2 = locs_subset1(select_peaks);
- prom_subset2 = prom_subset1(select_peaks);
- % 3rd step: exclude the peaks smaller than 20% of the largest peak
- select_peaks = prom_subset2 > max(prom_subset2)*0.2;
- peaks_subset3 = peaks_subset2(select_peaks);
- % select the corresponding values/properties
- locs_subset3 = locs_subset2(select_peaks);
- % using findpeaks again, but without a maximum peak width to find all
- % spikes even those with incorrectly measured peak width
- [peaks,locs,~,prom] = findpeaks(dataIN,...
- 'Annotate','extents', 'WidthReference','halfprom',...
- 'MinPeakProminence', 1);
- % find onset locations of positive stimuli
- [~, stim_locs] = findpeaks(standard_stimulus);
- % seperate the one spike per stimulus that was ignored before
- for i = 1:length(stim_locs)
- sel_peaks = locs >= stim_locs(i) & locs <= stim_locs(i)+5000;
- [~,maxIndex] = max(prom(sel_peaks));
- if ~isempty(maxIndex)
- locs_subset = locs(sel_peaks); peaks_subset = peaks(sel_peaks);
- extra_locs(i,1) = locs_subset(maxIndex);
- extra_peaks(i,1) = peaks_subset(maxIndex);
- end
- end
- % collect all spikes and sort them according to their location
- [locs_final,sortOrder] = sort([locs_subset3;extra_locs]);
- peaks_final = [peaks_subset3;extra_peaks];
- peaks_final = peaks_final(sortOrder);
- % plot the peaks that are found plus their prominence and width
- if plotflag
- figure
- findpeaks(dataIN, 10000,...
- 'Annotate','extents', 'WidthReference','halfprom',...
- 'MinPeakProminence', 1,'MaxPeakWidth',200);
- locs_plot = locs_final / 10000;
- hold on; plot(locs_plot, peaks_final, 'og'); hold off;
- xlabel("time [s]"); ylabel("membrane potential [mV]");
- end
- % return peak and location values
- if isequal(nargout,1)
- varargout{1} = peaks_final;
- elseif isequal(nargout,2)
- varargout{1} = peaks_final;
- varargout{2} = locs_final;
- end
- % end of function definition
- end
|