Round number closest to 0 in array

I have an array with numbers which are all really small (-9e-07 upto 2e+06). I want to round the values in each column of a 4D array,F, which are the closest to zero, to zero.

 Accepted Answer

[~,idx]=min(abs(a))
a(idx)=0

12 Comments

I just want to clarify; is the first line there to identify the minimum values of an array 'a' whilst ignoring the sign of each. And the second line replaces the identified elements in the array with 0?
The answer to both question is: Yes. Because at first, you wanted to identify the closest element to zero, which means I have to check the absolute values of the elements. Secondly, I just replaced the value with 0.
Thanks for clarifying that. It works perfectly if I first index the array I want to apply it to, if I don't index it however, it doesn't produce the output I'm looking for. I've posted the complete code below if you can make sense of it.
Array 'F', which is a 4D array is where I want to apply the code you've given. If I do: F1 = F(2,2,1,:); then it works as I would like it to. Otherwise it doesn't change any elements of the array 'F'. Sorry if that is unclear, I can try my best to clarify.
%Define grid points for pressure to be calculated at, step size of 0.001m =
%1mm. Choose value of 0.01m = 10mm.
x_g = (0:0.001:x );
y_g = (0:0.001:y);
z_g = (0:0.001:z);
%Define time vector. Pressure will be calculated at every time step.
%Time step: 1e-08s = 10ns
%End time: 1e-06s = 1microsecond
t = (0:10^-8:t2*10^-6);
%Create 4D grid
[X_G, Y_G, Z_G, T_G] = ndgrid(x_g,y_g,z_g,t);
%Obtain values for distances between source and grid points in meters
r = (sqrt(((X_G-xs).^2) +((Y_G-ys).^2)+((Z_G-zs).^2)));
%Populate arrays for speed of cound and initial pressure with size equal
%to T_G to allow matrices to be manipulated
C_G = repmat(c, size(T_G));
p0_G = repmat(p0, size(T_G));
%Determine arrival time (r/c)
G = r ./ C_G;
%Determine values of function within delta function (t-r/c)
F = T_G - G;
[~,idx] = min(abs(F));
F(idx) = 0;
Image Analyst
Image Analyst on 25 Dec 2017
Edited: Image Analyst on 25 Dec 2017
It should work because idx is a linear index, so it doesn't matter what the dimension of the array is. It could be 4-D or any dimension. You shouldn't need to create the F1 variable.
However, in a loop, or if you do it a second time, the min will be zero and the code will just set the zero to zero, not the smallest non-zero number. If you want the smallest non-zero number, first replace zeros with inf before running the code, then set them back to zero afterwards.
Also, we can't run your code because we don't have values for x, y, and z.
Yeah that's what I thought, I'm not sure why it isn't working. The input variables are:
x = 0.01
y = 0.01
z = 0.01
t2 = 3
xs = 0
ys = 0
zs = 0
c = 1500
p0 = 1
mathman
mathman on 25 Dec 2017
Edited: mathman on 25 Dec 2017
Specifically, the element at F(2,2,1,95) should be set to 0. Which it does if I index F as above. If I run min(abs(F)) on it's own it gives me the smallest values in each column which is perfect, its just not replacing those values with 0. It's replacing some values in the first column of the 1st page with 0 and seemingly nothing else.
birdman wrote the code assuming a vector. For a multi-dimensional array you need to use (:) to turn it into a vector:
[minValue, linearIndexOfMinValue] = min(abs(F(:)));
Unfortunately though, the code still needs to be modified like I said to find the value closest to zero but not zero. As is, with your parameters, the closest index is 1 where F = 0 at that point, so it will just set 0 equal to 0. Can you do this modification?
Ah I see. Do you mean setting the zeros to Inf before indexing and then reverting them?
Assuming that is what you meant, I've done that but it still doesn't seem to work. I've altered the code you posted to be
[minValue, linearIndexOfMinValue] = min(abs(F(:,:,:,:)));
I think that should find the values and positions of the smallest values in each position within F. But again, when replacing them with 0 it just changes the first 5 values of F(:,1,1,1);.
On reading the original question again, I might've been unclear with exactly what I want. I want the values closest to 0 in each column within the 4D array F.
I've tried to do it like this:
Z = zeros(size(F));
[~, idx] = min(abs(F(:,:,:,:)));
F(idx) = Z;
But it gives me an error on the final line saying 'In an assignment A(:) = B, the number of elements in A and B must be the same.'
The number of elements in F and Z are the same so I'm not sure what the problem there is.
Help us understand what a "column" means in this 4-D array. For example are these RGB images and the 4th dimension is the frame (i.e. time) dimension? And WHY do you want to do this quirky thing?
The 4th dimension is time. The other 3 are just points in space. So, a column in this context is just the y-axis and the rows are x-axis and 'pages' are z-axis.
Each element in F is an output of the formula: T-(r/c) where T is the time at each point, r is the distance from a source (in this case:(0,0,0)) and c is the speed of sound.
The formula T-(r/c) is 'contained within' a delta distribution, so it needs to set the output of that to 1 when T = r/c (in other words; when it's 0). The problem is that it never reaches exactly 0 at any point, it just gets super small at some points. Hence the reason I want to find the smallest values and set them to 0.
After that I'll make a logical array,H, to set any values of 0 to 1 and anything else to 0.
Using this logical array ,H, I can then calculate my final array using the delta distribution.
I've tried to explain it as best I can, hopefully it's clear.
mathman
mathman on 25 Dec 2017
Edited: mathman on 25 Dec 2017
I think I understand what's going on now.
So when I do [~, idx] = min(abs(F(:,:,:,:)));
It lists the element positions of each column which is the lowest. Then when I do F(idx) = 0; it replaces the elements identified in 'idx' with 0. But with multi-dimensional array indexing, the elements of F are listed in a column. So idx identifies elements ranging from 1-5. Therefore, when it tries to replace the elements it's just doing elements 1-5 from the WHOLE array expressed as a column. Rather than EACH individual column! I think I've got what the issue is now, I'm not sure how I would solve it yet.

Sign in to comment.

More Answers (0)

Asked:

on 25 Dec 2017

Edited:

on 25 Dec 2017

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!