**You are now following this question**

- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.

# Convert Quaternion to Euler angle extrinsically

78 views (last 30 days)

Show older comments

Hello,

I need to convert my results which are stored as quaternions into euler representation. The quat2eul and quat2angle functions seem the same and both will convert quaternions to euler angles. However, it is stated that they use intrinsic calculation (AKA rotation is done around Z axis, then Y' axis, then X'' axis). I need to convert extrinsically. I do not want each rotation to be based on the newly rotated axis. Is there any function in matlab to do this?

##### 1 Comment

James Tursa
on 25 Jan 2024

Please give an example of input and desired output. Maybe all you need to do is reorder.

### Accepted Answer

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

Intrinsic euler angles can be converted to extrinsic euler angles just be reversing their order.

EDIT: In other words, a Z-Y'-X'' intrinsic rotation by psi, theta, and phi is the same as an X-Y-Z extrinsic rotation by phi, theta, and psi.

##### 25 Comments

Paul
on 25 Jan 2024

Hi Matt,

Suppose I have three, intrinsic Euler angles applied in Z-Y-X order. Call these angles psi, theta, and phi.

Are you saying that the direction cosine matrix that corresponds to these angles can be constructed as if from extrinsic angles by reversing the order of the intrinsic angles and using their numerical values?

Paul
on 25 Jan 2024

Edited: Paul
on 25 Jan 2024

Let's try it.

Define the elemental, single-axis direction cosine matrices (DCMs).

Cx = @(x) angle2dcm(x,0,0,'XYZ');

Cy = @(y) angle2dcm(y,0,0,'YXZ');

Cz = @(z) angle2dcm(z,0,0,'ZYX');

Pick some angles and define the associated elemental DCMs

psi = pi/3; theta = pi/6; phi = pi/7;

Cpsi = Cz(psi);

Ctheta = Cy(theta);

Cphi = Cx(phi);

DCM assuming intrinsic angles.

Cintrinsic = Cphi*Ctheta*Cpsi

Cintrinsic = 3×3

0.4330 0.7500 -0.5000
-0.6718 0.6384 0.3758
0.6010 0.1732 0.7803

DCM assuming extrinsic angles, reverse the order, am I doing this correctly?

Cextrinsic = Cpsi*Ctheta*Cphi

Cextrinsic = 3×3

0.4330 0.8887 0.1505
-0.7500 0.2626 0.6071
0.5000 -0.3758 0.7803

They don't match.

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

I will demonstrate using the AxelRot function from this FEX download,

which let's you compute the DCM about an arbitrary 3D axis.

Let's first choose some arbitrary angles in degrees,

psi =30; theta = 50; phi = 70;

Extrinsic Computation

For an extrinsic X-Y-Z rotation we compute 1-step DCMs as follows,

[Rx,~]=AxelRot(phi,[1;0;0]);

[Ry,~]=AxelRot(theta,[0;1;0]);

[Rz,~]=AxelRot(psi,[0;0;1]);

and compose the total extrinsic rotation as,

Rextrinsic=Rz*Ry*Rx

Rextrinsic = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

Intrinisc Computation

For an intrinsic Z-Y'-X'' rotation, we first compute the rotation about Z by psi,

[Rz,~]=AxelRot(psi,[0,0,1]);

Now, we compute the rotation by theta about Y'. The Y' axis, however, is a rotation by Rz of the fixed y-axis. It corresponds to the second column of Rz. Therefore, the 1-step DCM is,

[Ryp,~]=AxelRot(theta, Rz(:,2));

Similarly, the final rotation requires that we know the X'' axis. The X'' axis is the transformation of the original x-axis over the course of the first two rotation steps, and therefore,

[Rxpp,~]=AxelRot(phi, Ryp*Rz*[1;0;0]);

The total intrinsic rotation can now be computed as,

Rintrinsic=Rxpp*Ryp*Rz

Rintrinsic = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

As you can see, the intrinsic and extrinsic DCM computations match quite well,

Rextrinsic-Rintrinsic

ans = 3×3

1.0e-15 *
-0.1110 -0.1110 -0.1110
-0.0555 -0.1110 0.1110
0.1110 -0.1110 0.0833

Frank Martin
on 25 Jan 2024

Aren't extrinsic rotations alwasy the same regardless of the order performed?

So should I be using quat2eul('XYZ')?

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

Aren't extrinsic rotations alwasy the same regardless of the order performed?

No, both extrinsic and intrinsic rotation angles depend on the choice and order of the 1-step rotation axes.

So should I be using quat2eul('XYZ')?

Impossible to answer because you haven't said what euler angle representation you are looking for, other than that it be extrinsic. In general, however, any time you use quat2eul(), there will always be two possible ways to interpret the result.

In the case of eul=quat2eul(__,'XYZ'), this can be interpreted as an extrinsic rotation by eul(3) about Z, then eul(2) about Y, then eul(1) about X.

It can also be interpreted as an intrinsic rotation by eul(1) about X, then eul(2) about Y', then eul(3) about Z''.

Paul
on 25 Jan 2024

Edited: Paul
on 25 Jan 2024

Matt,

I agree with your edit: "a Z-Y'-X'' intrinsic rotation by psi, theta, and phi is the same as an X-Y-Z extrinsic rotation by phi, theta, and psi."

At the risk of adding to the confusion, there's really two reversals happening.

1) For a given sequence of intrinsic angles, say Z-Y'-X'', the elemental DCMs are multiplied in reverse order as for a Z-Y-X sequence of extrinsic angles when forming the DCM.

