schedule

It is required to programmatically find the number and location of positive peaks on the graph.
It is known that the number of peaks is odd. Usually 3, 5 or 7. In this case 3. It is also known that every positive peak is followed by a negative one.
How best to solve this problem in Python? Preferably without matching factors
Addition : Data always begins with a positive peak and ends with a negative one.
The data is a vertical projection of the image processed by the np.gradient(projection)/projection function. That is, the ratio of the second derivative of the function to its height.

  • Need to search in the data set or on the image? - Konstantin Les
  • Do I understand correctly that this is a signal received from somewhere (and not a function)? Can this signal start with a negative peak or always only with a positive one? Need an algorithm or features of its implementation in Python? - Konstantin Les
  • Search in a discrete data set. I would like to solve this problem based on functions from scipy or any other large and debugged library. Completed the question - Oceinic

2 answers 2

Since just the local extremum does not suit you, you need to add a check for exceeding the threshold for rejecting small peaks and artifacts. The threshold can be calculated as the MSE of the sample multiplied by some constant corresponding to the confidence interval for the expectation.
In practice, this constant is taken equal to 2.5 .

UPD
Taking into account the additional conditions of the problem, the peak should be considered a maximum in the segment from the “top” (starting point or first value above q ) to “bottom” (first value below -q ).
Moreover, for an array of dimension n following algorithm is possible:

  1. Find the MSE of the sample and calculate the threshold q .
  2. Put top=0 .
  3. Find the bottom coordinate of the first point of the segment [top, n-1] with a value less than -q . If there is no such point, go to step 7.
  4. Find the coordinate of the maximum on the segment [top, bottom-1] . If the maximum value is greater than q , write it to the peak array.
  5. Find the top coordinate of the first point of the segment [bottom+1, n-1] with a value greater than q . If there is no such point, go to step 7.
  6. Go to p.3.
  7. Use peak array.
  • And how to take into account the alternation of peaks? - Oceinic
  • @Oceinic Clarified - Yuri Negometyanov February

Nothing better than searching for peaks in an array does not occur. Strictly alternating positive and negative peaks eases the task.

Those. algorithm like this.
Select the values ​​of two thresholds: positive and negative. We are looking for a maximum while the signal is greater than the negative threshold. The maximum found is the peak, and the index in the array is its position. We look forward to exceeding the positive threshold and are looking for another positive peak. Thresholds are selected to be above noise: fluctuations around zero. Their values ​​can be clear based on the nature of the signal (the minimum possible value of the peak), or you can try to calculate them statistically (find the standard deviation of noise and set the threshold to a value, for example, 3 standard deviation).
I am afraid that the finished function in the libraries will not be. However, the implementation of such an algorithm is trivial. Unfortunately, I don’t know much about Python, so I’ll give a possible implementation in C ++ (I think that problems with understanding should not arise):

 typedef double sample_type; struct Peak { sample_type magnitude; std::size_t pos; }; std::vector<Peak> peaks(const std::vector<sample_type> &sig) { static sample_type threshold_lo = -0.05; static sample_type threshold_hi = 0.05; std::vector<Peak> ret_peaks; std::vector<sample_type>::size_type isample = 0; while (1) { while ((isample < sig.size()) && (sig[isample] < threshold_hi)) { ++isample; } if (isample >= sig.size()) break; ret_peaks.push_back(Peak(sig[isample], isample)); while ((isample < sig.size()) && (sig[isample] > threshold_lo)) { if (sig[isample] > ret_peaks.back().magnitude) { ret_peaks.back().magnitude = sig[isample]; ret_peaks.back().pos = isample; } ++isample; } if (isample >= sig.size()) break; } return ret_peaks; } 

You can also use the correlation (to calculate it must be a finished function in scipy). But, in my opinion, in this case it is a more complicated approach. You can also read about correlation here.