Bug in islocalmin/islocalmax?

I have some data that has some numerical round off errors that I need to find local minimums and local maximums within a tolerance, but it doesn't work the way I think I should. Here is a reproducable example.
y = [1 0 1e-10 0 2]; % ideally this should be [1 0 0 0 2];
tolerance = 1e-5;
% islocalmax works, it gives an empty array
find(islocalmax(y,'FlatSelection','center','MinProminence',1e-5))
% however islocalmin does not work, it gives two minimums at 2 and 4 rather
% than expected 3 according to my tolerance
find(islocalmin(y,'FlatSelection','center','MinProminence',1e-5))
The same odd behaviour occurs for the following
y2 = [1 0 1e-10 1e-10 0 2];
find(islocalmin(y2,'FlatSelection','center','MinProminence',1e-5))
% yields 2 and 5, instead of expected 3
y3 = [1 0 1e-10 -1e-10 0 2];
find(islocalmin(y3,'FlatSelection','center','MinProminence',1e-5))
% yields 4, instead of expected 3
Is there a workaround? Is there a way I could "flatten" the values according to tolerance? Note, I only used 0 to 1e-10 to ilustrate this, I would like this to work for any values with smaller variations than 1e-5.
Thank you all,

 Accepted Answer

Robert
Robert on 18 Jun 2022
I may have figured it out, thanks to comments here, it got me thinking towards filtering. Turns out simple truncation is the key. In my case, y = round(y,4) works for prominance of 1e-5. This essentially flattens the data perturbations.

More Answers (3)

Image Analyst
Image Analyst on 18 Jun 2022
Edited: Image Analyst on 18 Jun 2022
I think you should be using findpeaks. It has the ability to filter the peaks to get just the ones you want - the peaks with the particular properties you desire.
Star Strider
Star Strider on 18 Jun 2022
Those functions (and findpeaks) do not use anything that could be considered to be a ‘tolerance’. The ‘prominence’ of a peak (or valley, depending on the function) relates the peak to the values that surround it.
To use a ‘tolerance’ value (that I assume means a range of peak height values), the only option that I can think of would require two different calls to the functions with different criteria, getting the logical vectors (or using find to get the numeric indices), and then using logical (logical vectors) or set (numeric indices) functions on the results to get the differences between the outputs of the two calls.

4 Comments

Robert
Robert on 18 Jun 2022
Edited: Robert on 18 Jun 2022
Thanks, I assumed that prominence would consider both sides of the valley, not just one side as is illustrated by my example. I did find a workaround but it requires quite a bit of calls to the islocalmax/min functions and ismember functions. I was hoping to find a more elegant solution that would "flatten" my values.
[1 0 1e-10 -1e-10 1e-10 0 2] => [1 0 0 0 0 0 2]
I am not certain what result you want.
You could consider the low-amplitude values to be noise, and some sort of filtering or smoothing might work (for example smoothdata), however the example vectors are too short to do any sort of processing with, so I cannot demonstrate those results with them.
.
Smoothing data does work, but I wanted to stay away from that as it also can produce perturbations and requires tunning the window size for example.
O.K.
That’s the best option I can think of. I didn’t consider the round function, since I’m still not certain what the actual problem is.

Sign in to comment.

Perhaps you just want to set values less than the tolerance to the min?
y(y<tolerance) = min(y);
Or perhaps you want to do some denoising with something like a median filter or Savitzky-Golay filter sgolayfilt

1 Comment

The issue is that there is perturbations to data, not just a min value.

Sign in to comment.

Products

Release

R2021b

Asked:

on 18 Jun 2022

Commented:

on 18 Jun 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!