2) Therefore, to get the same DCM, we also have to reverse the order of the rotations, e.g., to X-Y-Z for the extrinsic angles.

When I see a statement like "reverse the order of the angles," I feel like that's referring to how the the DCM is formed, i.e., item (1), but not accounting for the need to also reverse the sequence of rotations, i.e., item (2). Maybe I'm not reading that statement correctly.

When I read the OP's question it sounded to me like he wanted to convert from Z-Y'-X'' intrinsic to Z-Y-X extrinsic, though that wasn't stated explicitly.

Paul
on 25 Jan 2024

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

@Paul I've re-run with,

psi =30; theta = 50; phi = 70;

but you should see agreement between the intrinsic and extrinsic computation with any choice of angles. Are you saying you get disagreement when using the version of AxelRot from the File Exchange?

Paul
on 25 Jan 2024

Edited: Paul
on 25 Jan 2024

No, I didn't run with AxelRot.m from the file exchange. I wasn't sure if it would be appopriate to download it from there and then attach it to a comment here. I was trying to recreate what I thought AxelRot does, but was unsuccessful. Did you run that code in that comment here on Answers? If so, how did you do that without uploading AxelRot.m to that comment? Did you upload it, run, then delete the file attachment?

Is Rextrinsic a point rotation or a frame rotation?

