3

I am writing code to find the local minima and maxima of the gradient of a signal similar to this stackoverflow question. I am using argrelextrema to do this. To test my my approach I implemented a quick test using the Cosine function.

# Get the data
x = np.arange(start=0,
              stop=20,
              step=0.2)
y = np.cos(x)

# Calculate the gradient
gradient = []
for y1, y2 in zip(y, y[1:]):
    # Append the gradient (Delta Y / Delta X) where Delta X = 1
    gradient.append(y2-y1)

# Turn the gradient from a list to an array
gradient = np.array(gradient)

# Calculate the maximum points of the gradient
maxima = argrelextrema(gradient, np.greater_equal, order=2)
minima = argrelextrema(gradient, np.less_equal, order=2)

# Plot the original signal
plt.plot(x, y, label="Original Signal")
plt.scatter(x[maxima], y[maxima], color="red", label="Maxima")
plt.scatter(x[minima], y[minima], color="blue", label="Minima")
plt.title("Original Graph")
plt.legend(loc='lower left')
plt.show()

# Plot the gradient
plt.plot(gradient, label="First Derivative")
plt.scatter(maxima, gradient[maxima], color="red", label="Maxima")
plt.scatter(minima, gradient[minima], color="blue", label="Minima")
plt.title("1st Derivative Graph")
plt.legend(loc='lower left')
plt.show()

This gives the following results:

Local Minima and Maxima of a Cos graph

All seems well. However when I change the code such that:

x = [my data of 720 points]
y = [my data of 720 points some are np.inf]

Link to the data (saved as a '.txt' file)

I get really strange results as seen below:

Weird Minima and Maxima

At first, I thought it could be due to the order=2 parameter of the argrelextrema function or noise in my signal. Changing the order to a larger window size reduces the number of points found, and so does including a digital filter. I, however, still can't understand why does it not find the maxima and minima at the peaks of the gradient rather than simply along the flat region?

Note: This question had the inverse of my problem.

Edit:

Changing the parameters less_equal to less and greater_equal to greater also removes many of the points along the flat region. Although I am still confused why the maxima and minima of the gradient are not selected.

Watchdog101
  • 700
  • 6
  • 19

1 Answers1

1

The problem has been fixed!

The first problem was that the data was noisy. That means that minima and maxima were being found all along the line. You can solve that in two ways. Firstly you can apply a filter to smooth the line:

from scipy import ndimage

# Filter the signal (to remove excess noise)
scanner_readings = ndimage.gaussian_filter(data, sigma=3)

Another option would be to increase the window size of the argrelextrema and argrelextrema functions.

# Calculate the maximum points of the gradient
maxima = argrelextrema(gradient, np.greater_equal, order=4)
minima = argrelextrema(gradient, np.less_equal, order=4)

Finally, it seems as if the functions argrelextrema and argrelextrema do not handle discontinuities well. To fix this, I replaced all inf values with the maximum value found which in this case was 10. You can see how I did this below:

# Remove discontinuity (10 is the max value in the data)
data[data == np.inf] = 10

When you do this, you get the following results:

Original Signal First derivative

Watchdog101
  • 700
  • 6
  • 19