"Random" generation of rotation matrices

32.5k Views Asked by At

For a current project, I need to generate several $3\times 3$ rotation matrices for input into an algorithm. I thought I might go about this by randomly generating the number of elements needed to define a rotation matrix and then calculating the remaining elements from them. Does anyone know of an algorithm for calculating the remaining elements once a defining set of elements is given? Or does anyone know of a better way to go about this? Thanks.

6

There are 6 best solutions below

1
On BEST ANSWER

I have had the same exact problem myself a while ago so I point you to this which says it very succinctly with plenty of references.

8
On

Rotation matrices can be uniquely defined by a vector and a rotation angle. To generate the vector, you can use grandom spherical coordinates $\phi$ and $\theta$. Thus you should first generate random angles by using:

$$\theta = \arccos(2u_1 - 1)$$ $$\phi = 2\pi u_2$$ Where $u_1,u_2$ are uniformly distributed in $[0,1]$. This will give you a vector around which to rotate. Then, randomly decide the amount of rotation $\psi\in[0,2\pi]$.

3
On

Here's one way: use yaw, pitch, and roll. Generate three angles at random: $\alpha,\beta,\gamma$. Generate your random rotation as

$$ R = R_x(\gamma) \, R_y(\beta) \, R_z(\alpha)\ $$

Where $R_z(\alpha)$ is the rotation matrix about the $z$-axis, given by $$ R_z = \begin{bmatrix} \cos\alpha & -\sin\alpha & 0\\ \sin\alpha & \cos\alpha & 0\\ 0 & 0 & 1 \end{bmatrix} $$

and the other two are similarly defined (for their respective axes and angles).

2
On

What I often do is, to generate a random matrix and column-rotate it to some shape, for instance triangular shape. keeping track of the rotations gives then a random-rotation-matrix.
In my matrix-program MatMate this read simply:

 u = randomu(3,3)   // generate a 3x3 matrix with uniform distributed entries
 t = gettrans ( u, "tri") // get the rotation-matrix, which rotates u to "tri"angular shape

 // check
 chk = u * t   // matrix chk is triangular
2
On

This is an interesting question! If the "random matrix" is being used for any sort of Monte-Carlo testing, it is important that a sequence of "random matrices" produced by whatever (as von Neumann noted, putting us in a state of sin if we claim too much about it) pseudo-random device, be at least demonstrably equi-distributed in the rotation group $SO(3)$.

I have no serious operational quibble with other answers, which are certainly thoughtful and productive, but/and I might object that they are ad-hoc, so offering no a-priori promise of any genuine pseudo-randomness.

If it does matter to have a more-certifiable pseudo-randomness, the following device lends itself more to proof, for random 3-D rotations. Use the fact that Hamiltonian $\mathbb H$ quaternions give 3D rotations in at least one way, namely, identify $\mathbb R^3$ with purely imaginary quaternions, and let $g\in \mathbb H^\times$ act on purely-imaginary quaternions $x$ by $g\cdot x=gxg^{-1}$.

In that set-up, it's not too hard to prove various "pseudo-randomness" (equi-distribution) properties.

(Edit: For example, choose elements of $\mathbb H$ pseudo-randomly in some ball of radius $R$ according to some volume-equidistribution "rule", and let $R\rightarrow +\infty$...)

0
On

We can take advantage of the Rodrigues' rotation formula to generate rotation matrices.

Image of the Rodrigues' rotation formula

Image of the bracket notation

With this, you only need to generate a random 3x1 unit vector (as the rotation axis) and specify a rotation angle. This formula will transform them into a valid rotation matrix.

MATLAB example:

function R = rot(w, theta)
  bw = [0, -w(3), w(2); w(3), 0, -w(1); -w(2), w(1), 0];
  R = eye(3) + sin(theta)*bw + (1-cos(theta))*bw*bw;
end

w = rand(3,1)
w = w/norm(w)
R = rot(w, 3.14)

C++ example:

// w: the unit vector indicating the rotation axis
// theta: the rotation angle in radian
Eigen::Matrix3d MatrixExp3 (Eigen::Vector3d w, float theta){
  Eigen::Matrix3d bw, R;
  bw << 0, -w(2), w(1), w(2), 0, -w(0), -w(1), w(0), 0;
  R << Eigen::Matrix3d::Identity() + std::sin(theta)*bw + (1-std::cos(theta))*bw*bw;
  return R;
}

int main() {
  std::srand((unsigned int) time(0));
  Eigen::Vector3d w = Eigen::Vector3d::Random();
  Eigen::Matrix3d R = MatrixExp3(w.normalized(), 3.14f);
  std::cout << R << std::endl;
}