How to identify first local minima before the main peak?

12 views (last 30 days)
Tomaszzz
Tomaszzz on 30 Jan 2022
Commented: Tomaszzz on 31 Jan 2022
Hi all,
I am having a trouble with identifing first local minima (red stars in the image below) before the main peak (blue star) in a consistent manner
My code seems to identify the second local minima before the main peak, rather than the first. This should be in the locations what I circled manually in yellow in the figure below. (signal attached).
Also this should account for the fact that the first main peak may be too far left and there are no local minimas before it,
and similary the last main peak may be too far right and there are no local minimas after it (which the code already does pretty well).
Can you help please?
load'signal'
% indentify all peaks
[all_peak_value,all_peak_location]= findpeaks(thigh_orient_y);
% identify all troughs in data
[all_trough_value,all_trough_location]= findpeaks(-thigh_orient_y);
all_trough_value = -all_trough_value;
% identify main peak (i.e. ones lower than 50)
[main_trough_value,main_trough_location]= findpeaks(thigh_orient_y,'MinPeakProminence',30);
%% Identify first local minima before main through (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = all_peak_location == main_trough_location(i);
if find(index)>1 % this will ignore if a main trough is too far left and there are not two smaller troughs
counter = counter + 1;
start_location(counter) = all_trough_location(find(index)-1); % find start location
start_value(counter) = all_trough_value(find(index)-1); % find start value
end
end
%% Identify first local minima after main trough (main peak)
counter = 0
for i = 1:length(main_trough_location)
index = all_trough_location > main_trough_location(i);
if sum(index)>0 % this will ignore if the main trough is too far right so there are no peaks afterwards
counter = counter + 1;
end_location(counter) = all_trough_location(find(index,1));
end_value(counter) = all_trough_value(find(index,1));
end
end
%% Plot
figure
plot(thigh_orient_y,'k')
hold on
plot(all_trough_location,all_trough_value,'ko')
plot(main_trough_location,main_trough_value,'b*')
plot(start_location,start_value,'r*')
plot(end_location,end_value,'g*')
h = legend('signal',' all troughs','main peak','start', 'end');
set(h,'location','northeast','box','off')
box off

Accepted Answer

Voss
Voss on 30 Jan 2022
I think the problem is that there is an implicit assumption in your code about whether the i-th peak comes before the i-th trough or the i-th trough comes before the i-th peak. That is to say, it is necessary to know whether all_peak_location(i) is the location of the peak right before or right after all_trough_location(i), but this depends on which comes first in the data, the first peak or the first trough.
To illustrate this point, first I'll run the code as posted to get the plot for reference:
load('signal.mat')
% indentify all peaks
[all_peak_value,all_peak_location]= findpeaks(thigh_orient_y);
% identify all troughs in data
[all_trough_value,all_trough_location]= findpeaks(-thigh_orient_y);
all_trough_value = -all_trough_value;
% identify main peak (i.e. ones lower than 50)
[main_trough_value,main_trough_location]= findpeaks(thigh_orient_y,'MinPeakProminence',30);
%% Identify first local minima before main through (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = all_peak_location == main_trough_location(i);
if find(index)>1 % this will ignore if a main trough is too far left and there are not two smaller troughs
counter = counter + 1;
start_location(counter) = all_trough_location(find(index)-1); % find start location
start_value(counter) = all_trough_value(find(index)-1); % find start value
end
end
%% Identify first local minima after main trough (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = all_trough_location > main_trough_location(i);
if sum(index)>0 % this will ignore if the main trough is too far right so there are no peaks afterwards
counter = counter + 1;
end_location(counter) = all_trough_location(find(index,1));
end_value(counter) = all_trough_value(find(index,1));
end
end
%% Plot
figure
plot(thigh_orient_y,'k')
hold on
plot(all_trough_location,all_trough_value,'ko')
plot(main_trough_location,main_trough_value,'b*')
plot(start_location,start_value,'r*')
plot(end_location,end_value,'g*')
h = legend('signal',' all troughs','main peak','start', 'end');
set(h,'location','northeast','box','off')
box off
Now look what happens when I remove the first 10 samples of data, so that the first trough is removed, but the first peak remains:
load('signal.mat')
% remove first trough:
thigh_orient_y(1:10) = [];
% indentify all peaks
[all_peak_value,all_peak_location]= findpeaks(thigh_orient_y);
% identify all troughs in data
[all_trough_value,all_trough_location]= findpeaks(-thigh_orient_y);
all_trough_value = -all_trough_value;
% identify main peak (i.e. ones lower than 50)
[main_trough_value,main_trough_location]= findpeaks(thigh_orient_y,'MinPeakProminence',30);
%% Identify first local minima before main through (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = all_peak_location == main_trough_location(i);
if find(index)>1 % this will ignore if a main trough is too far left and there are not two smaller troughs
counter = counter + 1;
start_location(counter) = all_trough_location(find(index)-1); % find start location
start_value(counter) = all_trough_value(find(index)-1); % find start value
end
end
%% Identify first local minima after main trough (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = all_trough_location > main_trough_location(i);
if sum(index)>0 % this will ignore if the main trough is too far right so there are no peaks afterwards
counter = counter + 1;
end_location(counter) = all_trough_location(find(index,1));
end_value(counter) = all_trough_value(find(index,1));
end
end
%% Plot
figure
plot(thigh_orient_y,'k')
hold on
plot(all_trough_location,all_trough_value,'ko')
plot(main_trough_location,main_trough_value,'b*')
plot(start_location,start_value,'r*')
plot(end_location,end_value,'g*')
h = legend('signal',' all troughs','main peak','start', 'end');
set(h,'location','northeast','box','off')
box off
Now the code is apparently picking the right troughs, right?
So the code assumes that the data has its first peak before its first trough. If it's the other way, the indexing is off by one. So that's the source of the problem.
Now, what's the solution? Well, you could check that the first peak is before the first trough, and if it's not, add an appropriate element at the beginning of all_peak_value and all_peak_location (and probably a flag that signifies that a pseudo-peak has been included, so don't plot it). That would probably work ok, but I prefer to re-think the method of finding the relevant troughs for each main peak to make it work in either situation. I think the thing to do is not rely on any relationship between all_peak_location(i) and all_trough_location(i) but make it work regardless of the order of peaks and troughs.
load('signal.mat')
% indentify all peaks
[all_peak_value,all_peak_location]= findpeaks(thigh_orient_y);
% identify all troughs in data
[all_trough_value,all_trough_location]= findpeaks(-thigh_orient_y);
all_trough_value = -all_trough_value;
% identify main peak (i.e. ones lower than 50)
[main_trough_value,main_trough_location]= findpeaks(thigh_orient_y,'MinPeakProminence',30);
%% Identify first local minima before main through (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = find(all_trough_location < main_trough_location(i),1,'last');
if isempty(index)
continue
end
counter = counter + 1;
start_location(counter) = all_trough_location(index); % find start location
start_value(counter) = all_trough_value(index); % find start value
end
%% Identify first local minima after main trough (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = find(all_trough_location > main_trough_location(i),1);
if isempty(index)
continue
end
counter = counter + 1;
end_location(counter) = all_trough_location(index);
end_value(counter) = all_trough_value(index);
end
%% Plot
figure
plot(thigh_orient_y,'k')
hold on
plot(all_trough_location,all_trough_value,'ko')
plot(main_trough_location,main_trough_value,'b*')
plot(start_location,start_value,'r*')
plot(end_location,end_value,'g*')
h = legend('signal',' all troughs','main peak','start', 'end');
set(h,'location','northeast','box','off')
box off
That looks good, right? And it still works if I remove the first trough:
load('signal.mat')
% remove first trough:
thigh_orient_y(1:10) = [];
% indentify all peaks
[all_peak_value,all_peak_location]= findpeaks(thigh_orient_y);
% identify all troughs in data
[all_trough_value,all_trough_location]= findpeaks(-thigh_orient_y);
all_trough_value = -all_trough_value;
% identify main peak (i.e. ones lower than 50)
[main_trough_value,main_trough_location]= findpeaks(thigh_orient_y,'MinPeakProminence',30);
%% Identify first local minima before main through (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = find(all_trough_location < main_trough_location(i),1,'last');
if isempty(index)
continue
end
counter = counter + 1;
start_location(counter) = all_trough_location(index); % find start location
start_value(counter) = all_trough_value(index); % find start value
end
%% Identify first local minima after main trough (main peak)
counter = 0;
for i = 1:length(main_trough_location)
index = find(all_trough_location > main_trough_location(i),1);
if isempty(index)
continue
end
counter = counter + 1;
end_location(counter) = all_trough_location(index);
end_value(counter) = all_trough_value(index);
end
%% Plot
figure
plot(thigh_orient_y,'k')
hold on
plot(all_trough_location,all_trough_value,'ko')
plot(main_trough_location,main_trough_value,'b*')
plot(start_location,start_value,'r*')
plot(end_location,end_value,'g*')
h = legend('signal',' all troughs','main peak','start', 'end');
set(h,'location','northeast','box','off')
box off

More Answers (0)

Community Treasure Hunt

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

Start Hunting!