findIntSpikes.m 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. function varargout = findIntSpikes(data, varargin)
  2. %% Find interneuron action potentials
  3. % This function is designed to find interneuron spikes and seperate them
  4. % from noise and other fast changes in the membrane potential. The function
  5. % is capable of finding most of the interneuon spikes with amplitudes down
  6. % to approximately 1 mV. If requested, a plot can be created showing all
  7. % spikes that were detected by the function for validation purposes.
  8. % -------------------------------------------------------------------------
  9. % Input [optional input arguments are name-value-pairs]
  10. % -----
  11. % data: data to be analysed, type: vector
  12. % PlotFlag: select if a plot should be created for each trial
  13. % (optional) showing the detected peaks. 0 (no plots, default),
  14. % 1 (plots)
  15. % ------
  16. % Output
  17. % ------
  18. % varargout{1}: peak values [mV]
  19. % varargout{2}: peak locations [datapoints]
  20. % -------------------------------------------------------------------------
  21. % Program by: Bjarne Schultze [last modified: 01.03.2022]
  22. % -------------------------------------------------------------------------
  23. %% Preparations
  24. % parse the user input
  25. p = inputParser;
  26. addRequired(p,'data', @(x) isvector(x))
  27. addParameter(p,'PlotFlag', [], @(x) isequal(x,1)||isequal(x,0))
  28. parse(p, data, varargin{:})
  29. dataIN = p.Results.data;
  30. plotflag = p.Results.PlotFlag;
  31. % load additional file
  32. load("../AdditionalFiles/standard_stimulus.mat", "standard_stimulus")
  33. %% Main calculations
  34. [peak_values, locations, ~, prom] = findpeaks(dataIN,...
  35. 'Annotate','extents', 'WidthReference','halfprom',...
  36. 'MinPeakProminence', 1,'MaxPeakWidth',200);
  37. % preassign a vector to gather the quater prominence width
  38. qprom_width = zeros(length(peak_values),1);
  39. % measure the peak width at one quarter of the prominence for each
  40. % spike (default would be half prom)
  41. for spike = 1:length(peak_values)
  42. % set the quarter prom as reference value for width measurement
  43. measure_level = peak_values(spike) - 0.25*prom(spike);
  44. % select a window of 100 datapoints around the current spike if
  45. % possible, otherwise a one-sided smaller window
  46. if locations(spike) < 51
  47. spikeData = dataIN(1:locations(spike)+50);
  48. spikeLoc = locations(spike);
  49. elseif locations(spike)+50 > locations(end)
  50. spikeData = dataIN(locations(spike)-50:end);
  51. spikeLoc = 51;
  52. else
  53. spikeData = dataIN(locations(spike)-50:locations(spike)+50);
  54. spikeLoc = 51;
  55. end
  56. % devide the points in left and right of the peak
  57. dataL = spikeData(1:spikeLoc);
  58. dataR = spikeData(spikeLoc+1:end);
  59. % take the points (left and right) that are closest to the
  60. % measure level of a quarter of the prominence
  61. [~,minL] = min((dataL - measure_level), [], ...
  62. 'ComparisonMethod','abs');
  63. [~,minR] = min((dataR - measure_level), [], ...
  64. 'ComparisonMethod','abs');
  65. % calculate the final width at quarter peak prominence
  66. qprom_width(spike) = minR + spikeLoc - minL;
  67. end
  68. % sort and select the all found peaks in a 3-step algorithm
  69. % 1st step: exclude every peak beneath the overall mean +1 mV
  70. select_peaks = peak_values > mean(dataIN)+1;
  71. peaks_subset1 = peak_values(select_peaks);
  72. % select the corresponding values/properties
  73. locs_subset1 = locations(select_peaks);
  74. qprom_width_subset1 = qprom_width(select_peaks);
  75. prom_subset1 = prom(select_peaks);
  76. % 2nd step: select only peaks with a quarter peak prom over 4 and
  77. % under 45
  78. select_peaks = 4 < qprom_width_subset1 & qprom_width_subset1 < 45;
  79. peaks_subset2 = peaks_subset1(select_peaks);
  80. % select the coorresponding values/properties
  81. locs_subset2 = locs_subset1(select_peaks);
  82. prom_subset2 = prom_subset1(select_peaks);
  83. % 3rd step: exclude the peaks smaller than 20% of the largest peak
  84. select_peaks = prom_subset2 > max(prom_subset2)*0.2;
  85. peaks_subset3 = peaks_subset2(select_peaks);
  86. % select the corresponding values/properties
  87. locs_subset3 = locs_subset2(select_peaks);
  88. % using findpeaks again, but without a maximum peak width to find all
  89. % spikes even those with incorrectly measured peak width
  90. [peaks,locs,~,prom] = findpeaks(dataIN,...
  91. 'Annotate','extents', 'WidthReference','halfprom',...
  92. 'MinPeakProminence', 1);
  93. % find onset locations of positive stimuli
  94. [~, stim_locs] = findpeaks(standard_stimulus);
  95. % seperate the one spike per stimulus that was ignored before
  96. for i = 1:length(stim_locs)
  97. sel_peaks = locs >= stim_locs(i) & locs <= stim_locs(i)+5000;
  98. [~,maxIndex] = max(prom(sel_peaks));
  99. if ~isempty(maxIndex)
  100. locs_subset = locs(sel_peaks); peaks_subset = peaks(sel_peaks);
  101. extra_locs(i,1) = locs_subset(maxIndex);
  102. extra_peaks(i,1) = peaks_subset(maxIndex);
  103. end
  104. end
  105. % collect all spikes and sort them according to their location
  106. [locs_final,sortOrder] = sort([locs_subset3;extra_locs]);
  107. peaks_final = [peaks_subset3;extra_peaks];
  108. peaks_final = peaks_final(sortOrder);
  109. % plot the peaks that are found plus their prominence and width
  110. if plotflag
  111. figure
  112. findpeaks(dataIN, 10000,...
  113. 'Annotate','extents', 'WidthReference','halfprom',...
  114. 'MinPeakProminence', 1,'MaxPeakWidth',200);
  115. locs_plot = locs_final / 10000;
  116. hold on; plot(locs_plot, peaks_final, 'og'); hold off;
  117. xlabel("time [s]"); ylabel("membrane potential [mV]");
  118. end
  119. % return peak and location values
  120. if isequal(nargout,1)
  121. varargout{1} = peaks_final;
  122. elseif isequal(nargout,2)
  123. varargout{1} = peaks_final;
  124. varargout{2} = locs_final;
  125. end
  126. % end of function definition
  127. end