Reputation: 145
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:
in the interval der_pos(1):der_neg(1)
→ 1:4
→ interpolated(1:4) = [1,5,3,2]
the max is 5
which is at index 2
.
in the interval der_pos(2):der_neg(2)
→ 6:9
→ interpolated(6:9) = [10,8,14,4]
the max is 14
which is at index 8
.
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
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
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