Azzera filtri
Azzera filtri

Measure duration of peaks in graoh

1 visualizzazione (ultimi 30 giorni)
Joel
Joel il 5 Apr 2023
Commentato: Joel il 6 Apr 2023
Hi all
In the plot below I have one value for every hour of the year. You can click on them to show a label expressing when the peak occur and how big it is. A peak is defined as values above the red line (24200)
I want to know how long the peaks last, i.e. I want to estimate the time between the blue lines and know the highest value of that peak.
As you can see above, some peaks have several values.
So, instead of clicking on the values
I want to click on these peaks on the red line, then a label shows up printing out how long the peak last and how big the highest value of that peak is.

Risposta accettata

Mathieu NOE
Mathieu NOE il 5 Apr 2023
hello
maybe this ? use that demo on your data and let me know
the plot should look better on your PC compared to what is displayed below
% dummy data
n=1000;
x=(0:n-1)/n;
y = abs(sin(10*x+5*x.^2)).*(1+0.1*x);
threshold = 0.7*max(y);
[max_val,locs] = findpeaks(y,'MinPeakHeight',threshold); % find the peak and its x axis location
[t0_pos1,s0_pos1,t0_neg1,s0_neg1]= crossing_V7(y,x,threshold,'linear'); % positive (pos) and negative (neg) slope crossing points
% ind => time index (samples)
% t0 => corresponding time (x) values
% s0 => corresponding function (y) values , obviously they must be equal to "threshold"
figure(1)
plot(x,y,'b',x,threshold*ones(size(x)),'--r',x(locs),max_val,'dr',t0_pos1,s0_pos1,'db',t0_neg1,s0_neg1,'dg','linewidth',2,'markersize',12);grid on
legend('signal','threshold','signal peak value','signal positive slope crossing points','signal negative slope crossing points' );
ylim([0 1.8]);
% time difference between crossing points
peak_width = - t0_pos1 + t0_neg1;
% add text to the plot
for ck = 1:numel(peak_width)
x_text = t0_pos1(ck);
y_text = 1.25*max_val(ck);
text(x_text,y_text,['Peak Value : ' num2str(max_val(ck))] );
y_text = 1.15*max_val(ck);
text(x_text,y_text,['Peak Width : ' num2str(peak_width(ck))] );
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [t0_pos,s0_pos,t0_neg,s0_neg] = crossing_V7(S,t,level,imeth)
% [ind,t0,s0,t0close,s0close] = crossing_V6(S,t,level,imeth,slope_sign) % older format
% CROSSING find the crossings of a given level of a signal
% ind = CROSSING(S) returns an index vector ind, the signal
% S crosses zero at ind or at between ind and ind+1
% [ind,t0] = CROSSING(S,t) additionally returns a time
% vector t0 of the zero crossings of the signal S. The crossing
% times are linearly interpolated between the given times t
% [ind,t0] = CROSSING(S,t,level) returns the crossings of the
% given level instead of the zero crossings
% ind = CROSSING(S,[],level) as above but without time interpolation
% [ind,t0] = CROSSING(S,t,level,par) allows additional parameters
% par = {'none'|'linear'}.
% With interpolation turned off (par = 'none') this function always
% returns the value left of the zero (the data point thats nearest
% to the zero AND smaller than the zero crossing).
%
% check the number of input arguments
error(nargchk(1,4,nargin));
% check the time vector input for consistency
if nargin < 2 | isempty(t)
% if no time vector is given, use the index vector as time
t = 1:length(S);
elseif length(t) ~= length(S)
% if S and t are not of the same length, throw an error
error('t and S must be of identical length!');
end
% check the level input
if nargin < 3
% set standard value 0, if level is not given
level = 0;
end
% check interpolation method input
if nargin < 4
imeth = 'linear';
end
% make row vectors
t = t(:)';
S = S(:)';
% always search for zeros. So if we want the crossing of
% any other threshold value "level", we subtract it from
% the values and search for zeros.
S = S - level;
% first look for exact zeros
ind0 = find( S == 0 );
% then look for zero crossings between data points
S1 = S(1:end-1) .* S(2:end);
ind1 = find( S1 < 0 );
% bring exact zeros and "in-between" zeros together
ind = sort([ind0 ind1]);
% and pick the associated time values
t0 = t(ind);
s0 = S(ind);
if ~isempty(ind)
if strcmp(imeth,'linear')
% linear interpolation of crossing
for ii=1:length(t0)
%if abs(S(ind(ii))) >= eps(S(ind(ii))) % MATLAB V7 et +
if abs(S(ind(ii))) >= eps*abs(S(ind(ii))) % MATLAB V6 et - EPS * ABS(X)
% interpolate only when data point is not already zero
NUM = (t(ind(ii)+1) - t(ind(ii)));
DEN = (S(ind(ii)+1) - S(ind(ii)));
slope = NUM / DEN;
slope_sign(ii) = sign(slope);
t0(ii) = t0(ii) - S(ind(ii)) * slope;
s0(ii) = level;
end
end
end
% extract the positive slope crossing points
ind_pos = find(sign(slope_sign)>0);
t0_pos = t0(ind_pos);
s0_pos = s0(ind_pos);
% extract the negative slope crossing points
ind_neg = find(sign(slope_sign)<0);
t0_neg = t0(ind_neg);
s0_neg = s0(ind_neg);
else
% empty output
ind_pos = [];
t0_pos = [];
s0_pos = [];
% extract the negative slope crossing points
ind_neg = [];
t0_neg = [];
s0_neg = [];
end
end
  1 Commento
Joel
Joel il 6 Apr 2023
Hi
Thank you! Just what I needed!
I only have one issue now. The timetable shows every peak.
But some peaks have two peaking values (see picture)
so I got on 10x1 double with the peak values and a 9x1 duration with the duration
I only want the duration between the positive and negative crossing of the red line and the highest value between them. In the picture above the peaking values are 25309 and 25504.
I only want the highest value (25504) to show. So that the max_val an peak_width are the same size 1x9.

Accedi per commentare.

Più risposte (0)

Prodotti


Release

R2023a

Community Treasure Hunt

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

Start Hunting!

Translated by