What can I do to further vectorise this code?
2 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Some context first:
I have several sets of experimental data that look like this:
I'll be restricting my discussion to just one set of data. My objective is to extract the peaks (maximum and minimum) of each "cycle." findpeaks didn't help with that since the data doesn't always ascend/descend monotonously over a quarter-cycle, especially near the peaks:
However, that's not the case near the x-axis (time) intersects, so I used the sign change in the strain (y-axis) that happens there to collect the strain values of each "cycle" and calculate, iteratively, the maximum and minimum of each set. This is the code I wrote after some optimisation (in the form of a function):
function Umkehrpunkte = ump(x)
% Prepare data for processing (Calculate Stress and Strain; Area always constant)%
Area = 24.5;
x(:,3) = x(:,3)*100;
x(:,2) = x(:,2)/Area;
%Initialise index(es) for loops and create a zeros-matrix with a reasonable number of rows for storage of maxima and minima%
z = 1;
Umkehrpunkte = zeros(100,2);
i_umk = 1;
length_x = length(x); %Slightly faster. Compare in profiler.
while z < length_x %z corresponds to row number
t = z; %Setting lower row index to the first element being processed; marks the starting point of a cycle
while z < length_x && sign(x(z,2)) == 1 %Using change of sign at x-axis as criterion for terminating incrementation of z
z = z+1; %Increment until last positive value (positive half-cycle) has been reached.
end
%Termination checkpoint: Store the maxima of the last data set and terminate the outer while-loop.
%(LAST DATA SET IS ALWAYS A POSITIVE HALF CYCLE!)
if z == length_x;
Umkehrpunkte(i_umk, [1 2]) = [max(x(t:z,2)) max(x(t:z,3))]; %Locate and assign last maximum; run only once before termination.
i_umk = i_umk +1;
break;
end
while sign(x(z,2)) == -1; %Negative half-cycle, see comment at first inner while-loop for details
z = z+1;
end
end
%Extract the maximum and the minimum of the current FULL cycle.
Umkehrpunkte([i_umk i_umk+1], [1 2]) = [max(x(t:z,2)) max(x(t:z,3)); min(x(t:z,2)) min(x(t:z,3))]; i_umk = i_umk +2; %
end
%Trimming off the zeros
Umkehrpunkte = Umkehrpunkte(1:i_umk-1, [1 2]);
My first thought was to vectorise the collection of positive and negative half-cycles using the critera I set here for the inner while-loops (signum function) as boolean conditions, but that would collect all positive or all negative data points without showing which half-cycle they belong to. Any approach I came up with to separate the data involved loops, just different ones. So my first question along this line of thought is: is there any way I can achieve what I want with something like the following?
Umkehrpunkte = max(all positive values of x(all rows, specific column(s)))
%And then the same here for all negative values of x to calculate the minima.
What, if anything, can be added to this besides loops that would make it collect the data until it finds a positive/negative value, the way it does in the code above, and then stop and process it?
Feel free to suggest more broad overhauls or entirely different approaches. Thanks in advance.
Edit: More context: The "x" that's passed to the function is a 24000+ by 3 matrix. The first column contains the time, second and third columns the stress and strain, respectively.
Edit 2: Made the comments a bit clearer.
4 commentaires
Stephen23
le 31 Jan 2020
Modifié(e) : Stephen23
le 31 Jan 2020
"findpeaks didn't help with that since the data doesn't always ascend/descend monotonously over a quarter-cycle..."
I don't see any reason why it shouldn't, once you set the following options to something suitable for your data:
- MinPeakHeight
- MinPeakProminence
- Threshold
- MinPeakDistance
- You might also find the peak width options useful.
Please do both of these:
- show us exactly how you called findpeaks,
- upload some sample data by clicking the paperclip button.
Réponse acceptée
Mohammad Sami
le 31 Jan 2020
Have you tried the function islocalmax and islocalmin ?
maxIndices = islocalmax(x(:,2));
minIndices = islocalmin(x(:,2));
7 commentaires
Mohammad Sami
le 1 Fév 2020
Another option
load Block_18.mat
sign_18 = sign(Block_18(:,2));
half_cycle_id = sign_18 ~= circshift(sign_18,1); % detect sign change
half_cycle_id = cumsum(half_cycle_id); % assign id to each half cycle
if half_cycle_id(1) == 0
half_cycle_id = half_cycle_id + 1;
end
min_18 = accumarray(half_cycle_id,Block_18(:,2),[],@min,NaN);
max_18 = accumarray(half_cycle_id,Block_18(:,2),[],@max,NaN);
summ = table(unique(half_cycle_id),min_18,max_18);
summ.isnegative_cyc = sign(summ.min_18) == -1;
summ.val(summ.isnegative_cyc) = summ.min_18(summ.isnegative_cyc);
summ.val(~summ.isnegative_cyc) = summ.max_18(~summ.isnegative_cyc);
Plus de réponses (0)
Voir également
Produits
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!