Code covered by the BSD License

# quaternion.m

### Mark Tincknell (view profile)

18 Oct 2011 (Updated )

quaternion class, vectorized, converts among rotation representations, numerical Euler propagation

quaterniondemo( time, sap, DCMin, interval )
```function quaterniondemo( time, sap, DCMin, interval )
% function quaterniondemo( time, sap, DCMin, interval )
% quaternion demo, compare numerical and analytical rotational motion
% solutions
% Inputs:
%  time(nt)     time series array (s)
%  sap(3)       [spin rate (Hz), precession cone half angle (rad),
%               precession rate (Hz)]
%  DCMin(3,3) [OPTIONAL] initial Direction Cosine Matrix; default = eye(3)
%  interval   [OPTIONAL] plot update pause interval (s); default = 0.1
% Outputs:
%  2 figures ploting axis orientations for the time series from matlab's
%  ode45 (Ordinary Differential Equation) numerical solution using the
%  quaternion class and PropagateEulerEq method, and the analytical
%  solution for axisymmetric objects computed in the spinprecess function.
% Author:
%  Mark Tincknell, 4 January 2011

if (nargin < 3) || isempty(DCMin)
DCMin   = eye(3);
end
if (nargin < 4) || isempty(interval)
interval    = 0.1;
end
ws      = 2 * pi * sap(1);
theta   = sap(2);
wp      = 2 * pi * sap(3);
costh   = cos( theta );
if (abs( costh ) < eps) || (ws == 0)
w0  = [ 0; -wp; 0 ];
I   = [ 1; 1; 1 ];
else
mu  = 1 + ws /( wp * costh );
w0  = [ ws /( 1 - 1/mu ); -ws * tan( theta )/( mu - 1 ); 0 ];
I   = [ 1; mu; mu ];
end
q0      = quaternion.angleaxis( theta, [0;0;1] );
[q1 w1] = PropagateEulerEq( q0, w0, I, time );
q1      = quaternion.rotationmatrix( DCMin ) .* q1;
PlotRotation( q1, interval );
title( 'quaternion' );

DCM     = spinprecess( time, sap, DCMin );
plotRotation( DCM, interval );
title( 'spinprecess' );

end % quaterniondemo

function plotRotation( DCM, interval )
% function plotRotation( DCM, interval )
% Plot rotation axes for a series of Direction Cosine Matrices, adapted
% from the quaternion PlotRotation method
if ~exist( 'interval', 'var' )
interval    = 0.1;
end
nel = size( DCM, 3 );
or  = zeros(1,3);
ax  = eye(3);
alx = zeros( nel, 3, 3 );
figure;
for iel = 1 : nel
%     plot3( [ or; ax(:,1).' ], [ or ; ax(:,2).' ], [ or; ax(:,3).' ], ':' );
plot3( [ or; ax(1,:) ], [ or ; ax(2,:) ], [ or; ax(3,:) ], ':' );
hold on
set( gca, 'Xlim', [-1 1], 'Ylim', [-1 1], 'Zlim', [-1 1] );
xlabel( 'x' );
ylabel( 'y' );
zlabel( 'z' );
grid on
nax = DCM(:,:,iel);
alx(iel,:,:)    = nax;
%     plot3( [ or; nax(:,1).' ], [ or ; nax(:,2).' ], [ or; nax(:,3).' ], '-', 'LineWidth', 2 );
plot3( [ or; nax(1,:) ], [ or ; nax(2,:) ], [ or; nax(3,:) ], '-', 'LineWidth', 2 );
%     plot3( alx(1:iel,:,1), alx(1:iel,:,2), alx(1:iel,:,3), '*' );
plot3( squeeze(alx(1:iel,1,:)), squeeze(alx(1:iel,2,:)), squeeze(alx(1:iel,3,:)), '*' );
if interval
pause( interval );
end
hold off
end % for
end % plotRotation

function [DCMout, Omega] = spinprecess( time, sap, DCMin )
% function [DCMout, Omega] = spinprecess( time, sap, DCMin )
% Direction Cosine (Rotation) Matrices for a spinning, precessing
% axisymmetric object.  "x" ([1;0;0]) is the principal body axis.
% Inputs:
%  time(nt)     times (s)
%  sap(3)       [spin rate (Hz), prec. cone angle (rad), prec. rate (Hz)]
%  DCMin(3,3) [OPTIONAL] initial Direction Cosine Matrix; default = eye(3)
% Outputs:
%  DCMout(3,3,nt)   Direction Cosine Matrices
%  Omega(3,3,nt)    Rotational velocity matrices
% Application:
%  x_rot = DCMout * x (where x is a 3 element column position vector)
%  v_rot = Omega * x + v (where v is the translational velocity vector)
% Calls:
%  rodrigues(axis,theta)    Rotation by theta about axis
% Author:
%  Mark Tincknell, MIT LL, 23 Nov. 2004
%                  revised 14 Dec. 2009

if (nargin < 3) || isempty(DCMin)
DCMin   = eye(3);
end
nt      = length( time );
Rang    = rodrigues( [0;0;1], sap(2) ); % precession cone angle
omegas  = 2 * pi * sap(1);              % spin
omegap  = 2 * pi * sap(3);              % precession
for it = nt : -1 : 1
[Rs, dRs]   = rodrigues( [1;0;0], omegas * time(it) );
[Rp, dRp]   = rodrigues( [1;0;0], omegap * time(it) );
DCMout(:,:,it)  = DCMin * Rp * Rang * Rs;
Omega(:,:,it)   = DCMin *( omegap * dRp * Rang * Rs + ...
omegas * Rp * Rang * dRs );
end
end % spinprecess

function [R, dR] = rodrigues( u, theta )
% function [R, dR] = rodrigues( u, theta )
% Computes rotation matrix (Direction Cosine Matrix) from Rodrigues'
% rotation formula. See http://mathworld.wolfram.com/RodriguesRotationFormula.html
% Inputs:
%  u(3)     fixed axis of rotation
%  theta    rotation angle in radians
% Outputs:
%  R(3,3)   rotation matrix
%  dR(3,3)  differential of R
% Application:
%  x_rot = R * x (where x is a 3 element column vector)
%  v_rot = omega * dR * x (where omega is d(theta)/dt)
% Authors:
%  Douglas Lanman, Mark Tincknell, MIT LL, 8 August 2003

% Normalize u (fixed-axis of rotation)
u   = u/norm(u);

% Skew-symmetric matrix W
W   = [ 0    -u(3)  u(2);
u(3)  0    -u(1);
-u(2)  u(1)  0];
W2  = W^2;

% Trig functions
sth = sin( theta );
cth = cos( theta );

% Rotation matrix R, differential rotation matrix dR
R   = eye(3) + sth * W + (1 - cth) * W2;
dR  = cth * W + sth * W2;

end % rodrigues```