Chrischpo
Chrischpo

Reputation: 145

How to find maximum value within multiple intervals?

I have two arrays, der_pos and der_neg, which contain indices of an array interpolated. I want to get all the indices for the maximum values of interpolated in the intervals:

der_pos(1):der_neg(1)
der_pos(2):der_neg(2)
etc...

E.g.:

interpolated = [1,5,3,2,7,10,8,14,4]
der_pos = [1,6]
der_neg = [4,9]

So, I would like to obtain the indices:

[2,8]

Because:

I managed to do it using a for loop:

interpolated = [1,5,3,2,7,10,8,14,4];

der_pos = [1,6];
der_neg = [4,9];

indices = zeros(1,length(der_pos));
for i = [1:length(der_pos)]
    [peak, index] = max(interpolated(der_pos(i):der_neg(i)));
    indices(i) = index + der_pos(i) - 1;
endfor

indices % gives [2,8]

But is there a more concise way of doing this?

Upvotes: 2

Views: 283

Answers (2)

Luis Mendo
Luis Mendo

Reputation: 112659

Here's a way:

interpolated = [1,5,3,2,7,10,8,14,4]; % data
der_pos = [1,6]; % data
der_neg = [4,9]; % data
m = bsxfun(@ge, 1:numel(interpolated), der_pos(:)) .* ...
    bsxfun(@le, 1:numel(interpolated), der_neg(:)); % each row is a mask that contains
    % 1 for values in the interval and 0 for values outside the interval
m(~m) = NaN; % replace 0 by NaN
[val, result] = max(bsxfun(@times, m, interpolated(:).'), [], 2); % val is the maximum 
    % of each row, and result is its column index. The maximum is 1 for rows that
    % contain at least a 1, and NaN for rows that only contain NaN
result(isnan(val)) = 0; % If the maximum value was NaN the result is set to 0
    % (or maybe use NaN), to indicate that the interval was empty

This gives 0 for empty intervals. For example, der_pos = [1,6,8]; der_neg = [4,9,6]; produce result = [2;8;0].

The intervals may overlap. For example, der_pos = [1,6,3]; der_neg = [4,9,7]; produce result = [2;8;6].

Upvotes: 1

Laure
Laure

Reputation: 373

Here's a sample code. The function findpeaks returns all the peak. The loop then keeps indices of peaks that are in the wanted range.

I added a test to avoid errors in case of no found peak (index will be -1), and to keep the first peak if two peaks are found. You can use a cell if you want to keep all peaks in an interval.

interpolated = [1,5,3,2,7,10,8,14,4];
der_pos = [1 6 7 ];
der_neg = [4 9 8];

[~,i]=findpeaks(interpolated);
indices= -1+zeros(size(der_pos,2),1);
for loopi = 1:length(i)
    val = i(i>=der_pos(loopi)&i<=der_neg(loopi));
    if ~isempty(val)
        indices(loopi) = val(1);
    end
end

Upvotes: 1

Related Questions