-1

I am new to MATLAB and I wonder is there any way for me to do the following:

  • get a list of indices of minimum values in each 180 samples of my data which is 18000 samples in length

This is how I used to do it in Python (with numpy.where), but now I'm trying to do it in MATLAB. any help please.

dips = numpy.where((smoothEnvelop[180:-180] < 7))[0] + 180 #7 is a threshold example
Jason Aller
  • 3,541
  • 28
  • 38
  • 38

2 Answers2

1

Following is a solution using a loop. It also incorprates the possibility to define a step size.

% Input.
x = round(rand(20, 1) * 100)

% Window size.
ws = 5;

% Step size.
ss = 1;

% Number of elements.
nx = numel(x);

% Number of result elements.
ny = numel(1:ss:(nx - ws + 1));

% Initialize output.
y = zeros(ny, 1);

% Calculate output.
jj = 1;
for ii = 1:ss:(nx - ws + 1)
  ww = x(ii:(ii + ws - 1));
  [~, yLoop(jj)] = min(ww);
  yLoop(jj) = yLoop(jj) + ii - 1;
  jj = jj + 1;
end

% Output.
y

The indices of the minima stored in y are with respect to the original input x.

Output for ws = 5, and ss = 1:

x =
   88
   74
   96
   31
    6
   67
   98
   92
   69
   49
   12
   28
   43
   87
   68
   49
   20
   98
   83
   62

y =
    5
    5
    5
    5
    5
   10
   11
   11
   11
   11
   11
   12
   17
   17
   17
   17

EDIT

I added a version using indexing, which is way faster for large inputs.

% Input.
x = round(rand(20000, 1) * 100);

% Window size.
ws = 5;

% Step size.
ss = 1;

% Number of elements.
nx = numel(x);

% --- Solution using loop --- %

% Number of result elements.
ny = numel(1:ss:(nx - ws + 1));

% Initialize output (loop).
yLoop = zeros(ny, 1);

tic
% Calculate output.
jj = 1;
for ii = 1:ss:(nx - ws + 1)
  ww = x(ii:(ii + ws - 1));
  [~, yLoop(jj)] = min(ww);
  yLoop(jj) = yLoop(jj) + ii - 1;
  jj = jj + 1;
end
tLoop = toc;

% Output (loop).
yLoop;

% --- Solution using indexing --- %

tic
% Calculate indices.
ind = 1:ss:(nx - ws + 1);
ind = repmat(ind, ws, 1) + ([0:(ws - 1)].' * ones(1, numel(ind)));

% Calculate output (indexing).
[~, yIndexing] = min(x(ind));
yIndexing = (yIndexing + (0:ss:(ss * (size(ind, 2) - 1)))).';
tIndexing = toc;

% Compare loop and indexing version.
fprintf("yLoop == yIndexing: %d\n", sum(yLoop == yIndexing) == ny);
fprintf("yLoop time: %f s\n", tLoop);
fprintf("yIndeing time: %f s\n", tIndexing);

For n = 20000, ws = 5, and ss = 1, we get the following times:

yLoop time: 0.672510 s
yIndeing time: 0.004466 s
Community
  • 1
  • 1
HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • thank you sir, but as i stayted, i want to get the indices of those minimums, i used find(y(jj)) but i think i still dont know how to use it correctly, because it gives me all 1 –  Mar 31 '19 at 10:08
  • Ah, I'm sorry, I missed that! Will try to provide an updated solution soon. – HansHirse Mar 31 '19 at 10:30
  • Updated my solution - sorry again for the initial, incomplete answer! – HansHirse Mar 31 '19 at 10:50
  • @AmineChadi Now, both versions - loop and indexing - should work properly. – HansHirse Apr 01 '19 at 05:51
1

Let

data = [6 7 7 3 6 1 3 7 2 1 0 8]; % example data
N = 4; % block size

For disjoint blocks, just reshape intro a matrix so that each block becomes a column and then compute the arg min of each column:

[~, indices] = min(reshape(data,N,[]), [], 1);

gives

indices =
     4     2     3

For sliding blocks, create an indexing matrix and then compute arg min along each column:

[~, indices] = min(data(bsxfun(@plus, 1:numel(data)-N+1, (0:N-1).')), [], 1);

gives

indices =
     4     3     4     3     2     1     4     4     3
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147