sophie astro
sophie astro

Reputation: 3

Filter matrix when entries are close

I am using Matlab and I have a problem with filtering a matrix. The matrix is filled with rising numbers, I want to delete all entries in the matrix which are closer then a given intervall to the entry before (n-1).

I did this already with a for loop, and it worked. The problem is, it took five hours to compute!

my code:

for i=2:y   
    if ((arrMaster1(i-1)+deadtime)<arrMaster1(i))
        j=j+1;
        arrMaster1cut(j,3)=int64(arrMaster1(i));
    else
    end   
end

Upvotes: 0

Views: 38

Answers (2)

Wolfie
Wolfie

Reputation: 30047

Firstly, you can do all of your subtractions at once, rather than individual elements each loop. This can be made even easier by using diff like so

diffs = diff(arrMaster1(1:y));
% equivalent to: diffs = arrMaster1(2:y) - arrMaster1(1:y-1);

Then create a logical array, to test if your differences are greater than deadtime:

keepthese = [true, diffs > deadtime]; 
% outputs vector like [1 0 1 1 1 0 ...], of length y, where 1 is true and 0 is false
% diffs is of length y-1, so extra "true" is needed.
% There is a "true" in the place of every element you want to keep.

Finally, create your output:

arrMaster1cut = int64(arrMaster1(keepthese));
% This is called logical indexing, you're choosing all elements of
% arrMaster1 where keepthese has the value 1 / true

All together:

diffs = diff(arrMaster1(1:y));                 % Get differences for tolerencing
keepthese = [true, diffs > deadtime];          % Get indices to keep
arrMaster1cut = int64(arrMaster1(keepthese));  % Create output

Edit note

The keepthese vector is a row vector, hence concatenation with a comma. If arrMaster1 is a column vector, then diffs will be too, so instead use a semicolon

keepthese = [true; diffs > deadtime];          % Get indices to keep (column vector)

A note on indexing

Logical indexing vs normal indexing. Let's say we wanted to pull the 1st, 2nd and 4th elements from a 5 element matrix. We could use two methods:

 elements = mymatrix([1,2,4]);
 elements = mymatrix(logical([1,1,0,1,0])); % logical converts 1/0 to true/false

Obviously, the second approach (logical indexing) isn't as clear in this example. However, when used above it allows us to avoid a call to the find function, which would convert the logical index into a numbered vector:

find([1,1,0,1,0]); % = [1,2,4]

Therefore, we gain a speed advantage.

Upvotes: 1

user2999345
user2999345

Reputation: 4195

i don't have all your code so this is just a guess, but your code maybe run so slow because you don't pre-allocate memory for arrMaster1cut, and you change it's size in each iteration.

moreover, you can vectorize the entire code using diff:

% random arrMaster1 array
y = 100;
arrMaster1 = randi(100,[1 y]);
deadtime = 5;
% differences vector
d = diff(arrMaster1);
% differences greater than deadtime
idxs = find(d > deadtime);
% produce arrMaster1cut
arrMaster1cut1 = int64(arrMaster1(idxs+1));
% your method
j = 0;
arrMaster1cut2 = [];
for i=2:y
    if ((arrMaster1(i-1)+deadtime)<arrMaster1(i))
        j=j+1;
        arrMaster1cut2(j)=int64(arrMaster1(i));
    else
    end
end
% check for equal results
isequal(arrMaster1cut2, arrMaster1cut1)

Upvotes: 0

Related Questions