Removing data from a structure that is less than a certain threshold
10 views (last 30 days)
I am running a code to find the positions and trajectories of microparticles. I get a lot of noise as my particle concentration is quite dense. The false positives slow down my code significantly so I want to get rid of them every loop so I have made the following code:
while c <= length(AllTraj.Passive)
if ((length(AllTraj.Passive(c).T) <= 10) && ...
(max(AllTraj.Passive(c).T) < (i-2)))
AllTraj.Passive(c) = ;
AllTraj.Passive represents a struct with my connected particle trajectories each with time (T), X and Y values.
I want to get rid of any particles (rows) which have a trajectory of length 10 or less if they are no longer being tracked in the current frame (i-2 is current frame).
This code seems to run very slowly when I have a lot of particles and when I clear the rows which meet the criteria.
Is there a faster way to remove data that is less than a threshold time?
Jan on 16 Jul 2019
Edited: Jan on 16 Jul 2019
The iterative growing and shrinking of arrays is extremely expensive. Better:
nTraj = numel(AllTraj.Passive);
remove = false(1, nTraj);
for c = 1:nTraj
tmp = AllTraj.Passive(c).T;
% [EDITED: remove -> remove(c)]
remove(c) = (numel(tmp) <= 10) && (max(tmp) < (i-2));
AllTraj.Passive(remove) = ;
Remember: To create a growing array, e.g.:
x = ;
for k = 1:1e6
x(k) = rand;
Matlab has to reserve sum(1:1e6)*8 bytes in the RAM and copy almost the same amount of memory. This is 4 TeraByte, although the final array has 8 MB only. Of course this is slow.
The solution is a pre-allocation:
x = zeros(1, 1e6);
Or in your case to collect the indices to remove at first and remove them in one step after the loop.
More Answers (1)
Guillaume on 16 Jul 2019
This code seems to run very slowly
The code you've posted either doesn' do anything because the if condition is never true, or errors (if the if condition is ever true). It can't be the code you actually use.
If your loop has a known number of iterations you should be using for not while. That way you can't mess up the iterator variable. Let's see what would happen if your if test was true:
%removed unnecessary brackets from the expression to make it easier to read
%check that the field T has less than 10 elements and that the maximum is less than something.
%i is a terrible variable name by the way.
if length(AllTraj.Passive(c).T) <= 10 && max(AllTraj.Passive(c).T) < (i-2)
The only thing you if the test is true is to replace the structure stored in Passive(c) by an empty array. The code then reaches the else. Since the if was true, the code in the else is not executed and c is not incremented. The code then reaches the end of the while loop.
Since c was not incremented, c is still the same as previous iteration. So, we know that AllTraj.Passive(c) is . And therefore AllTraj.Passive(c).T is now an error. There is no field T, Passive(c) is not a structure anymore.
A for loop would avoid the bug:
for c = 1:numel(AllTraj.Passive)
if numel(AllTraj.Passive(c).T) <= 10 && max(AllTraj.Passive(c).T) < (i-2)
AllTraj.Passive(c) = ;
Unfortunately for you, there is no way to make this faster without completely changing the way you store your data originally.