2 views (last 30 days)

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.

Mohammad Sami
on 31 Jan 2020

Have you tried the function islocalmax and islocalmin ?

maxIndices = islocalmax(x(:,2));

minIndices = islocalmin(x(:,2));

Mohammad Sami
on 1 Feb 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);

Sign in to comment.

Sign in to answer this question.

Opportunities for recent engineering grads.

Apply Today
## 4 Comments

## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_791930

⋮## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_791930

## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_791949

⋮## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_791949

## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_792020

⋮## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_792020

## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_792078

⋮## Direct link to this comment

https://au.mathworks.com/matlabcentral/answers/502864-what-can-i-do-to-further-vectorise-this-code#comment_792078

Sign in to comment.