Finding correct MinPeakDistance using for loop

1 次查看(过去 30 天)
I am trying to find the peaks when a signal (EFFEKT) exceeds a threshold (Abonnemang)
EFFEKT is an 8760x1 double, containing a value for every hour of the year.
Some peaks involves several values (see figure), thus I use this loop to make every peak only contain the biggest value (max_val). t0_pos1 is the starting point; when a peak crosses the threshold on the way up and t0_neg1 on the way down. The if-statement makes sure that the number of crossings is correlated with the number of peaks.
However the if statements is not activated for certain threshold values like in this example.
Any ideas on how I can overcome this?
load EFFEKT.mat
Abonnemang=21200;
dt = datetime(2021,1,1:1:365);
et = hours(0:23)';
t = repmat(dt,length(et),1) + repmat(et,1,length(dt));
t=t(:);
for x=1:numel(EFFEKT)-2 %REMOVE NEIGHBOURING PEAKS
[max_val,locs] = findpeaks(EFFEKT,'MinPeakHeight',Abonnemang,'MinPeakDistance',x); % find the peak and its x axis location
[t0_pos1,s0_pos1,t0_neg1,s0_neg1]= crossing_V7(EFFEKT,t,Abonnemang,'linear'); % positive (pos) and negative (neg) slope crossing points
peak_width = t0_neg1- t0_pos1;
if length(max_val)==length(t0_pos1)
break
end
end

回答(1 个)

chicken vector
chicken vector 2023-4-24
编辑:chicken vector 2023-4-24
Your idea of increasing 'MinPeakDistance' to adjust the peaks found is not consistent.
For example, if you iterate manually, you can see that when length(max_val) is approaching length(t0_pos1), you are already starting to lose some valuable information as shown below in green.
There was a related question yesterday. You can use the method explained there, which is originally from this question to divide peaks in group.
clear;clc;
load EFFEKT.mat
Abonnemang = 21200;
t = datetime(2021,1,1,1:length(EFFEKT),0,0)';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Credits @KSSV:
ad = EFFEKT' > Abonnemang;
ad0 = zeros(size(ad)) ;
ad0(logical(ad)) = find(ad) ;
ii = zeros(size(ad0));
jj = ad0 > 0;
ii(strfind([0,jj(:)'],[0 1])) = 1;
idx = cumsum(ii).*jj;
out = accumarray( idx(jj)',ad0(jj)',[],@(x){x'});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
nPeaks = length(out);
peaks = zeros(1,nPeaks);
peakTime = NaT(1,nPeaks);
firstCrossing = NaT(1,nPeaks);
lastCrossing = NaT(1,nPeaks);
for j = 1 : nPeaks
[maxValue, maxIdx] = max(EFFEKT(out{j}));
peaks(j) = maxValue;
peakTime(j) = t(out{j}(maxIdx));
firstCrossing(j) = t(out{j}(1));
lastCrossing(j) = t(out{j}(end));
end
figure;
tiledlayout(1,2);
nexttile
hold on;
plot(t,EFFEKT);
yline(Abonnemang);
scatter(peakTime,peaks,'r')
title('Peaks')
set(gca,'FontSize',24)
peakIdx = 34;
plotIdx = out{peakIdx}(1)-2:out{peakIdx}(end)+2;
nexttile
hold on;
plot(t(plotIdx),EFFEKT(plotIdx));
yline(Abonnemang);
scatter(peakTime(peakIdx),peaks(peakIdx),'r')
xline(firstCrossing(peakIdx),'k')
xline(lastCrossing(peakIdx),'k')
title('Crossing')
set(gca,'FontSize',24)
Result:
On a sidenote, I suggest you to pay attention on what really depends on the looping variable, in your case x.
For example you are performing the 8760 times the command:
[t0_pos1,s0_pos1,t0_neg1,s0_neg1]= crossing_V7(EFFEKT,t,Abonnemang,'linear'); % positive (pos) and negative (neg) slope crossing points
peak_width = t0_neg1- t0_pos1;
But this does not depend on x, therefore it may be performed only once prior to the loop, largely increasing the speed of your code.

产品


版本

R2023a

Community Treasure Hunt

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

Start Hunting!

Translated by