If I want to use Rextrinsic to operate on a vector, would post-multiply Rextrinic by a column vector on the right (new = Rextrinsic*old(:)) or would I premultiply by a row vector on the left (new = old(:).' * Rextrinsic) ?

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

Did you upload it, run, then delete the file attachment?

Yes, I did. I don't like to have the availability of FEX files decentralized by attaching permanent copies to Matlab Answers posts.

If I had to guess, though, the discrepancy between your home-brewed implementation and AxelRot is that the discrete cosines in your DCMs are organized row-wise instead of column-wise.

Paul
on 25 Jan 2024

Then I'm glad I didn't attach it myself.

I think I got is sorted out. Would you mind answering my additional questions in this comment? We were probably typing at the same time ....

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

Is Rextrinsic a point rotation or a frame rotation?

I'm not familiar with that terminolgy. Is one the tranpose of the other?

If I want to use Rextrinsic to operate on a vector, would post-multiply Rextrinic by a column vector on the right (new = Rextrinsic*old(:)) or would I premultiply by a row vector on the left (new = old(:).' * Rextrinsic) ?

All rotation matrices in my example follow the convention that column vectors are points to be rotated by pre-multiplication with R, i.e. new=R*old.

Bruno Luong
on 25 Jan 2024

Edited: Bruno Luong
on 25 Jan 2024

Pick some angles and define the associated elemental DCMs

Cx = @(x) angle2dcm(x,0,0,'XYZ');

Cy = @(y) angle2dcm(y,0,0,'YXZ');

Cz = @(z) angle2dcm(z,0,0,'ZYX');

psi = pi/3; theta = pi/6; phi = pi/7;

Cpsi = Cz(psi);

Ctheta = Cy(theta);

Cphi = Cx(phi);

DCM assuming intrinsic angles.

Cintrinsic = Cphi*Ctheta*Cpsi

Cintrinsic = 3×3

0.4330 0.7500 -0.5000
-0.6718 0.6384 0.3758
0.6010 0.1732 0.7803

% Bruno add

eul2rotm(-[phi theta psi], "XYZ") % intrinsic

ans = 3×3

0.4330 0.7500 -0.5000
-0.6718 0.6384 0.3758
0.6010 0.1732 0.7803

DCM assuming extrinsic angles, reverse the order, am I doing this correctly?

Cextrinsic = Cpsi*Ctheta*Cphi

Cextrinsic = 3×3

0.4330 0.8887 0.1505
-0.7500 0.2626 0.6071
0.5000 -0.3758 0.7803

% Bruno add

eul2rotm(-[psi theta phi], "ZYX") % intrinsic

ans = 3×3

0.4330 0.8887 0.1505
-0.7500 0.2626 0.6071
0.5000 -0.3758 0.7803

They don't match.

The first you compute Cintrinsic is intrinsic 'XYZ'

The second you compute Cextrinsic is actually intrinsic 'ZYX'; so it is normal they don't match

The correct extrinsic 'zyx' is actually

Cextrinsic_correct = Cphi*Ctheta*Cpsi

Cextrinsic_correct = 3×3

0.4330 0.7500 -0.5000
-0.6718 0.6384 0.3758
0.6010 0.1732 0.7803

which is equal to intrinsic 'XYZ', Cintrinsic

Bruno Luong
on 25 Jan 2024

Edited: Bruno Luong
on 25 Jan 2024

"Is Rextrinsic a point rotation or a frame rotation?

I'm not familiar with that terminolgy. Is one the tranpose of the other?"

The terminogy seems to be in MATLAB quaternion function (PF argument). They are related in this way, if you reverse the sign of euler angle (inverse, transpose the rotation), you will get the conjugate quaternions to each other:

E = rand(1,3)*2*pi;

qF = quaternion(E, "euler","XYZ", "frame")

qF = quaternion

-0.51753 + 0.59469i + 0.30175j - 0.53614k

qP = quaternion(-E, "euler", "XYZ", "point")

qP = quaternion

-0.51753 - 0.59469i - 0.30175j + 0.53614k

norm(conj(qP)-qF)

ans = 1.9230e-16

I interpret it as if you consider the rotation is frame rotated by a rigid body (robot arm, airplane), the world coordinates of extrinsic objects in the new (intrinsic) frame, in which case the inverse of the rotation matrix is to be multiplied with the wod coordinates to get the intrinsic coordinates.

Paul
on 25 Jan 2024

I'm following up on this comment

"All rotation matrices in my example follow the convention that column vectors are points to be rotated by pre-multiplication with R, i.e. new=R*old."

I'm going to ask some basic questions to make sure I'm crystal clear on what you're doing.

Suppose I define Rx and Rz using AxelRot as follows:

[Rx,~] = AxelRot(phi, [1,0,0]);

[Rz,~] = AxelRot(psi, [0,0,1]);

Now, I have a point in space, call it P1. The coordinates of P1 in the World frame, or W-frame, are

p1 = [p1x; p1y; p1z];

I pre-multiply p1 by Rx and call the result p2

p2 = Rx*p1;

My understanding is that the point in space represented by p2, call it P2, is NOT the same point as P1, i.e., they are two distinct points in space (assuming phi ~= 0 of course), and that the elements of p2 are the coordinates of P2 resolved in the W-frame. Correct?

If so, my understanding is that P2 is obtained by rotating P1 around the x-axis of the W-frame. Correct?

If so, then suppose my next operation is

p3 = Rz*p2;

Again, the point in space represented by p3, call it P3, is NOT the same point as P2, and the elements of p3 are the coordinates of P3 resolved in the W-Frame. Correct?

If so, around which axis is P2 rotated to arrive at P3?

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

If so, around which axis is P2 rotated to arrive at P3?

Around the world z-axis. All operations,

[R,~]=AxelRot(theta,w)

give a rotation matrix such that R*v rotates v by theta degrees about the world w-axis.

It may be important, though, to keep in mind that all of these things have dual interpretation. Rotating v around the axis w by theta is the same thing as finding the coordinates of v in a coordinate frame rotated by -theta about w.

Paul
on 25 Jan 2024

Because you didn't say otherwise, I'll assume that you agree with all of my other assertions are correct, or, at least, valid interpretations.

" R*v rotates v by theta degrees about the world w-axis."

And R is a right handed rotation?

On this line

p3 = Rz*p2;

Is Rz acting as an intrinsic or extrinsic rotation?

Matt J
on 25 Jan 2024

Edited: Matt J
on 25 Jan 2024

Because you didn't say otherwise, I'll assume that you agree with all of my other assertions are correct, or, at least, valid interpretations.

Yes, they were all valid.

And R is a right handed rotation?

Yes, you should see that det(R)=+1 in all of AxelRot's output.

Is Rz acting as an intrinsic or extrinsic rotation?

I don't know how concepts of intrinsic vs. extrinsic would apply to a single elementary rotation about the z-axis. Intrinsic and extrinsic has to do with how a non-elementary rotation decomposes into a sequence of simpler rotations.

Paul
on 25 Jan 2024

The rotation of P1 to P3 is is decomposed into Rx and Rz

p3 = Rz*Rx*p1;

Is Rz acting as an intrinsic or extrinsic rotation?

Paul
on 26 Jan 2024

Edited: Paul
on 26 Jan 2024

The 2023b documentation has improved a little bit (still far from really good) that makes it (maybe?) possible to follow the breadcrumbs and figure out (which shouldn't be necessary if the doc is really well-written) what all these toolbox functions are doing.

Define three angles

psi = 30; theta = 50; phi = 70; euld = [psi theta phi];

Define a direction cosine matrix (DCM) using a ZYX sequence angle2dcm

rmat0 = angle2dcm(psi*pi/180,theta*pi/180,phi*pi/180,'ZYX')

rmat0 = 3×3

0.5567 0.3214 -0.7660
0.4524 0.6561 0.6040
0.6967 -0.6828 0.2198

According to angle2dcm, "The rotation angles represent a passive transformation from frame A to frame B. The resulting direction cosine matrix represents a series of right-hand intrinsic passive rotations from frame A to frame B." (emphasis added). I'm also pleased to note that the 2023b doc page is much improved over what I see in 2022a, which does not explicitly say that the rotations are intrinsic. Note that passive rotation is synonymous with frame rotation. Unfortunately, the doc page doesn't say if rmat0 should pre-multiply a Matlab column vector or post-multiply a Matlab row vector. We'll get that sorted out below.

Next, we follow the code in the Matlab tutorial "Rotations, Orientation, and Quaternions" in the section Other Rotation Representations. Important: "Note here, and throughout, the rotations around each axis are intrinsic"

"Build a quaternion from these Euler angles for the purpose of frame rotation" in a ZYX sequence.

qeuldframe = quaternion(euld, 'eulerd', 'ZYX', 'frame');

"This same rotation can be represented as a rotation matrix:" rotmat

rmat = rotmat(qeuldframe, 'frame')

rmat = 3×3

0.5567 0.3214 -0.7660
0.4524 0.6561 0.6040
0.6967 -0.6828 0.2198

rmat is the same as rmat0.

"To find the location of the point in the rotated reference frame, right-multiply rotmatFrame by the transposed array pt." pt is defined on that doc page as a row, so the frame rotation, rmat, is intended to pre-multiply a column, and therefore so is rmat0.

rmat2 = eul2rotm([psi theta phi]*pi/180,'ZYX')

rmat2 = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

rmat2 is the transpose of rmat0 and rmat. BUT, according to the doc page: "When using the rotation matrix, premultiply it with the coordinates to be rotated (as opposed to postmultiplying)." So if v is expressed in Matlab as a column vector then

v = [1;2;3];

(rmat*v).' == v.'*rmat2

ans = 1×3 logical array

0 0 0

From this, I conclude that rmat2 is also a frame rotation based on intrinsic angles in a ZYX sequence.

Finally, using the code I posted above:

Cx = @(x) angle2dcm(x,0,0,'XYZ');

Cy = @(y) angle2dcm(y,0,0,'YXZ');

Cz = @(z) angle2dcm(z,0,0,'ZYX');

Cpsi = Cz(psi*pi/180);

Ctheta = Cy(theta*pi/180);

Cphi = Cx(phi*pi/180);

Cintrinsic = Cphi*Ctheta*Cpsi

Cintrinsic = 3×3

0.5567 0.3214 -0.7660
0.4524 0.6561 0.6040
0.6967 -0.6828 0.2198

Cintrinsic matches rmat and rmat0, and the transpose of rmat2. As previously claimed in my upstream comment, Cintrinsic is formed from an intrinsic, ZYX sequence. It is a frame rotation intended to premultiply a column vector.

Given the coordinates of a vector resolved in starting frame, i.e., the parent frame, the frame rotation is used to define the coordinates of the same vector resolved in the rotated, or child frame.

v_resolved_in_child = Cintrinsic * v_resolved_in_parent

I'm certain that's what the doc page means when it says: ""To find the location of the point in the rotated reference frame ..."

Comment: because the rotations are intrinsic, it would be better to use the noation that @Matt J used and call them all Z-Y'-X'' to be clear that the second and third rotations are rotations from intermediate frames, but I've been using ZYX as that's the convention used for the input argument to all the the TMW functions used above.

As an aside, suppose I want to generate a frame rotation, but using extrinsic angles in a ZYX sequence. Here, the rotations are successively around the Z-, Y-, and X-axes all of the parent frame. Call the respective rotation angles alpha, beta, and gamma. With these angles, the frame rotation from the parent frame to the child frame is

Cextrinsic = Cz(gamma)*Cy(beta)*Cx(alpha)

If Cextrinsic is to equal Cintrinsic, i.e., represent the same frame rotation from parent to child, then it's clear that, in general, the triplet (gamma,beta,alpha) won't be numerically the same as (psi,theta,phi). This conclusion is exactly what I was attempting to illustrate by showing that

Cintrinsic ~= Cz(psi)*Cy(theta)*Cx(phi)

where the right hand side is what I misunderstood to be the meaning of "Intrinsic euler angles can be converted to extrinsic euler angles just by reversing their order." My misunderstanding of what @Matt J meant.

I don't think that extrinsic rotation angles are conceptually useful for frame rotations.

Anyway, moving on to a point rotation, which is also called an active rotation. Point Rotation shows how it differs from a frame rotation. A point rotation moves the point (or the tip of a vector) to a new location in the same coordinate frame. There is only one coordinate frame.

Given a quaternion, rotmat can compute the associated point rotation matrix. Starting with the quaternion derived previously

rotmatPoint = rotmat(qeuldframe,'point')

rotmatPoint = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

which is the transpose of the frame rotation matrix

rotmatPoint - rmat.'

ans = 3×3

0 0 0
0 0 0
0 0 0

which is consistent with the doc page statement: "The rotation matrix for point rotation is the transpose of the matrix for frame rotation."

The point rotation is applied by post-multiplying on the right, i.e.,

pt1 = rotmatPoint * (pt')

where pt1 is " the location of the rotated point (emphasis added)" as compared to multiplication by the frame rotation that finds the "location of the point in the rotated reference frame (emphasis added)"

Rotx = @(x) [1 0 0; 0 cosd(x) -sind(x); 0 sind(x) cosd(x)]; % [Rx,~] = AxelRot(x,[1 0 0])

Roty = @(y) [cosd(y) 0 sind(y); 0 1 0; -sind(y) 0 cosd(y)]; % [Ry,~] = AxelRot(y,[0 1 0])

Rotz = @(z) [cosd(z) -sind(z) 0; sind(z) cosd(z) 0; 0 0 1]; % [Rz,~] = AxelRot(z,[0 0 1])

Compute the elementary rotations for the three angles

Rx = Rotx(phi); %[Rx,~] = AxelRot(phi, ,[1;0;0]);

Ry = Roty(theta); %[Ry,~] = AxelRot(theta,[0;1;0]);

Rz = Rotz(psi); %[Rz,~] = AxelRot(psi ,[0;0;1]);

Compute the rotation matrix

Rextrinsic = Rz*Ry*Rx

Rextrinsic = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

We see the same result as rotmatPoint. As suggested by Matt's variable name and his statement above regarding interpretation of successive multiplication of AxelRot elementary rotations, the angles phi, theta, psi define extrinsic angles in an XYZ sequence to define a point rotation matrix that pre-multiples a column vector of coordinates of a point to compute coordinates of a new (i.e., rotated) point in the same coordinate frame.

I don't think that intrinsic rotation angles are conceptually useful for point rotations.

The last point (no pun intended) I'll make is that our point rotation matrix can be found by

rotmat(quaternion([phi theta psi], 'eulerd', 'XYZ', 'point'),'point')

ans = 3×3

0.5567 0.4524 0.6967
0.3214 0.6561 -0.6828
-0.7660 0.6040 0.2198

where I think that @Matt J and I agree that phi, theta, and psi are extrinsic rotations. If we are correct, that is in contrast to this comment. I wonder if that's the reason that quaternion doesn't say anything about whether or not the Euler angles on input are intrinsic or extrinsic. Maybe that distinction depends on the 'point' or 'frame' argument.

Bruno Luong
on 26 Jan 2024

Edited: Bruno Luong
on 26 Jan 2024

A 3 x 3 rotation matrix has three binary attributes/usage/interpretation.

- intrinsic/extrinsic when the matrix is decomposed as product of 3 rotation matrix about basis axis
- frame/point
- At usage level: left multiplication with 1 x 3 row vector, right multiplication of 3 x 1 column vector of 3d coordinates

You can flip two (even) of the above attributes, the matrix remains the same.

If you flip one or three (odd) of the above attribute(s) the matrix becomes its transpose/inverse, So the euler decomposition flip the order.

Therefore if you don't specify two of those attributes, telling the remaning attribute as such or such is confusing, since it is NOT enough to specify the whole situation.

It is entirely up to user to understand and adapt to his/her usage.

From my understading when Matt claims "extrinsic" in his convention, the assumption of the other two attributes are

- point rotation with
- right multication by vector of (word) coordinates.

However I can also see it as "intrinsic" of frame rotation for example. Nothing contradicts with the claim by @Brian Fanous in this thread

Paul
on 26 Jan 2024

In this line:

rotmat(quaternion([phi theta psi], 'eulerd', 'XYZ', 'point'),'point')

we've specified one of the attributes as a point rotation. The usage of rotmat in the doc page ""Rotations, Orientation, and Quaternions" all show (at least as I recall) the output of rotmat is intended for right-multiplication by a vector. Given those two attributes are specified, are the Euler angles in that line of code intrinsic or extrinsic?

Bruno Luong
on 26 Jan 2024

Edited: Bruno Luong
on 26 Jan 2024

q = quaternion([phi theta psi], 'eulerd', 'XYZ', 'point') returns quaternion for extrinsic point rotation (usage right multiplication by column vector of coordinates or q*v*conj(q))

phi = rand()*360;

theta = rand()*360;

psi = rand()*360;

q = quaternion([phi theta psi], 'eulerd', 'XYZ', 'point')

q = quaternion

-0.52669 + 0.56213i - 0.22555j - 0.59644k

% q = conj(quaternion(-[phi theta psi], 'eulerd', 'XYZ', 'frame'))

R = rotmat(q,'point')

R = 3×3

0.1868 -0.8819 -0.4330
0.3747 -0.3435 0.8612
-0.9081 -0.3231 0.2663

% Check euler decomposition of R

Rx = makehgtform('xrotate', deg2rad(phi));

Ry = makehgtform('yrotate', deg2rad(theta));

Rz = makehgtform('zrotate', deg2rad(psi));

R = Rz*Ry*Rx; R = R(1:3,1:3)

R = 3×3

0.1868 -0.8819 -0.4330
0.3747 -0.3435 0.8612
-0.9081 -0.3231 0.2663

% Verify point rotation using R and q

P = randn(3,1); % random point

RP1 = R*P

RP1 = 3×1

-0.2398
1.4719
-0.3082

v = quaternion(0,P(1),P(2),P(3));

tmp = q*v*conj(q);

[a,b,c,d] = parts(tmp);

RP2 = [b; c; d]

RP2 = 3×1

-0.2398
1.4719
-0.3082

### More Answers (2)

Bruno Luong
on 26 Jan 2024

Edited: Bruno Luong
on 26 Jan 2024

Here is the answer by MATLAB code: extrinsic angles is flip intrinsic angles

% Generate random unit quaternion

q = quaternion(randn, randn, randn, randn);

q = q ./ norm(q)

q = quaternion

-0.50199 - 0.41335i + 0.75491j + 0.085223k

Order = 'ZYX'

Order = 'ZYX'

Ei = quat2eul(q, Order) % Intrinsic Euler angle

Ei = 1×3

-1.7849 -0.7580 2.2956

% Extrinsic Euler angle, simply flip order then flip resulting angles

Ee = fliplr(quat2eul(q, fliplr(Order)))

Ee = 1×3

1.8498 -0.9762 2.6051

% The rotation matrix corresponds to q

R = rotmat(q, 'frame')

R = 3×3

-0.1543 -0.7096 0.6875
-0.5385 0.6438 0.5437
-0.8284 -0.2863 -0.4815

% Check intrinsic frame decomposition, revers angle sign because we deal

% with "frame" rotation type, basic rotation compatible with specified

% Order 'ZYX'

Riz = makehgtform('zrotate', -Ei(1));

Riy = makehgtform('yrotate', -Ei(2));

Rix = makehgtform('xrotate', -Ei(3));

Ri = Rix*Riy*Riz; Ri = Ri(1:3,1:3) % it must match R

Ri = 3×3

-0.1543 -0.7096 0.6875
-0.5385 0.6438 0.5437
-0.8284 -0.2863 -0.4815

norm(Ri-R) % or this must be very small

ans = 4.8438e-16

% Check extrinsic frame decomposition

Rez = makehgtform('zrotate', -Ee(1));

Rey = makehgtform('yrotate', -Ee(2));

Rex = makehgtform('xrotate', -Ee(3));

Re = Rez*Rey*Rex; Re = Re(1:3,1:3) % it must match R

Re = 3×3

-0.1543 -0.7096 0.6875
-0.5385 0.6438 0.5437
-0.8284 -0.2863 -0.4815

norm(Re-R) % or this must be very small

ans = 6.5414e-16

Paul
on 25 Jan 2024

Hi Frank,

According to a comment in this answer, there appears to be no function in any toolbox that works with extrinsic Euler angles.

It's possible that new functionality has been added in the intervening time or that the commenter was unaware of such functionality at that time.

Also, keep in mind that participants with a Staff flair are not providing official TMW responses here on Answers.

### See Also

### Categories

### Products

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!**An Error Occurred**

Unable to complete the action because of changes made to the page. Reload the page to see its updated state.

Select a Web Site

Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .

You can also select a web site from the following list

How to Get Best Site Performance

Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.

Americas

- América Latina (Español)
- Canada (English)
- United States (English)

Europe

- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)

- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)

Asia Pacific

- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)