Skip to content

Commit

Permalink
added euler angles doc
Browse files Browse the repository at this point in the history
  • Loading branch information
arsenovic committed Sep 28, 2016
1 parent 737ce4d commit c7f15fb
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 22 deletions.
328 changes: 328 additions & 0 deletions docs/EulerAngles.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Euler Angles"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook demonstrates how to use `clifford` to implement rotations in three dimensions using rotors. Specifically, the rotation is parameterized using Euler Angles. Conversion from the rotor form to a matrix reprentation is shown, and only takes three lines of code. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Euler Angles with Rotors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A common way to parameterize rotations in three dimensions is through [Euler Angles](https://en.wikipedia.org/wiki/Euler_angles). \n",
"\n",
"\"Any orientation can be achieved by composing three elemental rotations. The elemental rotations can either occur about the axes of the fixed coordinate system (*extrinsic rotations*) or about the axes of a rotating coordinate system, which is initially aligned with the fixed one, and modifies its orientation after each elemental rotation (*intrinsic rotations*). \"\n",
"\n",
"The animation below shows an intrinsic rotation model, as each elemental rotation is applied. Label the left,right, and vertical blue-axes are $e_1, e_2,$ and $e_3$, respectively. \n",
"\n",
"\n",
"The series of rotations can be described:\n",
"\n",
"1. rotate about $e_3$\n",
"2. rotate about the rotated $e_1$, call it $e_1^{'}$\n",
"3. rotate about the twice rotated axis of $e_3$, call it $e_3^{''}$"
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<img src=\"_static/Euler2a.gif\"/>"
],
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import Image,SVG\n",
"Image(url='_static/Euler2a.gif')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"Following Sec. 2.7.5 from \"Geometric Algebra for Physicists\", we first rotate an angle $\\phi$ about the\n",
"$e_3$-axis, which is equivalent to rotating in the $e_{12}$-plane. This is done with the rotor\n",
"\n",
"$$ R_{\\phi} = e^{-\\frac{\\phi}{2} e_{12}}$$\n",
"\n",
"\n",
"Next we rotate about the rotated $e_1$-axis, which we label $e_1^{'}$\n",
"\n",
"$$ e_1^{'} =R_{\\phi} e_1 \\tilde{R_{\\phi}} $$\n",
"\n",
"The plane corresponding to this axis is found by taking the dual of $e_1^{'}$\n",
"\n",
"$$ I R_{\\phi} e_1 \\tilde{R_{\\phi}} = R_{\\phi} e_{23} \\tilde{R_{\\phi}} $$\n",
"\n",
"\n",
"(where we have made use of the fact that the psuedo-scalar commutes in G3). The second roation by angle $\\theta$ about the $e_1^{'}$-axis is then ,\n",
"\n",
"\n",
"$$ R_{\\theta} = e^{\\frac{\\theta}{2} R_{\\phi} e_{23} \\tilde{R_{\\phi}}} $$\n",
"\n",
"\n",
"However, noting that \n",
"\n",
"$$ e^{R_{\\phi} e_{23} \\tilde{R_{\\phi}}} =R_{\\phi} e^{e_{23}} \\tilde{R_{\\phi}} $$\n",
"\n",
"Allows us to write the second rotation by angle $\\theta$ about the $e_1^{'}$-axis as \n",
"\n",
"$$ R_{\\theta} = R_{\\phi} e^{\\frac{\\theta}{2}e_{23}} \\tilde{R_{\\phi}} $$\n",
"\n",
"So, the combonation of the first two elemental rotations equals, \n",
"\n",
"\\begin{align*} \n",
"R_{\\theta} R_{\\phi} &= R_{\\phi} e^{\\frac{\\theta}{2}e_{23}} \\tilde{R_{\\phi}} R_{\\phi} \\\\ \n",
"&= e^{-\\frac{\\phi}{2} e_{12}}e^{-\\frac{\\theta}{2} e_{23}}\n",
"\\end{align*}\n",
"\n",
"This pattern can be extended to the third elemental rotation of angle $\\psi$ in the twice-rotated $e_1$-axis, creating the total rotor \n",
"\n",
"$$ R = e^{-\\frac{\\phi}{2} e_{12}} e^{-\\frac{\\theta}{2} e_{23}} e^{-\\frac{\\psi}{2} e_{12}} $$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we initialize the algbera and assign the variables"
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from clifford import Cl\n",
"\n",
"layout, blades = Cl(3) # create a 3-dimensional clifford algebra\n",
"\n",
"locals().update(blades) # lazy way to put entire basis in the namespace"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"Next we define a function to produce a rotor given euler angles"
]
},
{
"cell_type": "code",
"execution_count": 95,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def R_euler(phi, theta,psi):\n",
" Rphi = e**(-phi/2.*e12)\n",
" Rtheta = e**(-theta/2.*e23)\n",
" Rpsi = e**(-psi/2.*e12)\n",
" \n",
" return Rphi*Rtheta*Rpsi"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example, using this to create the rotation shown in the animation above,"
]
},
{
"cell_type": "code",
"execution_count": 96,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0.65328 - (0.65328^e12) - (0.38268^e23)"
]
},
"execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from numpy import pi \n",
"\n",
"R = R_euler(pi/4, pi/4, pi/4)\n",
"R"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see how this rotor changes an ortho-normal frame "
]
},
{
"cell_type": "code",
"execution_count": 97,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(0.14645^e1) + (0.85355^e2) + (0.5^e3),\n",
" -(0.85355^e1) - (0.14645^e2) + (0.5^e3),\n",
" (0.5^e1) - (0.5^e2) + (0.70711^e3)]"
]
},
"execution_count": 97,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
"[R*a*~R for a in [e1,e2,e3]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Convert to Rotation Matrix"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The matrix representation for a rotation can defined as the result of rotating an ortho-normal frame. Rotating an ortho-normal frame can be done easily, "
]
},
{
"cell_type": "code",
"execution_count": 98,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(0.14645^e1) + (0.85355^e2) + (0.5^e3),\n",
" -(0.85355^e1) - (0.14645^e2) + (0.5^e3),\n",
" (0.5^e1) - (0.5^e2) + (0.70711^e3)]"
]
},
"execution_count": 98,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from numpy import array \n",
"\n",
"A = [e1,e2,e3] # initial ortho-normal frame\n",
"B = [R*a*~R for a in A] # resultant frame after rotation\n",
"\n",
"B"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The components of this frame are equivalent to the rotation matrix. We could put this in a matrix easily by, "
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.14644661, 0.85355339, 0.5 ],\n",
" [-0.85355339, -0.14644661, 0.5 ],\n",
" [ 0.5 , -0.5 , 0.70710678]])"
]
},
"execution_count": 99,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"M = [float(b|a) for b in B for a in A] # you need float() due to bug in clifford\n",
"array(M).reshape(3,3)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "IPython (Python 2)",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

0 comments on commit c7f15fb

Please sign in to comment.