How to calculate this kind of matrix :
A = [ 1 3 4
4 5 7
10 8 6]
X= [x1
x2
x3]
Y= A*X=0
we can change it into :
1x1+3x2+4x3=0
4x1+5x2+7x3=0
10x1+8x2+6x3=0
How to do elimination in Matlab to get the x1, x2 and x3??
I'm not 100% sure what you're asking.
I suppose you want a way to solve a SLE. There are few way to this, the one that I personally find more straightforward is
x=A\b
where in your case:
b=zeros(3,1)
Note that you don't need the vector you're calling X as MATLAB will automatically consider the values in A as coefficient of different variables
My guess is you created an example for this question, but didn't really check if it would produce the desired result. For Ax = 0 to have a non-zero solution, the determinant det(A) must be zero. As the determinant of your A matrix is 40, the only solution is x = [0; 0; 0].
Now, assuming you picked a better example, such as:
A = [1 2 3;2 4 6;1 1 1];
Now, det(A) = 0.
Using regular linsolve, you will still only get x = [0; 0; 0] as a solution. However, there are clearly (infinitely) many other non-trivial solutions. You can achieve one such solution using null like this:
x = null(A)
x =
0.4082
-0.8165
0.4082
A*x
ans =
1.0e-014 *
0.1110
0.2220
0.0944
Which is practically zero (inaccuracies are due to floating point precision).
You can also use Singular value decomposition, svd to get the same results:
[U S V] = svd(A);
x = V(:,end)
x =
0.4082
-0.8165
0.4082
A*x
ans =
1.0e-014 *
0.1110
0.2220
0.0944
Related
This question fairly easy doing it manually however, I am struggling to have this written in code.
There is a quartic polynomial:
P(x)=ax^4+bx^3+cx^2+dx+e
There is also a given matrix M:
5 0 -1 2 9
-2 -1 0 1 2
Which the first row gives P(x) and the second row gives the value of x.
Using the information in matrix M, find the coefficients:
a, b, c, d, e
I would know how to work this manually, subbing each column and solve simultaneously with the other columns to obtain a value for each coefficient or put it in a matrix.
I have an idea of what to do, but I don't know how to code it.
I do believe the last line would be linearsolve(M(,1),M(,2)) and thus be able to obtain each coefficient but I have no idea how to get to that line.
Welcome J Cheong
% Values of y and x (note: in your post you had 2 values at x = 1, I assumed that was an accident)
M = [5 0 -1 2 9 ; -2 -1 0 1 2];
% Separate for clarity
y = M(1,:);
x = M(2,:);
% Fit to highest order polynomial model
f = fit(x',y',['poly', num2str(length(y)-1)])
% Extract coefficients
coeff = coeffvalues(f);
% Plotting
X = linspace(min(x)-1, max(x) + 1, 1000) ;
plot(x,y,'.',X,f(X))
Edit
Sorry, I'm using Matlab. Looking at the Octave documentation. You should be able to get the coefficients using
p = polyfit(x,y,length(y)-1)';
Then to display the coefficients the way you specified try this
strcat(cellstr(char(96+(1:length(p))')), { ' = ' } , cellstr(num2str(p)))
y=[5 0 -1 2 9];
x=[-2 -1 0 1 2];
P=polyfit(x,y,2)
gives
P =
2.0000 1.0000 -1.0000
these are your coefficients for c,d,e the others are zero. You can check the result:
polyval(P, x)
ans =
5.0000e+00 2.2204e-16 -1.0000e+00 2.0000e+00 9.0000e+00
which gives you y
Btw, you can solve this very fast just inside your head without calculator because the function values for x=0 and x=+/-1 are very easy to calculate.
I'm currently trying to compute the camera matrix P given a set of world points (X) with its corresponding image points (x). However, when testing for the the result, P (3 x 4 camera matrix) multiplying by the world points does not give me the correct corresponding image points. However, only the first column of PX = x. The other column won't return the approximate image points.
Code:
X = [1 2 3; 4 5 6; 7 8 9; 1 1 1];
x = [3 2 1; 6 5 4; 1 1 1];
[mX, nX] = size(X);
[mx, nx] = size(x);
for i = 0:(nX-1)
XX{i+1} = transpose(X(1+i: 4+i));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(i+1:3+i));
end
%TODO - normalization
A = [];
%construct matrix
for i = 1:nX
A = [A; zeros(1,4) -1*(xx{i}(3)*transpose(XX{i})) xx{i}(2)*transpose(XX{i})];
A = [A; xx{i}(3)*transpose(XX{i}) zeros(1,4) -1*xx{i}(1)*transpose(XX{i})];
end
%using svd to solve for non zero solution
[u s v] = svd(A);
p = v(:, size(v,2));
p = reshape(p, 4,3)';
output for the first column, works good:
>> p*XX{1}
ans =
0.0461
0.0922
0.0154
>> ans/0.0154
ans =
2.9921
5.9841
0.9974
>> xx{1}
ans =
3
6
1
output for the second column, doesn't work:
>> p*XX{2}
ans =
0.5202
0.0867
0.1734
>> ans/0.1734
ans =
2.9999
0.5000
1.0000
>> xx{2}
ans =
6
1
2
By the way, I was told that I need to normalize the world points and image points before I compute the camera matrix. I have not done this step and have no idea how to. If this is causing the issue, please explain what can be done. Thank you in advance.
This is because you aren't indexing into the matrix properly. You are using linear indexing to access each column of the matrix. In that case, your for loop needs to access each column independently. Therefore, each iteration of your for loop must access groups of 4 elements for your 3D points and groups of 3 elements for your 2D points.
As such, you simply need to do this for your for loops:
for i = 0:(nX-1)
XX{i+1} = transpose(X(4*i + 1 : 4*(i + 1)));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(3*i + 1 : 3*(i + 1)));
end
After this, the code should work no problem. To verify, we can loop through each 3D point and determine its 2D equivalent as you're using cells:
out = zeros(size(xx)); % Declare output matrix
for ii = 1 : numel(XX) % For each 3D point...
out(:,ii) = p * XX{ii}; % Transform the point
out(:,ii) = out(:,ii) / out(end,ii); % Normalize
end
We thus get:
>> out
out =
3.0000 2.0000 1.0000
6.0000 5.0000 4.0000
1.0000 1.0000 1.0000
Compare with your x:
>> x
x =
3 2 1
6 5 4
1 1 1
Suggestion - Use vectorization
If I can suggest something, please do not use cell arrays here. You can create the matrix of equations for solving using vectorization. Specifically, you can create the matrix A directly without any for loops:
A = [zeros(N, 4) -X.' bsxfun(#times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(#times, -x(1,:).', X.')];
If you own MATLAB R2016b and up, you can do this with internal broadcasting:
A = [zeros(N, 4) -X.' x(2,:).' .* X.';
X.' zeros(N, 4) -x(1,:).' .* X.']
Note that you will see the rows are shuffled in comparison to your original matrix A because of the vectorization. Because we are solving for the null space of the matrix A, shuffling the rows has no effect. Therefore, your code can be simplified to:
X = [1 2 3; 4 5 6; 7 8 9; 1 1 1];
x = [3 2 1; 6 5 4; 1 1 1];
A = [zeros(N, 4) -X.' bsxfun(#times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(#times, -x(1,:).', X.')];
% Use this for MATLAB R2016b and up
% A = [zeros(N, 4) -X.' x(2,:).' .* X.';
% X.' zeros(N, 4) -x(1,:).' .* X.']
[u, s, v] = svd(A);
p = v(:, end);
p = reshape(p, 4, 3).';
To finally compute the output matrix, you can just use simple matrix multiplication. The fact that you are using cells requires that you have to use a for loop and it's much faster to do this with matrix multiplication:
out = p * X;
You can then take the last row of the results and divide each of the other rows by this row.
out = bsxfun(#rdivide, out, out(end,:));
Again with MATLAB R2016b and up, you can just do it as so:
out = out ./ out(end,:);
Lets assume we have some code. In Matlab editor:
x = zeros(1,10);
x(1,1) = 2;
for k = 1: 9
x(k+1) = 10 * x(k);
end
Is it possible to write the equation without the for loop?
Try this:
x = 2 * 10.^(0:9);
Hope that helps.
Check out the logspace function:
x=2*logspace(0,9,10)
You have an error because it is contrary to the rules of matrix multiplication.
My solution below, I used the free analogue of Matlab - Octave, which has a similar syntax:
X=randint(2) % Matrix of size 2 by 2
X =
1 0
0 0
Y=2 * 10.^X(:)
Y =
20
2
2
2
You have a right to multiply the matrix only this type:
M x N on N x P
The result is a matrix of the following dimensions:
M x P
See also:
Element-wise multiplication
Element-wise power
I hope this helped
I want to plot an equation using a for-loop. I have tried several different ways, but keep getting the apparently common error "Subscript indices must either be real positive integers or logicals". The equation I want to plot is y(x) = (x^4)-(4*x^3)-(6*x^2)+15.
The last code I tried was the following:
y(0) = 15;
for x = [-3 -2 -1 0 1 2 3 4 5 6];
y(x) = (x^4)-(4*x^3)-(6*x^2)+15;
end
plot(x,y)
To start from the beginning,
y(0) = 15;
will give you the following error:
Subscript indices must either be real positive integers or logicals.
This is because Matlab's indexing starts at 1. Other languages like C and Python start at 0.
Matlab can work directly with vectors. So in your code, there is no need for a loop at all.
You can do it like this:
x = [-3 -2 -1 0 1 2 3 4 5 6];
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
Note that we need to use element-wise operators like .* and .^ to calculate the values vectorized for every element. Therefore a point . is written in front of the operator.
Additionally, we can improve the code substantially by using the colon operator to generate x:
x = -3:6; % produces the same as [-3 -2 -1 0 1 2 3 4 5 6]
y = (x.^4) - (4*x.^3) - (6*x.^2) + 15;
plot(x, y);
If you want finer details for your graph, use linspace as suggested by #Yvon:
x = linspace(-3, 6, 100); % produces a vector with 100 points between -3 and 6.
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)
x = linspace(-3, 6, 100);
y = x.^4-4*x.^3-6*x.^2+15;
plot(x,y)
Is it possible to use the size (s) of the points to 'weight' the line of best fit?
x = [1 2 3 4 5];
y = [2 4 5 3 4];
s = [10 15 20 2 5];
scatter(x,y,s)
hold on
weight = s;
p = polyfit(x,y,1); %how do I take into account the size of the points?
f = polyval(p,x);
plot(x,f,'-r')
Using Marcin's suggestion, you can incorporate lscov into polyfit. As the documentation explains, polynomial fitting is done by computing the Vandermonde matrix V of x, and then executing p = V\y. This is the standard formalism of any least-squares solution, and lends itself to weighted-least-squares in MATLAB through lscov.
Taking your x, y and weight vectors, instead of calling polyfit(x,y,n) you can do the following:
% Construct Vandermonde matrix. This code is taken from polyfit.m
V(:,n+1) = ones(length(x),1,class(x));
for j = n:-1:1
V(:,j) = x.*V(:,j+1);
end
% Solve using weighted-least-squares
p = lscov(V,y,weight);
You can even go one step further, and modify polyfit.m itself to include this functionality, or add another function polyfitw.m if you are not inclined to modify original MATLAB functions. Note however that polyfit has some more optional outputs for structure, computed using QR decomposition as detailed in the documentation. Generalization of these outputs to the weighted case will require some more work.
x = (1:10)';
y = (3 * x + 5) + rand(length(x),1)*5;
w = ones(1,length(y));
A = [x ones(length(x),1)];
p = lscov(A,y,w);
plot(x,y,'.');
hold on
plot(x,p(1)*x + p(2),'-r');