I have this distance matrix between 6 points of one structure and 5 points of the second structure:
a = [2.565 0.394 2.927 2.774 1.600;
0.402 1.950 3.272 2.086 0.985;
2.965 3.250 1.720 0.841 2.305;
2.797 2.050 0.830 0.829 1.585;
3.865 2.662 1.246 2.086 2.634;
1.592 0.977 2.305 1.579 0.274]
I need the minimum distances between points. Sometimes I get one point between two points of the other structure. 0.274 0.394 0.402 0.830 0.829
This means I will get point 4 (from the 6 points structure) to be closest to points 3 and 4 from the other structure. I am not allowed to have one point closest to two others.
How do I get unique pairs of these close points?
I think I should verify if there is a small difference between first 2 minima in a row. The problematic point is always in the middle of other two.
I need to get 0.274 0.394 0.402 0.830 0.841 (see answer 1).
My original code was:
for i = 1 : 6
mins(i) = min(a(i, :));
end
mins = sort(mins);
mins = mins(1 : 5);
Thanks.
So thanks beaker, I do hope the question gets another answer,
[pairs,a1,a2]=matchpairs(a,1,'min')
pairs =
2 1
1 2
4 3
3 4
6 5
a1 =
5
a2 =
0×1 empty double column vector
Also I hope someone explains what the other outputs mean and when can they be useful.
Related
suppose that we are determine peaks in vector as follow:
we have real values one dimensional vector with length m,or
x(1),x(2),.....x(m)
if x(1)>x(2) then clearly for first point peak(1)=x(1);else we are then comparing x(3) to x(2),if x(3)
[ indexes,peaks]=function(x,m);
c=[];
b=[];
if x(1)>x(2)
peaks(1)=x(1);
else
for i=2:m-1
if x(i+1)< x(i) & x(i)>x(i-1)
peak(i)=x(i);
end;
end
end
end
peaks are determined also using following picture:
sorry for the second picture,maybe it is not triangle,just A and C are on straight line,but here peak is B,so i can't continue my code for writing algorithm to find peak values in my vector.please help me to continue it
updated.numercial example given
x=[2 1 3 5 4 7 6 8 9]
here because first point is more then second,so it means that peak(1)=2,then we are comparing 1 to 3,because 3 is more then 1,we now want to compare 5 to 3,it is also more,compare 5 to 4,because 5 is more then 4,then it means that peak(2)=5,,so if we continue next peak is 7,and final peak would be 9
in case of first element is less then second,then we are comparing second element to third one,if second is more then third and first elements at the same time,then peak is second,and so on
You could try something like this:
function [peaks,peak_indices] = find_peaks(row_vector)
A = [min(row_vector)-1 row_vector min(row_vector)-1];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
Save it as find_peaks.m
Now, you can use it as:
>> A = [2 1 3 5 4 7 6 8 9];
>> [peaks, peak_indices] = find_peaks(A)
peaks =
2 5 7 9
peak_indices =
1 4 6 9
This would however give you "plateaus" as well (adjacent and equal "peaks").
You can use diff to do the comparison and add two points in the beginning and end to cover the border cases:
B=[1 diff(A) -1];
peak_indices = find(B(1:end-1)>=0 & B(2:end)<=0);
peaks = A(peak_indices);
It returns
peak_indices =
1 4 6 9
peaks =
2 5 7 9
for your example.
findpeaks does it if you have a recent matlab version, but it's also a bit slow.
This proposed solution would be quite slow due to the for loop, and you also have a risk of rounding error due to the fact that you compare the maximal value to the central one instead of comparing the position of the maximum, which is better for your purpose.
You can stack the data so as to have three columns : the first one for the preceeding value, the second is the data and the third one is the next value, do a max, and your local maxima are the points for which the position of the max along columns is 2.
I've coded this as a subroutine of my own peak detection function, that adds a further level of iterative peak detection
http://www.mathworks.com/matlabcentral/fileexchange/42927-find-peaks-using-scale-space-approach
I have a matrix like this:
fd =
x y z
2 5 10
2 6 10
3 5 11
3 9 11
4 3 11
4 9 12
5 4 12
5 7 13
6 1 13
6 5 13
I have two parts of my problem:
1) I want to calculate the difference of each two elements in a column.
So I tried the following code:
for i= 1:10
n=10-i;
for j=1:n
sdiff1 = diff([fd(i,1); fd(i+j,1)],1,1);
sdiff2 = diff([fd(i,2); fd(i+j,2)],1,1);
sdiff3 = diff([fd(i,3); fd(i+j,3)],1,1);
end
end
I want all the differences such as:
x1-x2, x1-x3, x1-x4....x1-x10
x2-x3, x2-x4.....x2-x10
.
.
.
.
.
x9-x10
same for y and z value differences
Then all the values should stored in sdiff1, sdiff2 and sdiff3
2) what I want next is for same z values, I want to keep the original data points. For different z values, I want to merge those points which are close to each other. By close I mean,
if abs(sdiff3)== 0
keep the original data
for abs(sdiff3) > 1
if abs(sdiff1) < 2 & abs(sdiff2) < 2
then I need mean x, mean y and mean z of the points.
So I tried the whole programme as:
for i= 1:10
n=10-i;
for j=1:n
sdiff1 = diff([fd(i,1); fd(i+j,1)],1,1);
sdiff2 = diff([fd(i,2); fd(i+j,2)],1,1);
sdiff3 = diff([fd(i,3); fd(i+j,3)],1,1);
if (abs(sdiff3(:,1)))> 1
continue
mask1 = (abs(sdiff1(:,1)) < 2) & (abs(sdiff2(:,1)) < 2) & (abs(sdiff3:,1)) > 1);
subs1 = cumsum(~mask1);
xmean1 = accumarray(subs1,fd(:,1),[],#mean);
ymean1 = accumarray(subs1,fd(:,2),[],#mean);
zmean1 = accumarray(subs1,fd(:,3),[],#mean);
fd = [xmean1(subs1) ymean1(subs1) zmean1(subs1)];
end
end
end
My final output should be:
2.5 5 10.5
3.5 9 11.5
5 4 12
5 7 13
6 1 13
where, (1,2,3),(4,6),(5,7,10) points are merged to their mean position (according to the threshold difference <2) whereas 8 and 9th point has their original data.
I am stuck in finding the differences for each two elements of a column and storing them. My code is not giving me the desired output.
Can somebody please help?
Thanks in advance.
This can be greatly simplified using vectorised notation. You can do for instance
fd(:,1) - fd(:,2)
to get the difference between columns 1 and 2 (or equivalently diff(fd(:,[1 2]), 1, 2)). You can make this more elegant/harder to read and debug with pdist but if you only have three columns it's probably more trouble than it's worth.
I suspect your first problem is with the third argument to diff. If you use diff(X, 1, 1) it will do the first order diff in direction 1, which is to say between adjacent rows (downwards). diff(X, 1, 2) will do it between adjacent columns (rightwards), which is what you want. Matlab uses the opposite convention to spreadsheets in that it indexes rows first then columns.
Once you have your diffs you can then test the elements:
thesame = find(sdiff3 < 2); % for example
this will yield a vector of the row indices of sdiff3 where the value is less than 2. Then you can use
fd(thesame,:)
to select the elements of fd at those indexes. To remove matching rows you would do the opposite test
notthesame = find(sdiff > 2);
to find the ones to keep, then extract those into a new array
keepers = fd(notthesame,:);
These won't give you the exact solution but it'll get you on the right track. For the syntax of these commands and lots of examples you can run e.g. doc diff in the command window.
I have a cluster of points in 3D point clouds, says
A = [ 1 4 3;
1 2 3;
1 6 3;
1 5 3];
The distance matrix then was found:
D= pdist(A);
Z= squareform(D);
Z =
0 2 2 1
2 0 4 3
2 4 0 1
1 3 1 0
I would like to sort the points so that the sum of the distance travelled through the points will be the smallest, and output in another matrix. This is similar to TSP problem but in a 3D model. Is there any function can do this?
Your help is really appreciated in advance.
This could be one approach and must be efficient enough for a wide range of datasizes -
D = pdist(A);
Z = squareform(D); %// Get distance matrix
N = size(A,1); %// Store the size of the input array for later usage
Z(1:N+1:end) = Inf; %// Set diagonals as Infinites as we intend to find
%// minimum along each row
%// Starting point and initialize an array to store the indices according
%// to the sorted requirements set in the question
idx = 1;
out_idx = zeros(N,1);
out_idx(1) = idx;
%// Perform an iterative search to look for nearest one starting from point-1
for k = 2:N
start_ind = idx;
[~,idx] = min(Z(start_ind,:));
Z(:,start_ind) = Inf;
out_idx(k) = idx;
end
%// Now that you have the list of indices based on the next closest one,
%// sort the input array based on those indices and have the desired output
out = A(out_idx,:)
Sample run for given input -
A =
1 4 3
1 2 3
1 6 3
1 5 3
1 2 3
out =
1 4 3
1 5 3
1 6 3
1 2 3
1 2 3
The only way I can see you do this is by brute force. Also bear in mind that because this is brute force, this will scale very badly as the total number of points increases. This is fine for just 4 points, but if you want to scale this up, the total number of permutations for N points would be N! so be mindful of this before using this approach. If the number of points increases, then you may get to a point where you run out of memory. For example, for 10 points, 10! = 3628800, so this probably won't bode well with memory if you try and go beyond 10 points.
What I can suggest is to generate all possible permutations of visiting the 4 points, then for each pair of points (pt. 1 -> pt. 2, pt. 2 -> pt. 3, pt. 3 -> pt. 4), determine and accumulate the distances, then find the minimum distance accumulated. Whichever distance is the minimum will give you the sequence of nodes you need to visit.
Start with perms to generate all possible ways to visit four points exactly once, then for each pair of points, figure out the distances between the pairs and accumulate the distances. Keep considering pairs of points along each unique permutation until we reach the end. Once we're done, find the smallest distance that was generated, and return the sequence of points to generate this sequence.
Something like:
%// Your code
A = [ 1 4 3;
1 2 3;
1 6 3;
1 5 3];
D = pdist(A);
Z = squareform(D);
%// Generate all possible permutations to visit for our points
V = perms(1:size(A,1));
%// Used to accumulate our distances per point pair
dists = zeros(size(V,1), 1);
%// For each point pair
for idx = 1 : size(V,2)-1
%// Get the point pair in the sequence
p1 = V(:,idx);
p2 = V(:,idx+1);
%// Figure out the distance between the two points and add them up
dists = dists + Z(sub2ind(size(Z), p1, p2));
end
%// Find which sequence gave the minimum distance travelled
[~,min_idx] = min(dists);
%// Find the sequence of points to generate the minimum
seq = V(min_idx,:);
%// Give the actual points themselves
out = A(seq,:);
seq and out give the actual sequence of points we need to visit, followed by the actual points themselves. Note that we find one such possible combination. There may be a chance that there is more than one possible way to get the minimum distance travelled. This code just returns one possible combination. As such, what I get with the above is:
>> seq
seq =
3 4 1 2
>> out
out =
1 6 3
1 5 3
1 4 3
1 2 3
What the above is saying is that we need to start at point 3, then move to point 4, point 1, then end at point 2. Also, the sequence of pairs of points we need to visit is points 3 and 4, then points 4 and 1 and finally points 1 and 2. The distances are:
Pt. 3 - Pt. 4 - 1
Pt. 4 - Pt. 1 - 1
Pt. 1 - Pt. 2 - 2
Total distance = 4
If you take a look at this particular problem, the minimum possible distance would be 4 but there is certainly more than one way to get the distance 4. This code just gives you one such possible traversal.
Sorry for the perhaps confusing title...
Basically I have a 3x3 matrix containing elevation angle, azimuth angle and range. I want to generate new matrices each time elevation >5 deg. There are usually about 5 segments that have this data and I want to separate each one into a new matrix.
I know how to index but not sure how to put this condition in...
Thanks
sat_tcs=llh2tcsT(sat_llh,station_llh);
sat_elev=atan2(sat_tcs(3,:),sqrt(sat_tcs(1,:).^2+sat_tcs(2,:).^2));
sat_azim=atan2(-sat_tcs(2,:),sat_tcs(1,:));
range=sqrt(sat_tcs(1,:).^2+sat_tcs(2,:).^2+sat_tcs(3,:).^2);` sat_elev(sat_elev < 5*deg2rad) = NaN; sat_look_tcs=[sat_elev;sat_azim;range];
It would be helpful to have some examples of the input and expected output, but taking a guess at what you mean I'd try this:
elevation_column = 3;
threshold = 5;
m = [1 2 3; 4 5 6; 7 8 9; 1 2 3];
n = m(m(:,elevation_column)>threshold,:);
This produces:
n =
4 5 6
7 8 9
Sorry, I would post an image of my graph but supposedly I need reputation points for that..but it the elevation data looks almost sinusoidal and so it has regions over 5 deg and then falls again. I want to generate a new matrix for every set above this angle
suppose that we are determine peaks in vector as follow:
we have real values one dimensional vector with length m,or
x(1),x(2),.....x(m)
if x(1)>x(2) then clearly for first point peak(1)=x(1);else we are then comparing x(3) to x(2),if x(3)
[ indexes,peaks]=function(x,m);
c=[];
b=[];
if x(1)>x(2)
peaks(1)=x(1);
else
for i=2:m-1
if x(i+1)< x(i) & x(i)>x(i-1)
peak(i)=x(i);
end;
end
end
end
peaks are determined also using following picture:
sorry for the second picture,maybe it is not triangle,just A and C are on straight line,but here peak is B,so i can't continue my code for writing algorithm to find peak values in my vector.please help me to continue it
updated.numercial example given
x=[2 1 3 5 4 7 6 8 9]
here because first point is more then second,so it means that peak(1)=2,then we are comparing 1 to 3,because 3 is more then 1,we now want to compare 5 to 3,it is also more,compare 5 to 4,because 5 is more then 4,then it means that peak(2)=5,,so if we continue next peak is 7,and final peak would be 9
in case of first element is less then second,then we are comparing second element to third one,if second is more then third and first elements at the same time,then peak is second,and so on
You could try something like this:
function [peaks,peak_indices] = find_peaks(row_vector)
A = [min(row_vector)-1 row_vector min(row_vector)-1];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
Save it as find_peaks.m
Now, you can use it as:
>> A = [2 1 3 5 4 7 6 8 9];
>> [peaks, peak_indices] = find_peaks(A)
peaks =
2 5 7 9
peak_indices =
1 4 6 9
This would however give you "plateaus" as well (adjacent and equal "peaks").
You can use diff to do the comparison and add two points in the beginning and end to cover the border cases:
B=[1 diff(A) -1];
peak_indices = find(B(1:end-1)>=0 & B(2:end)<=0);
peaks = A(peak_indices);
It returns
peak_indices =
1 4 6 9
peaks =
2 5 7 9
for your example.
findpeaks does it if you have a recent matlab version, but it's also a bit slow.
This proposed solution would be quite slow due to the for loop, and you also have a risk of rounding error due to the fact that you compare the maximal value to the central one instead of comparing the position of the maximum, which is better for your purpose.
You can stack the data so as to have three columns : the first one for the preceeding value, the second is the data and the third one is the next value, do a max, and your local maxima are the points for which the position of the max along columns is 2.
I've coded this as a subroutine of my own peak detection function, that adds a further level of iterative peak detection
http://www.mathworks.com/matlabcentral/fileexchange/42927-find-peaks-using-scale-space-approach