I have a matrix named data with x,y,z positions.
I have calculated the distance between all the points using pdist and got the matrix 'out' which has the diff of x, diff of y and diff of z and their corresponding rows.
A= data;
D1= pdist(A(:,1));
D2= pdist(A(:,2));
D3= pdist(A(:,3));
D = [D1' D2' D3'];
tmp = ones(size(A,1));
tmp = tril(tmp,-1);
[rowIdx,colIdx ] = find(tmp);
out = [D,A(rowIdx,:),A(colIdx,:)];
I want to calculate the average of all those points which satisfies certain conditions:
diff z <7 and diff x and diff y < 4.
So I wrote the following code:
a= find (out(:,3)>0);
cal=out(a,:);
b= cal(:,3)<7;
cal2 = cal(b,:);
[s,k]= size (cal2);
for i=1:s
if (cal2(i,1) < 4) && (cal2(i,2) < 4);
xmean = mean (cal2(i,[4,7]));
ymean = mean (cal2(i,[5,8]));
zmean = mean (cal2(i,[6,9]));
fd = [xmean ymean zmean];
end
end
The problem is, with this code I can get the mean of two points at a time. So, my output is giving me more number of points than what I actually want.I want to get the mean off all the points which satisfies the condition.
My final goal is to get a list of points where I can get the points whose (diff z is > 7 )+ (the mean of the points whose diff z is <7 while diff x < 4 and diff y <4) + (diff z < 7 but diff x and diff y > 4).
Can someone please help?
A = [0,0,0;0,0,5;0,0,10];
% create matrices with the distances
% [p1-p1, p1-p2, p1-p3;
% p2-p1, p2-p2, p2-p3;
% p3-p1, p3-p2, p3-p3];
dx= squareform(pdist(A(:,1)));
dy= squareform(pdist(A(:,2)));
dz= squareform(pdist(A(:,3)));
% dz = [0,5,10;5,0,5;10,5,0];
% select all points stisfying condition
idx = dx < 4 & dy < 4 & dz < 7;
% remove entries of the main diagonal
idx(sub2ind(size(idx),1:size(A,1),1:size(A,1))) = 0;
% select all indices. Since all distances are 2 times in the full matrix,
% only r or c is needed
[r,c] = find(idx==1);
% r = [2,1,3,2]; c = [1,2,2,3]
meanOfPoints = mean(A(r,:))
Say you want the mean of all points where diffZ<7, diffX<4 and diffY<4. Assuming that out stores the corresponding differences in x,y,z in the first three columns, and point coordinates in columns 4-9.
%# this is true for all points you want to average
condition = out(:,1) > 4 & out(:,2) > 4 & out(:,3) < 7;
%# get coordinates satisfying the condition; create a 2n-by-3 array
coords = [out(condition, 4:6);out(condition, 7:9)];
%# if you don't want to count coordinates multiple times when taking the average, run
%# coords = unique(coords,'rows');
%# average
meanCoordinates = mean(coords,1);
Related
I'm using data set with 200 data points that is used to draw B-Spline curve and I want to extract the 100 original control points from this curve to use it in one algorithm to solve one problem. The result of control points it's too small compared with the value of the data points of B-Spline curve so I don't know if I make something wrong in the following code or not I need help to know that because I must used these control points to complete my study in one algorithm
link of set of data points:
https://drive.google.com/open?id=0B_2BUqaJptbqUkRWLWdmbmpQakk
Code :
% read data set
dataset = importdata("path of data set here");
x = dataset(:,1);
y = dataset(:,2);
for i=1:200
controlpoints(i,1) = x(i);
controlpoints(i,2) = y(i);
controlpoints(i,3) = 0;
end
% Create Q with some points from originla matrix controlpoints ( I take only 103 points)
counter =1;
for i=1:200
if (i==11) || (i==20) || (i==198)
Q(counter,:) = F(i,:);
counter = counter +1;
end
if ne(mod(i,2),0)
Q(counter,:) = F(i,:);
counter = counter+1;
end
end
I used Centripetal method to find control points from curve like the following picture
Complete my code:
% 2- Create Centripetal Nodes array from Q
CP(1) = 0;
CP(103) =1;
for i=2:102
sum = 0;
for j=2:102
sum = sum + sqrt(sqrt((Q(j,1)-Q(j-1,1))^2+(Q(j,2)-Q(j-1,2))^2));
end
CP(i) = CP(i-1) + (sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2))/sum);
end
p=3; % degree
% 3- Create U_K array from CP array
for i=1:103
U_K(i) = CP(i);
end
To calculate control points we must follow this equation P=Qx(R') --> R' is inverse of R matrix so we must find R matrix then fins P(control points matrix) by the above equation. The following scenario is used to find R matrix
and to calculate N in B-Spline we must use these recursive function
Complete my code :
% 5- Calculate R_i_p matrix
for a=1:100
for b=1:100
R_i_p(a,b) = NCalculate(b,p,U_K(a),U_K);
end
end
% 6- Find inverse of R_i_p matrix
R_i_p_invers = inv(R_i_p);
% 7- Find Control points ( 100 points because we have curve with 3 degree )
for i=1:100
for k=1:100
PX(i) = R_inv(i,k) * Q(k,1);
PY(i) = R_inv(i,k) * Q(k,2);
end
end
PX2 = transpose(PX);
PY2 = transpose(PY);
P = horzcat(PX2,PY2); % The final control points you can see the values is very small compared with the original data points vlaues
My Recursive Function to find the previous R matrix:
function z = NCalculate(j,k,u,U)
if (k == 1 )
if ( (u > U(j)) && (u <= U(j+1)) )
z = 1;
else
z = 0;
end
else
z = (u-U(j)/U(j+k-1)-U(j)* NCalculate(j,k-1,u,U) ) + (U(j+k)-u/U(j+k)-U(j+1) * NCalculate(j+1,k-1,u,U));
end
end
Really I need to this help so much , I tried in this problem from one week :(
Updated:
Figure 1 for the main B-spline Curve , Figure 2 for the result control points after applied reverse engineering on this curve so the value is so far and so small compared with the original data points value
Updated(2):
I made some updates on my code but the problem now in the inverse of R matrix it gives me infinite value at all time
% 2- Create Centripetal Nodes array from Q
CP(1) = 0;
CP(100) =1;
sum = 0;
for i=2:100
sum = sum + sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2));
end
for i=2:99
CP(i) = CP(i-1) + (sqrt(sqrt((Q(i,1)-Q(i-1,1))^2+(Q(i,2)-Q(i-1,2))^2))/sum);
end
% 3- Create U_K array from CP array
for i=1:100
U_K(i) = CP(i);
end
p=3;
% create Knot vector
% The first elements
for i=1:p+1
U(i) = 0;
end
% The last elements
for i=100:99+p+1
U(i) = 1;
end
% The remain elements
for j=2:96
sum = 0;
for i=j:(j+p-1)
sum = sum + U_K(i);
end
U(j+p) = (1/p)* sum;
end
% 5- Calculate R_i_p matrix
for a=1:100
for b=1:100
R_i_p(a,b) = NCalculate(b,p,U_K(a),U);
end
end
R_i_p_invers = inv(R_i_p);
% 7- Find Control points ( 100 points )
for i=1:100
for k=1:100
if isinf(R_inv(i,k))
R_inv(i,k) = 0;
end
PX(i) = R_inv(i,k) * Q(k,1);
PY(i) = R_inv(i,k) * Q(k,2);
end
end
PX2 = transpose(PX);
PY2 = transpose(PY);
P = horzcat(PX2,PY2);
Note: I updated my NCalculate recursive function to give me 0 if the result is NaN (not a number )
function z = NCalculate(j,k,u,U)
if (k == 1 )
if ( (u >= U(j)) && (u < U(j+1)) )
z = 1;
else
z = 0;
end
else
z = (u-U(j)/U(j+k-1)-U(j)* NCalculate(j,k-1,u,U) ) + (U(j+k)-u/U(j+k)-U(j+1) * NCalculate(j+1,k-1,u,U));
end
if isnan(z)
z =0;
end
end
I think there are a few dubious issues in your approach:
First of all, if you try to create a b-spline curve interpolating 103 input points (and no other boundary conditions are imposed), the b-spline curve will have 103 control points regardless what degree the b-spline curve is.
The U_K array is the parameter assigned to each input point. They are not the same as the knot sequence ti used by the Cox DeBoor recursive formula. If the b-spline curve is of degree 3, you shall have (103+3+1) knot values in the knot sequence. You can create the knot values in the following way:
0) Denote the parameters as p[i], where i = 0 to (n-1), p[0]=0.0 and n is number of points.
1) Create the knot values as
knot[0] = (p[1]+p[2]+p[3])/D (where D is degree)
knot[1] = (p[2]+p[3]+p[4])/D
knot[2] = (p[3]+p[4]+p[5])/D
......
These are the interior knot values. You should notice that p[0] and p[n-1] will not be used in this step. You will have (n-D-1) interior knots.
2) Now, add p[0] to the front of the knot values (D+1) times and add p[n-1] to the end of the knot values (D+1) times and you are done. At the end, you will have (N+D+1) knots in total.
I have an array A (I have written so as to make it similar to the matrix that I am using) :
%%%%%%%%%%%%% This is Matrix %%%%%%%%%%%%%%%%%%%%
a = 3; b = 240; c = 10; d = 30; e = 1;
mtx1 = a.*rand(30,1) + a;
mtx2 = round((b-c).*rand(30,1));
mtx3 = round((d-e).*rand(30,1));
mtx4 = -9999.*ones(30,1);
A = [mtx1 mtx2 mtx3 mtx4];
for i = 10:12
for ii = 17 :19
A(i,:)= -9999;
A(ii,:)= 999;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I would calculate some statistical values, excluding from the calculation the values **-9999 and 999.
the statistical values must be calculated with respect to each column.
the columns represent respectively: the wind speed, direction, and
other parameters
I wrote a code but it is not correct
[nr,ncc]=size(A);
for i=1:ncc
B = A(:,i); %// Temp Vector
Oup=1; Odw=1; %// for Vector Control
while Oup>0 %// || Odw>0 % Oup>0 OR Odw>0 , Oup>0 && (AND) Odw>0
B=sort(B,'descend');
U = find(B<999 & B>-9999); % find for each column of the temp
%vector
Oup = length(U); % Calculates the length
B(U)=[]; % Delete values -9999 and 9999
end
% calculates parameters with the vector temp
count(i)=length(B);
med(i)=mean(B);
devst(i)=std(B);
mediana(i)=median(B);
vari(i)=var(B);
kurt(i)=kurtosis(B);
Asimm(i)=skewness(B);
Interv(i)=range(B);
Mass(i)=max(B);
Mini(i)=min(B);
if length(B)<nr
B(length(B)+1:nr)=nan;
end
C(:,i)=B(:); %//reconstruction of the original matrix
end
would you have any suggestions?
If your data set is in A, and you want to operate on it with a function f, just use logical indexing, i.e.:
f(A( ~(A==999 & A==-9999) )) =...
Alternatively, use find and linear indexing:
ind = find( ~(A==999 & A==-9999) );
f(A(ind)) = ....
I have distributed 100 random points(nodes) in an area by using following code
n=100; xm=100;ym=100;
for i = 1 : 1 :n
S(i).xd = rand(1,1)*xm ;
S(i).yd = rand (1,1)*ym ;
xd(i) = S(i).xd ;
yd(i) = S(i).yd ;
S(i).id = i;
S(i).type = 0;
S(i).g = 0 ;
S(i).E = Eo ;
S(i).type = 0 ;
end
Next I have fixed 10 gateway nodes at the edge of the area using following code
for i=1:1:10
Sg(i).xd= 2+100*rand(1,1);
Sg(i).yd=100;
xd(i)=Sg(i).xd;
yd(i)=Sg(i).yd;
Sg(i).id=i;
plot(Sg(i).xd,Sg(i).yd,'*k')
grid on;
hold on;
end
Now I have formed cluster heads using LEACH protocol from 100 nodes.
I have to find min distance gateway node from a CH. As there are 10 gateway nodes, I have to find which is closer to a CH in the area.
To determine CH I have used following code
for all nodes in the area
temp_rand1=rand;
if(temp_rand1<= (p/(1-p*mod(r,round(1/p)))))
countCHs1=countCHs1+1;
S3(i).type=1;
S3(i).g=round(1/p)-1;
C1(cluster1).xd=S3(i).xd;
C1(cluster1).yd=S3(i).yd;
**distance1=sqrt((S3(i).xd-(gw_node.x) )^2 + (S3(i).yd-(gw_node.y) )^2 );**
C1(cluster1).distance1=distance1;
C1(cluster1).id=i;
X(cluster1)=S3(i).xd;
Y(cluster1)=S3(i).yd;
cluster1=cluster1+1;
end
I know how to determine distance between a CH and one gateway node, But I do not know how to find closet gateway node from a set of gateway nodes.
Thanks in advance
Please reply
Not sure what you are asking. I assume you have set of fixed points in a straight line (marked blue) and set of random points (marked red). You want the Minimal distance between one fixed and one random point.
Try this code:
si = randi([0,100],10,2); %// Random points (red)
sg(:,1) = randi([0,100],10,1); %// fixed points x param (blue)
sg(:,2) = ones(10,1)*50; %// fixed points y param (blue) r const, to make them a st. line
sgc = mat2cell(sg,ones(1,size(sg,1)),size(sg,2)); %// converting to cell array
sic = mat2cell(si,ones(1,size(si,1)),size(si,2)); %// converting to cell array
%// distMat gives n*n matrix of all the dist between each fixed point with every other point.
distMat = cellfun(#(x,y) pdist2(x,y),repmat(sic,1,size(sgc,1)),repmat(sgc',size(sic,1),1));
figure; axis('image');
plot(si(:,1),si(:,2),'r.');
text(si(:,1),si(:,2),[repmat(' ',size(si,1),1), num2str((1:size(si,1))')]);
hold on
plot(sg(:,1),sg(:,2),'b.');
text(sg(:,1),sg(:,2),[repmat(' ',size(sg,1),1), num2str((1:size(sg,1))')]);
hold off
[mdist, index] = min(distMat(:));
[randomP, fixedP] = ind2sub(size(distMat),index)
Plot:
output:
randomP =
2
fixedP =
2
>> mdist
mdist =
6.7082
Not too sure what you are asking for but I think you want to find the two closest points.
This is how you could do it.
%// Generate some points
n = 3; xm = 1:n; ym =1:n;
m = [xm' ym']; %// This is the line
xd = [ 2 8 3];
yd = [ 1 4 3];
d = [xd' yd']; %// These are the random points
drep = repmat(d,n,1); %// This will repeat the matrix d n times
B= ones(n,1);
mrep = kron(m,B); %// This will repeat each value in m n times
distances = bsxfun(#minus,mrep,drep); %// The distance from each point to every other point
C_squared = sum(distances.^2,2)
[min_dist,idx] = min(sum(distances.^2,2)) %// Find the minimum distance
value_in_m = mrep(idx,:)
ans =
3 3
value_in_d = drep(idx,:)
ans =
3 3
Explanation
% Generate some points
n = 3;
xm = 1:n;
ym =1:n;
m = [xm' ym']; %// This is the line. Each row is a point
xd = [ 2 8 3];
yd = [ 1 4 3];
d = [xd' yd']; %// These are the random points
We want to calculate the distance from one point to every
other point so we repeat the points nxn times
Below is just one way of getting repeated elements.
More suggestions are here: https://stackoverflow.com/a/16269185
drep = repmat(d,n,1); %// This will repeat the matrix d n times
B= ones(n,1);
mrep = kron(m,B); %// This will repeat each value in m n times
We are basing this on Pythagoras theorem so (m_x-d_x)^2 + (m_y-d_y)^2 = C^2
distances = bsxfun(#minus,mrep,drep); %// The distance from each point to every other point
C_squared = sum(distances.^2,2)
Find the minimum distance
[min_dist,idx] = min(sum(distances.^2,2));
Find the points with the minimum distance
value_in_m = mrep(idx,:)
ans =
3 3
value_in_d = drep(idx,:)
ans =
3 3
I would like to produce a piecewise constant surface which is zero outside of some rectangle. More specifically, for t = (x,y) in R^2, I want
f(t) = 1 when 5<y<10 and 0<x<1;
-1 when 0<y<5 and 0<x<1;
1 when -5<y<0 and 0<x<1;
0 elsewhere
But, the surface I get doesn't look like what I want. I'm somewhat of a Matlab novice, so I suspect the problem is in the logical operators. My code is:
x = -2:.01:2; y = -15:15
[X,Y] = meshgrid(x,y); %Make domain
for i = 1:numel(X) %Piecewise function
for j = 1:numel(Y)
if Y(j) >= 0 && Y(j)<= 5 && X(i)>=0 && X(i)<=1
h2(i,j)= -1;
elseif Y(j)>5 && Y(j) <= 10 &&X(i)>=0 &&X(i)<=1
h2(i,j) = 1;
elseif Y(j)<0 && Y(j)>=-5 &&X(i)>=0 &&X(i)<=1
h2(i,j) = 1;
elseif X(i) <0 || X(i)>1 || Y(j)<-5 || Y(j)>10
h2(i,j) = 0;
end
end
end
%Normalize
C = trapz(abs(h2));
c = trapz(C);
h2 = c^(-1)*h2;
Thank you for your help and please let me know if you'd like me to specify more clearly what function I want.
You can very easily achieve what you want vectorized using a combination of logical operators. Avoid using for loops for something like this. Define your meshgrid like you did before, but allocate a matrix of zeroes, then only set the values within the meshgrid that satisfy the requirements you want to be the output values of f(t). In other words, do this:
%// Your code
x = -2:0.1:2; y = -15:15;
[X,Y] = meshgrid(x,y); %Make domain
%// New code
Z = zeros(size(X));
Z(Y > 5 & Y < 10 & X > 0 & X < 1) = 1;
Z(Y > 0 & Y < 5 & X > 0 & X < 1) = -1;
Z(Y > -5 & Y < 0 & X > 0 & X < 1) = 1;
mesh(X,Y,Z);
view(-60,20); %// Adjust for better angle
The above code allocates a matrix of zeroes, then starts to go through each part of your piecewise definition and searches for those x and y values that satisfy the particular range of interest. It then sets the output of Z to be whatever the output of f(t) is given those constraints. Take note that the otherwise condition is already handled by setting the whole matrix to be zero first. I then use mesh to visualize the surface, then adjust the azimuthal and elevation angle of the plot for a better view. Specifically, I set these to -60 degrees and 20 degrees respectively. Also take note that I decreased the resolution of the x values to have a step size of 0.1 instead of 0.01 for a lesser amount of granularity. This is solely so that you can see the mesh better.
This is the graph I get:
You can just use logical indexing:
x = -2:.01:2; y = -15:15;
[X,Y] = meshgrid(x,y); %// Make domain
h2=zeros(size(X));
h2(5<Y & Y<10 & 0<X & X<1)=1;
h2(0<Y & Y<5 & 0<X & X<1)=-1;
h2(-5<Y & Y<0 & 0<X & X<1)=1;
This statement: 5<Y & Y<10 & 0<X & X<1 returns a matrix of 1's and 0's where a 1 means that all 4 inequalities are satisfied, and a 0 means at least one is not. Where that matrix has a one, h2 will be modified to the value you want.
In MATLAB:
n = histc(x,edges);
is defined to behave as follows:
n(k) counts the value x(i) if edges(k)
<= x(i) < edges(k+1). The last bin
counts any values of x that match
edges(end).
Is there any way to flip the end behavior such that n(1) counts any values of x that match edges(1), and n(end) counts the values x(i) that satisfy edges(end-1) <= x(i) < edges(end)?
Consider the following code:
n = histc(x, [edges(1) edges]);
n(1) = sum(x==edges(1));
n(end) = [];
According to the question posted, the above will return:
n(1): counts any values of x that match edges(1)
n(k) [k~=1]: counts the value x(i) if edges(k-1) <= x(i) < edges(k)
This different from gnovice solution in that his answer uses the bounds: edges(k-1) < x(i) <= edges(k) (note the position of the equality sign).
To demonstrate, consider this simple example:
x = [0 1 1.5 2 2.5 4 6.5 8 10];
edges = 0:2:10;
>> n = fliplr(histc(-x,-fliplr(edges)))
n =
1 3 2 0 2 1
corresponding to the intervals:
0 (0,2] (2,4] (4,6] (6,8] (8,10]
Against:
>> n = histc(x, [edges(1) edges]);
>> n(1) = sum(x==edges(1));
>> n(end) = []
n =
1 3 2 1 1 1
corresponding to the intervals:
0 [0,2) [2,4) [4,6) [6,8) [8,10)
Since the edges argument has to have monotonically nondecreasing values, one way to flip the edge behavior is to negate and flip the edges argument and negate the values for binning. If you then flip the bin count output from HISTC, you should see the typical edge behavior of HISTC reversed:
n = fliplr(histc(-x,-fliplr(edges)));
The above uses FLIPLR, so x and edges should be row vectors (i.e. 1-by-N). This code will bin data according to the following criteria:
The first bin n(1) counts any values of x that match edges(1).
The other bins n(k) count the values x(i) such that edges(k-1) < x(i) <= edges(k).
Note that this flips the edge behavior of all the bins, not just the first and last bins! The typical behavior of HISTC for bin n(k) uses the equation edges(k) <= x(i) < edges(k+1) (Note the difference between the indices and which side has the equals sign!).
EDIT: After some discussion...
If you instead wanted to bin data according to the following criteria:
The first bin n(1) counts any values of x that match edges(1).
The second bin n(2) counts the values x(i) such that edges(1) < x(i) < edges(2).
The other bins n(k) count the values x(i) such that edges(k-1) <= x(i) < edges(k).
Then the following should accomplish this:
n = histc(x,[edges(1) edges(1)+eps(edges(1)) edges(2:end)]);
n(end) = [];
The first bin should capture only values equal to edges(1), while the lower edge of the second bin should start at an incremental value above edges(1) (found using the EPS function). The last bin, which counts the number of values equal to edges(end), is thrown out.