Rotation matrix is not orthogonal - matlab

I have rotation matrix which is not orthogonal. Whats wrong. I can't get it.
Exterior=[-6.6861,12.6118,-8.0660,[-0.4467,-0.3168,0.2380]*pi/180];%# deg 2 rad
%#data
ax=Exterior(4);
by=Exterior(5);
cz=Exterior(6);
%#Rotation in X
Rx = [1 0 0
0 cos(ax) -sin(ax)
0 sin(ax) cos(ax)];
%#Rotation in Y
Ry = [cos(by) 0 sin(by)
0 1 0
-sin(by) 0 cos(by)];
%#Rotation in Z
Rz = [cos(cz) -sin(cz) 0
sin(cz) cos(cz) 0
0 0 1];
R=Rx*Ry*Rz;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
R =
0.99998 -0.0041538 -0.0055292
0.0041969 0.99996 0.0077962
0.0054966 -0.0078192 0.99995
Orthogonality check
Inv(R)-R'=
2.2204e-016 2.6021e-018 8.6736e-019
0 1.1102e-016 -1.7347e-018
-2.6021e-018 3.4694e-018 2.2204e-016
R*R'=
2.2204e-016 2.6021e-018 8.6736e-019
0 1.1102e-016 -1.7347e-018
-2.6021e-018 3.4694e-018 2.2204e-016
Why there is different signs.???????
Any mistake??

