Hello it`s my first post here. I want to write matlab script for Delaunay triangulation. Here is my script:
clear all;clc
%% Delaunay
x=[ 160.1671 366.9226 430.7894 540.1208 660.2771 508.7287 252.1787];
y=[ 223.9615 259.5000 120.5769 245.5000 283.1923 472.7308 469.5000];
%
x=x';
y=y';
%orginal plot
dd=delaunay(x,y);
dt=TriRep(dd,x,y);
triplot(dt);
z=[x.^2+y.^2]
i=1:length(x);
ptk=[i' x y]
%% main loop
l=0;
for i=1:length(x)-2
for j=1+i:length(x)
for k=1+i:length(x)
if (j ~= k)
l=l+1;
xn = (y(j)-y(i))*(z(k)-z(i)) - (y(k)-y(i))*(z(j)-z(i));
yn = (x(k)-x(i))*(z(j)-z(i)) - (x(j)-x(i))*(z(k)-z(i));
zn = (x(j)-x(i))*(y(k)-y(i)) - (x(k)-x(i))*(y(j)-y(i));
if (zn < 0)
border=zn;
for m=1:length(x)
border = (border) & ...
((x(m)-x(i))*xn +...
(y(m)-y(i))*yn +...
(z(m)-z(i))*zn <= 0);
if (border)
ii(m)=[i];
jj(m)=[j];
kk(m)=[k];
end
end
end
end
end
end
end
wart=[ii' jj' kk']
dd
figure(2)
triplot(wart,x,y)
This is what I should get from this script. This matrix is generated as delaunay() matlab function:
dd =
6 7 2
7 1 2
4 6 2
1 3 2
4 3 5
6 4 5
2 3 4
This is what I get from implementation :
wart =
4 7 6
4 7 5
4 7 5
4 7 5
4 7 5
4 6 5
4 6 5
Could anyone of you tell me what is wrong with this ? Where is a mistake or simply guide me?
jils.
The issue is in your innermost loop, here:
if (zn < 0)
border=zn;
for m=1:length(x)
border = (border) & ...
((x(m)-x(i))*xn +...
(y(m)-y(i))*yn +...
(z(m)-z(i))*zn <= 0);
if (border)
ii(m)=[i];
jj(m)=[j];
kk(m)=[k];
end
end
end
You want to check if the triangle defined by points [i,j,k] is valid. Only if it is so for all m (no points inside the circumcircle) do you want to save those three points into your output. Currently, if the first point you check is outside the circumcircle, those three points get saved no matter what. In addition, since you loop over the same m for each possible triangle, even if you find the correct values you're likely overwriting them later on. This is also why you get repeats of the same values in your output.
In these cases it is always worth stepping through (mentally, manually on the command line, or using debug methods) your loops to see what happens. Your first output 4 7 6 doesn't appear in the inbuilt function results. So set your i,j,k to those values and see what happens in that inner loop.
Incidentally, you don't actually need a loop there. Check all values at once by doing something like:
border = (x-x(i)).*xn + (y-y(i)).*yn + (z-z(i)).*zn;
if all(border<0)
% then store coordinates
end
You can start with an empty output ([]) and append (using end+1), or calculate the max number of triangles and preallocate your output to that size, use a counter variable to keep track of how many you find and put them in the right place in the output array, and then trim the output to size right at the end. If you're planning to have larger input data sets, it would be better to preallocate.
Related
I have a file that contain the data logged of 6 experiments with this information logged "time ax ay az gx gy gz"
I will call it logmpu6050 in my specific case a 26,220X7 matrix.
I can recognize every experiment because time restart from a lower random value from the previous.
So when this condition is satisfied ti>ti+1 the data of the following experiment starts from the i+1 row.
I defined a "boundary vector" "ind" that contains all this value, and i added the first (1,1) and the last value(end,1) of the first column of the logmpu6050 matrix because are two exeption that don't satisfy the condition.
But when i want to know for example, this information:
query1=logmpu6050(ind(1),:)
Matlab gave me the values of the second row of ind, not the first, as you can see in the pic attached. Why?
I also tought it could start counting from 0, but is false, Matlab dispalys an error message with the 0 value.
Thanks, always, for your time, my civil engineer background makes hard to solve this kind of problems.
Here the code i wrote.
%Open the file
filename= uigetfile ('.txt');
fileID = fopen (filename);
logmpu6050 =csvread(filename);
fclose (fileID);
n=length(logmpu6050);
%Count every time i>i+1 and store the entire raw value
ind=find(diff(logmpu6050(:,1))<0);
ind=[logmpu6050(1,1);ind(:,:);logmpu6050(end,1)];
%No errors appear - logmpu6050 is a 26220X7 double - ind is a 7x1
ind
query1=logmpu6050(ind(1),:)
query2=logmpu6050(ind(2),:)
An alternative method could split the matrix into a cell array of submatrices:
% Generate an example
N = 3; % Num of experiments
n = randi([2,5],N,1); % Points per experiment
logmpu6050 = cell2mat(arrayfun(#(x) [(1:n(x))' x*ones(n(x),6)],1:N,'UniformOutput',0)');
% Find cut points
cuts = [diff(logmpu6050(:,1))<0;1];
% Split into a cell array
experiments = mat2cell(logmpu6050,diff([0;find(cuts)]));
Then you can access the submatrices like:
% The first experiment
experiments{1}
% The second experiment
experiments{2}
I think a lookup function would work nicely to pull out the submatrices you want.
Here's an example
% Generate an example data matrix
n = 3; % Points per experiment
N = 3; % Num of experiments
logmpu6050 = [repmat((1:n),1,N); repmat((1:n*N),6,1)]';
% Make a lookup function
lookup = #(x) cumsum([1;diff(logmpu6050(:,1))<0])==x;
% Get experiment 1 data
logmpu6050(lookup(1),:)
% Get experiment 2 data
logmpu6050(lookup(2),:)
This will output for the first experiment:
ans =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
and for the second:
ans =
1 4 4 4 4 4 4
2 5 5 5 5 5 5
3 6 6 6 6 6 6
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
Okay, this is a bit tricky to explain, but I have a long .txt file with data (only one column). It could look like this:
data=[18
32
50
3
19
31
48
2
18
33
51
4]
Now, every fourth value (e.g. 18, 19, 18) represents the same physical quantity, just from different measurements. Now, I want Matlab to take every fourth value and put it into an array X=[18 19 18], and like wise for the other quantities.
My solution so far looks like this:
for i=1:3;
for j=1:4:12;
X(i)=data(j);
end
end
... in this example, because there are three of each quantity (therefore i=1:3), and there are 12 datapoints in total (therefore j=1:4:12, in steps of 4). data is simply the loaded list of datapoints (this works fine, I can test it in command window - e.g. data(2)=32).
My problem, doing this, is, that my array turns out like X=[18 18 18] - i.e. only the last iteration is put into the array
Of course, in the end, I would like to do it for all points; saving the 2nd, 6th, and 10th datapoint into Y and so on. But this is simply having more for-loops I guess.
I hope this question makes sense. I guess it is an easy problem to solve.
Why don't you just do?
>> X = data(1:4:end)
X =
18
19
18
>> Y = data(2:4:end)
Y =
32
31
33
You can reshape the data and then either split it up into different variables or just know that each column is a different variable (I'm now assuming each measurement occurs the same number of times i.e. length(data) is a multiple of 4)
data = reshape(data, 4, []).';
So now if you want
X = data(:,1);
Y = data(:,2);
%// etc...
But also you could just leave it as data all in one variable since calling data(:,1) is hardly more hassle than X.
Now, you should NOT use for-loops for this, but I'm gong to address what's wrong with your loops and how to solve this using loops purely as an explanation of the logic. You have a nested loop:
for i=1:3;
for j=1:4:12;
X(i)=data(j);
end
end
Now what you were hoping was that i and j would each move one iteration forward together. So when i==1 then j==1, when i==2 then j==5 etc but this is not what happens at all. To best understand what's going on I suggest you print out the variables at each iteration:
disp(sprintf('i: \tj:'));
for i=1:3;
for j=1:4:12;
disp(sprintf(' %d\t %d',i,j));
end
end
This prints out
i: j:
1 1
1 5
1 9
2 1
2 5
2 9
3 1
3 5
3 9
What you wanted was
disp(sprintf('i: \tj:'));
for i=1:3;
disp(sprintf(' %d\t %d',i,4*i-3));
end
which outputs:
i: j:
1 1
2 5
3 9
applied to your problem:
%// preallocation!
X = zeros(size(data,1)/4, 1)
for i=1:3
X(i)=data(i*4 - 3);
end
Or alternatively you can keep a separate count of either i or j:
%// preallocation!
X = zeros(size(data,1)/4, 1)
i = 1;
for j=1:4:end;
X(i)=data(j);
i = i+1;
end
Just for completeness your own solution should have read
i = 0;
for j=1:4:12;
i = i+1;
X(i)=data(j);
end
Of course am304's answer is a better way of doing it.
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.
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