peak_finder.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include "peak_finder.h"
  2. #include <iostream>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <cmath>
  6. namespace graft_cv {
  7. void diff(std::vector<float> in, std::vector<float>& out)
  8. {
  9. out = std::vector<float>(in.size() - 1);
  10. for (int i = 1; i<in.size(); ++i)
  11. out[i - 1] = in[i] - in[i - 1];
  12. }
  13. void vectorElementsProduct(std::vector<float> a, std::vector<float> b, std::vector<float>& out)
  14. {
  15. out = std::vector<float>(a.size());
  16. for (int i = 0; i<a.size(); ++i)
  17. out[i] = a[i] * b[i];
  18. }
  19. void findIndicesLessThan(std::vector<float> in, float threshold, std::vector<int>& indices)
  20. {
  21. for (int i = 0; i<in.size(); ++i)
  22. if (in[i]<threshold)
  23. indices.push_back(i + 1);
  24. }
  25. void selectElementsFromIndices(std::vector<float> in, std::vector<int> indices, std::vector<float>& out)
  26. {
  27. for (int i = 0; i<indices.size(); ++i)
  28. out.push_back(in[indices[i]]);
  29. }
  30. void selectElementsFromIndices(std::vector<int> in, std::vector<int> indices, std::vector<int>& out)
  31. {
  32. for (int i = 0; i<indices.size(); ++i)
  33. out.push_back(in[indices[i]]);
  34. }
  35. void signVector(std::vector<float> in, std::vector<int>& out)
  36. {
  37. out = std::vector<int>(in.size());
  38. for (int i = 0; i<in.size(); ++i)
  39. {
  40. if (in[i]>0)
  41. out[i] = 1;
  42. else if (in[i]<0)
  43. out[i] = -1;
  44. else
  45. out[i] = 0;
  46. }
  47. }
  48. void scalarProduct(float scalar, std::vector<float> in, std::vector<float>& out)
  49. {
  50. out = std::vector<float>(in.size());
  51. for (int i = 0; i<in.size(); ++i)
  52. out[i] = scalar * in[i];
  53. }
  54. void findPeaks(std::vector<float> x0, std::vector<int>& peakInds, bool includeEndpoints, float extrema)
  55. {
  56. int minIdx = distance(x0.begin(), min_element(x0.begin(), x0.end()));
  57. int maxIdx = distance(x0.begin(), max_element(x0.begin(), x0.end()));
  58. float sel = (x0[maxIdx] - x0[minIdx]) / 4.0;
  59. int len0 = x0.size();
  60. scalarProduct(extrema, x0, x0);
  61. std::vector<float> dx;
  62. diff(x0, dx);
  63. replace(dx.begin(), dx.end(), 0.0f, - EPS);
  64. std::vector<float> dx0(dx.begin(), dx.end() - 1);
  65. std::vector<float> dx0_1(dx.begin() + 1, dx.end());
  66. std::vector<float> dx0_2;
  67. vectorElementsProduct(dx0, dx0_1, dx0_2);
  68. std::vector<int> ind;
  69. findIndicesLessThan(dx0_2, 0, ind); // Find where the derivative changes sign
  70. std::vector<float> x;
  71. float leftMin;
  72. int minMagIdx;
  73. float minMag;
  74. if (includeEndpoints)
  75. {
  76. //x = [x0(1);x0(ind);x0(end)];
  77. selectElementsFromIndices(x0, ind, x);
  78. x.insert(x.begin(), x0[0]);
  79. x.insert(x.end(), x0[x0.size() - 1]);
  80. //ind = [1;ind;len0];
  81. ind.insert(ind.begin(), 1);
  82. ind.insert(ind.end(), len0);
  83. minMagIdx = distance(x.begin(), std::min_element(x.begin(), x.end()));
  84. minMag = x[minMagIdx];
  85. //std::cout<<"Hola"<<std::endl;
  86. leftMin = minMag;
  87. }
  88. else
  89. {
  90. selectElementsFromIndices(x0, ind, x);
  91. if (x.size()>2)
  92. {
  93. minMagIdx = distance(x.begin(), std::min_element(x.begin(), x.end()));
  94. minMag = x[minMagIdx];
  95. leftMin = x[0]<x0[0] ? x[0] : x0[0];
  96. }
  97. }
  98. int len = x.size();
  99. if (len>2)
  100. {
  101. float tempMag = minMag;
  102. bool foundPeak = false;
  103. int ii;
  104. if (includeEndpoints)
  105. {
  106. // Deal with first point a little differently since tacked it on
  107. // Calculate the sign of the derivative since we tacked the first
  108. // point on it does not neccessarily alternate like the rest.
  109. std::vector<float> xSub0(x.begin(), x.begin() + 3);//tener cuidado subvector
  110. std::vector<float> xDiff;//tener cuidado subvector
  111. diff(xSub0, xDiff);
  112. std::vector<int> signDx;
  113. signVector(xDiff, signDx);
  114. if (signDx[0] <= 0) // The first point is larger or equal to the second
  115. {
  116. if (signDx[0] == signDx[1]) // Want alternating signs
  117. {
  118. x.erase(x.begin() + 1);
  119. ind.erase(ind.begin() + 1);
  120. len = len - 1;
  121. }
  122. }
  123. else // First point is smaller than the second
  124. {
  125. if (signDx[0] == signDx[1]) // Want alternating signs
  126. {
  127. x.erase(x.begin());
  128. ind.erase(ind.begin());
  129. len = len - 1;
  130. }
  131. }
  132. }
  133. //Skip the first point if it is smaller so we always start on maxima
  134. if (x[0] >= x[1])
  135. ii = 0;
  136. else
  137. ii = 1;
  138. //Preallocate max number of maxima
  139. float maxPeaks = ceil((float)len / 2.0);
  140. std::vector<int> peakLoc(maxPeaks, 0);
  141. std::vector<float> peakMag(maxPeaks, 0.0);
  142. int cInd = 1;
  143. int tempLoc;
  144. while (ii < len)
  145. {
  146. ii = ii + 1;//This is a peak
  147. //Reset peak finding if we had a peak and the next peak is bigger
  148. //than the last or the left min was small enough to reset.
  149. if (foundPeak)
  150. {
  151. tempMag = minMag;
  152. foundPeak = false;
  153. }
  154. //Found new peak that was lager than temp mag and selectivity larger
  155. //than the minimum to its left.
  156. if (x[ii - 1] > tempMag && x[ii - 1] > leftMin + sel)
  157. {
  158. tempLoc = ii - 1;
  159. tempMag = x[ii - 1];
  160. }
  161. //Make sure we don't iterate past the length of our vector
  162. if (ii == len)
  163. break; //We assign the last point differently out of the loop
  164. ii = ii + 1; // Move onto the valley
  165. //Come down at least sel from peak
  166. if (!foundPeak && tempMag > sel + x[ii - 1])
  167. {
  168. foundPeak = true; //We have found a peak
  169. leftMin = x[ii - 1];
  170. peakLoc[cInd - 1] = tempLoc; // Add peak to index
  171. peakMag[cInd - 1] = tempMag;
  172. cInd = cInd + 1;
  173. }
  174. else if (x[ii - 1] < leftMin) // New left minima
  175. leftMin = x[ii - 1];
  176. }
  177. // Check end point
  178. if (includeEndpoints)
  179. {
  180. if (x[x.size() - 1] > tempMag && x[x.size() - 1] > leftMin + sel)
  181. {
  182. peakLoc[cInd - 1] = len - 1;
  183. peakMag[cInd - 1] = x[x.size() - 1];
  184. cInd = cInd + 1;
  185. }
  186. else if (!foundPeak && tempMag > minMag)// Check if we still need to add the last point
  187. {
  188. peakLoc[cInd - 1] = tempLoc;
  189. peakMag[cInd - 1] = tempMag;
  190. cInd = cInd + 1;
  191. }
  192. }
  193. else if (!foundPeak)
  194. {
  195. float minAux = x0[x0.size() - 1]<x[x.size() - 1] ? x0[x0.size() - 1] : x[x.size() - 1];
  196. if (x[x.size() - 1] > tempMag && x[x.size() - 1] > leftMin + sel)
  197. {
  198. peakLoc[cInd - 1] = len - 1;
  199. peakMag[cInd - 1] = x[x.size() - 1];
  200. cInd = cInd + 1;
  201. }
  202. else if (!tempMag > minAux + sel)// Check if we still need to add the last point
  203. {
  204. peakLoc[cInd - 1] = tempLoc;
  205. peakMag[cInd - 1] = tempMag;
  206. cInd = cInd + 1;
  207. }
  208. }
  209. //Create output
  210. if (cInd > 0)
  211. {
  212. std::vector<int> peakLocTmp(peakLoc.begin(), peakLoc.begin() + cInd - 1);
  213. selectElementsFromIndices(ind, peakLocTmp, peakInds);
  214. }
  215. }
  216. //else
  217. //{
  218. //input signal length <= 2
  219. //}
  220. }
  221. }