Looks like the numbers in your orthogonality check are just due to rounding errors... They're really quite tiny.
There is an error in the question, pointed out by #ChisA. The OP pasted the same matrix for inv(R)-R' and R*R'
If we reconstruct the input file:
Exterior = [-6.681,12.6118,-8.0660,[-0.4467,-03168,0.2380]*pi/180]
ax = Exterior(4)
by = Exterior(5)
cz = Exterior(6)
Rx = [1 0 0 ; 0 cos(ax) -sin(ax) ; 0 sin(ax) cos(ax)]
Ry = [cos(by) 0 sin(by) ; 0 1 0 ; -sin(by) 0 cos(by)]
Rz = [cos(cz) -sin(cz) 0 ; sin(cz) cos(cz) 0 ; 0 0 1]
R = Rx*Ry*Rz
inv(R)-R'
R*R'
And run in through Octave (I don't have MATLAB):
Exterior =
-6.6810e+00 1.2612e+01 -8.0660e+00 -7.7964e-03 -5.5292e+01 4.1539e-03
ax = -0.0077964
by = -55.292
cz = 0.0041539
Rx =
1.00000 0.00000 0.00000
0.00000 0.99997 0.00780
0.00000 -0.00780 0.99997
Ry =
0.30902 0.00000 0.95106
0.00000 1.00000 0.00000
-0.95106 0.00000 0.30902
Rz =
0.99999 -0.00415 0.00000
0.00415 0.99999 0.00000
0.00000 0.00000 1.00000
R =
0.3090143 -0.0012836 0.9510565
-0.0032609 0.9999918 0.0024092
-0.9510518 -0.0038458 0.3090076
ans =
-5.5511e-17 1.3010e-18 1.1102e-16
2.1684e-19 0.0000e+00 -4.3368e-19
-1.1102e-16 -4.3368e-19 -5.5511e-17
ans =
1.0000e+00 -1.9651e-19 -4.6621e-18
-1.9651e-19 1.0000e+00 8.4296e-19
-4.6621e-18 8.4296e-19 1.0000e+00
Notice the R*R' is very close to I and inv(R)-R' is very close to 0.
Notice also that I get different small values than the OP. Because I am using a different piece of software the rounding errors will be different. So you should never rely on an exact comparison between two floating point numbers. You always should include some tolerance.
I hope this makes things a little clearer. See the comment by #gnovice below for links to more detailed information about rounding errors.

I don't understand why R*R' should be nearly zero. It should be the 3x3 identity matrix.
You might have a copy and paste error on your original question.

Related

How to generate 10 (3x3) matrices from (30x3) matrices and use it for rotation matrix

I have 10 data for b which I am reading from an excel file. I am trying to get 10 (3x3) rotation matrices by substituting in the matrix [1 0 0; 0 cos(a) -sin(a); 0 sin(a) cos(a)]. However, my code generates (30x3) matrices. Can I generate 10 3x3 matrices directly or is there a way to join the three consecutive rows together to make 10 3x3 matrices from (30x3) matrices?
syms a b
b = xlsread('C:\Desktop\Data.xlsx');
r = subs([1 0 0 0 cos(a) -sin(a) 0 sin(a) cos(a)], b)
rx = vec2mat(r,3)
Further developing the answer to get the final rotational matrix, the above structure is repeated thrice as shown below
syms a b c d rx ry rz rm
b = xlsread('C:\Desktop\Data.xlsx','A1:A10');
c = xlsread('C:\Desktop\Data.xlsx','B1:B10');
d = xlsread('C:\Desktop\Data.xlsx','C1:C10');
rx = reshape(vec2mat(subs([1 0 0 0 cosd(a) -sind(a) 0 sind(a) cosd(a)], b), 3).',3,3,numel(b));
ry = reshape(vec2mat(subs([cosd(a) 0 sind(a) 0 1 0 -sind(a) 0 cosd(a)], c), 3).',3,3,numel(b));
rz = reshape(vec2mat(subs([cosd(a) -sind(a) 0 sind(a) cosd(a) 0 0 0 1], d), 3).',3,3,numel(b));
rm = rx.*ry.*rz;
The answers given by the algorithm is right as follows for the angles (34, 0, 100) angles in degrees
[-cos((4*pi)/9), 0 , 0]
[0, -cos((4*pi)/9*cos((17*pi)/90), 0]
[0, 0, cos((17*pi)/90)]
instead of
rm =
0.8623 0 0
0 -0.7317 0
0 0 -0.8486
I am looking for a single matrix solution with decimal values (Not in terms of pi).
After your edit, I'm even more wondering, why you need symbolic variables and functions in the first place, if your desired result should be plain numerical.
So, avoiding symbolics: For each of your (single) rotation matrices as well as the combined rotation matrix, set up an anonymous function. Then, you can use arrayfun to generate the combined rotation matrix for each parameter set.
Here's some code:
% Parameters (from file, ...)
b = [34, 20, 30];
c = [0, 21, 31];
d = [100, 22, 32];
% Anonymous functions: (Single) rotation matrices
rot_x = #(alpha) [1 0 0; 0 cos(alpha) -sin(alpha); 0 sin(alpha) cos(alpha)];
rot_y = #(beta) [cos(beta) 0 sin(beta); 0 1 0; -sin(beta) 0 cos(beta)];
rot_z = #(gamma) [cos(gamma) -sin(gamma) 0; sin(gamma) cos(gamma) 0; 0 0 1];
% Anonymous function: Combined rotation matrix
rot_m = #(alpha, beta, gamma) rot_x(alpha) .* rot_y(beta) .* rot_z(gamma);
% Calculate combined rotation matrix for all parameter sets
rot_mats = arrayfun(rot_m, b, c, d, 'UniformOutput', false)
We get the following output:
rot_mats =
{
[1,1] =
0.86232 0.00000 0.00000
-0.00000 -0.73174 -0.00000
-0.00000 0.00000 -0.84857
[1,2] =
0.54771 0.00000 0.00000
-0.00000 -0.40807 -0.00000
-0.00000 0.00000 -0.22352
[1,3] =
0.76310 -0.00000 -0.00000
0.00000 0.12868 0.00000
0.00000 -0.00000 0.14110
}
As you can see, the first one is exactly your example – but, please pay attention: In your edit, you used sind and cosd, whereas the data from your example indicate, you were using sin and cos here!
Hope that helps!
Disclaimer: Tested with Octave 5.1.0, but also works with MATLAB Online.

Remove zeros from a matrix

I have a matrix with large rows and columns as follows:
A = 0 0 0 0
0 0 0 0
0 0 0 0
2000 11 16 -0.74
0 0 0 0
0 0 0 0
2000 12 26 -0.84
0 0 0 0
0 0 0 0
I need to remove all the zeros from the matrix to get output like,
B = 2000 11 16 -0.74
2000 12 26 -0.84
I have tried an available solution over here like,
B = A(A~=0)
It removes zeros but gives output like,
2000
2000
11
12
-0.74
-0.84
How to get the desired output?
assuming A is a two dimensional matrix
A(any(A,2),:)
will do.
Example:
>> A=[rand(2,3); zeros(3); rand(1,3)]
A =
0.13878 0.44315 0.25832
0.01879 0.93844 0.57537
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000
0.50581 0.37870 0.56563
>> A(any(A,2),:)
ans =
0.138776 0.443152 0.258325
0.018794 0.938439 0.575371
0.505809 0.378696 0.565632

Changing diagonal values if equal to 1

I want to change the diagonal values if equal to 1.
is it possible to look for diagonals and change the values in this particular diagonal to another value.
For example:
X =
1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1
I want to change this diagonal :
1
0
1
to
2.2
0
2.2
I tried:
XX(logical(eye(size(XX)))) = 2
but this will change all the values not only ones.
Could you please explain how to do that for other diagonals?
The function diag is useful to manipulate diagonals. It only extracts a diagonal from a matrix, or forms a new matrix given a vector of diagonal elements. But with appropriate arithmetic this is sufficient:
X = [1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1];
k = 2; % which diagonal to change
d = diag(X,k); % the old diagonal
n = d;
n(n==1) = 2.2; % the new diagonal values
X = X - diag(d,k) + diag(n,k); % subtract old values from diagonal, add new ones
Output:
X =
1.00000 1.00000 2.20000 0.00000
1.00000 1.00000 0.00000 2.20000
1.00000 0.00000 1.00000 1.00000
0.00000 1.00000 1.00000 1.00000
Here comes a solution only using linear indexing. I wanted to avoid generating additional matrices. Nothing's wrong with Cris Luengo's answer, that was just for fun.
% Input.
X = [1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1]
% Which diagonal to change.
k = 2;
% Determine dimension.
dim = size(X, 1);
% Calculate indices of diagonal elements.
idx = (max(abs(k), k * dim) + 1):(dim + 1):numel(X);
idx = idx(1:end+min(k+1, 0));
% Replace diagonal elements with new value.
X(idx(X(idx) == 1)) = 2.2
Output:
X =
1.00000 1.00000 2.20000 0.00000
1.00000 1.00000 0.00000 2.20000
1.00000 0.00000 1.00000 1.00000
0.00000 1.00000 1.00000 1.00000

Matlab: Finding distance to nearest TRUE value in a matrix

Lets assume I have a logical matrix A (about 1000x1000 size) and want to find for each element the euclidean distance to the nearest TRUE value. How can that be done fast in Matlab?
E.g if i have matrix A:
A = [1 0 0 0
0 1 1 1
0 0 0 0
0 0 1 0]
Then what i want is:
B = [0 1 1 1
1 0 0 0
1.41 1 1 1
2 1 0 1]
One possibility would be imdilate(), but then i would have to dilate a MxN Matrix with a 2Mx2N Matrix, which would take way too long.
I tried calculating the distances from each element to each element==1 using pdist2() and then taking the minimum but that turned out to use way too much memory.
Any suggestions? I would also settle for a solution that just approximates it.
The bwdist function in the Image Processing Toolbox does precisely this
A = [1 0 0 0
0 1 1 1
0 0 0 0
0 0 1 0];
B = bwdist(A);
% 0.00000 1.00000 1.00000 1.00000
% 1.00000 0.00000 0.00000 0.00000
% 1.41421 1.00000 1.00000 1.00000
% 2.00000 1.00000 0.00000 1.00000

Curious behaviour with anonymous functions in Octave and MATLAB

Hi I am curious why I am getting the following behaviour with MATLAB and Octave
octave:7> pdf = #(x) (0<=x && x<1).* (x) + (1<=x && x <=2).* (2-x);
octave:8>
octave:8> t = 0:0.1:1;
octave:9>
octave:9> y = pdf(t)
y =
0 0 0 0 0 0 0 0 0 0 0
octave:10>
I get the same behavior with MATLAB i.e. y is a zero vector.
But if I add the following for loop
for i=1:size(t,1)
y(i) = pdf(t(i))
end
then I get the correct result.
Columns 1 through 19:
0.00000 0.10000 0.20000 0.30000 0.40000 0.50000 0.60000 0.70000 0.80000 0.90000 1.00000 0.90000 0.80000 0.70000 0.60000 0.50000 0.40000 0.30000 0.20000
Columns 20 and 21:
0.10000 0.00000
The && and || are the short circuit operators, meant for use with scalars. Replace with & or |. I get an error when executing the above (vectorized) code in Matlab (R2011B).
After replacing the && with & it seems to work as you expect.