{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Path frame\n", "\n", "> Renato Naville Watanabe, Marcos Duarte \n", "> [Laboratory of Biomechanics and Motor Control](http://pesquisa.ufabc.edu.br/bmclab) \n", "> Federal University of ABC, Brazil" ] }, { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "

Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python setup" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.293508Z", "start_time": "2020-10-11T03:44:07.779017Z" } }, "outputs": [ { "ename": "ModuleNotFoundError", "evalue": "No module named 'sympy'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0msympy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0msym\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msympy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvector\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mCoordSys3D\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpyplot\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0msym\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_printing\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'sympy'" ] } ], "source": [ "import numpy as np\n", "import sympy as sym\n", "from sympy.vector import CoordSys3D\n", "import matplotlib.pyplot as plt\n", "sym.init_printing()\n", "from sympy.plotting import plot_parametric\n", "from sympy.physics.mechanics import ReferenceFrame, Vector, dot\n", "from matplotlib.patches import FancyArrowPatch\n", "plt.rcParams.update({'figure.figsize':(8, 5), 'lines.linewidth':2})" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Cartesian coordinate system\n", "\n", "As we perceive the surrounding space as three-dimensional, a convenient coordinate system is the [Cartesian coordinate system](http://en.wikipedia.org/wiki/Cartesian_coordinate_system) in the [Euclidean space](http://en.wikipedia.org/wiki/Euclidean_space) with three orthogonal axes as shown below. The axes directions are commonly defined by the [right-hand rule](http://en.wikipedia.org/wiki/Right-hand_rule) and attributed the letters X, Y, Z. The orthogonality of the Cartesian coordinate system is convenient for its use in classical mechanics, most of the times the structure of space is assumed having the [Euclidean geometry](http://en.wikipedia.org/wiki/Euclidean_geometry) and as consequence, the motion in different directions are independent of each other. \n", "
\n", "
Figure. Representation of a point and its position vector in a Cartesian coordinate system.
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Determination of a coordinate system\n", "\n", "In Biomechanics, we may use different coordinate systems for convenience and refer to them as global, laboratory, local, anatomical, or technical reference frames or coordinate systems. \n", "\n", "From [linear algebra](http://en.wikipedia.org/wiki/Linear_algebra), a set of unit linearly independent vectors (orthogonal in the Euclidean space and each with norm (length) equals to one) that can represent any vector via [linear combination](http://en.wikipedia.org/wiki/Linear_combination) is called a basis (or **orthonormal basis**). The figure below shows a point and its position vector in the Cartesian coordinate system and the corresponding versors (**unit vectors**) of the basis for this coordinate system. See the notebook [Scalar and vector](http://nbviewer.ipython.org/github/demotu/BMC/blob/master/notebooks/ScalarVector.ipynb) for a description on vectors. \n", "
Figure. Representation of a point $\\mathbf{P}$ and its position vector $\\overrightarrow{\\mathbf{r}}$ in a Cartesian coordinate system. The versors $\\hat{\\mathbf{i}},\\, \\hat{\\mathbf{j}},\\, \\hat{\\mathbf{k}}\\,$ form a basis for this coordinate system and are usually represented in the color sequence RGB (red, green, blue) for easier visualization.
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "One can see that the versors of the basis shown in the figure above have the following coordinates in the Cartesian coordinate system:\n", "
\n", "\n", "\\begin{equation}\n", "\\hat{\\mathbf{i}} = \\begin{bmatrix}1\\\\0\\\\0 \\end{bmatrix}, \\quad \\hat{\\mathbf{j}} = \\begin{bmatrix}0\\\\1\\\\0 \\end{bmatrix}, \\quad \\hat{\\mathbf{k}} = \\begin{bmatrix} 0 \\\\ 0 \\\\ 1 \\end{bmatrix}\n", "\\label{eq_1}\n", "\\end{equation}\n", "\n", "\n", "Using the notation described in the figure above, the position vector $\\overrightarrow{\\mathbf{r}}$ can be expressed as:\n", "
\n", "\n", "\\begin{equation}\n", "\\overrightarrow{\\mathbf{r}} = x\\hat{\\mathbf{i}} + y\\hat{\\mathbf{j}} + z\\hat{\\mathbf{k}}\n", "\\label{eq_2}\n", "\\end{equation}\n", "\n", "\n", "However, to use a fixed basis can lead to very complex expressions." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Path basis" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Consider that we have the position vector of a particle, moving in the path described by the parametric curve $s(t)$, described in a fixed reference frame as:\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{r}}(t) = {x}{\\bf\\hat{i}}+{y}{\\bf\\hat{j}} + {z}{\\bf\\hat{k}}\n", "\\label{eq_3}\n", "\\end{equation}\n", "\n", "\n", "
Figure. Position vector of a moving particle in relation to a coordinate system.
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Tangential versor\n", "\n", "Often we describe all the kinematic variables in this fixed reference frame. However, it is often useful to define a path basis, attached to some point of interest. In this case, what is usually done is to choose as one of the basis vector a unitary vector in the direction of the velocity of the particle. Defining this vector as:\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{e}_t} = \\frac{{\\bf\\vec{v}}}{\\Vert{\\bf\\vec{v}}\\Vert}\n", "\\label{eq_4}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" }, "variables": { "\\bf\\vec{C": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n", "\\bf\\vec{v": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n" } }, "source": [ "### Normal versor\n", "\n", "For the second vector of the basis, we define first a vector of curvature of the path (the meaning of this curvature vector will be seeing in another notebook):\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{C}} = \\frac{d{\\bf\\hat{e}_t}}{ds}\n", "\\label{eq_5}\n", "\\end{equation}\n", "\n", "\n", "Note that $\\bf\\hat{e}_t$ is a function of the path $s(t)$. So, by the chain rule:\n", "
\n", "\n", "\\begin{equation}\n", "\\frac{d{\\bf\\hat{e}_t}}{dt} = \\frac{d{\\bf\\hat{e}_t}}{ds}\\frac{ds}{dt} \\longrightarrow \\frac{d{\\bf\\hat{e}_t}}{ds} = \\frac{\\frac{d{\\bf\\hat{e}_t}}{dt}}{\\frac{ds}{dt}} \\longrightarrow {\\bf\\vec{C}} = \\frac{\\frac{d{\\bf\\hat{e}_t}}{dt}}{\\frac{ds}{dt}}\\longrightarrow {\\bf\\vec{C}} = \\frac{\\frac{d{\\bf\\hat{e}_t}}{dt}}{\\Vert{\\bf\\vec{v}}\\Vert}\n", "\\label{eq_6}\n", "\\end{equation}\n", "\n", "\n", "Now we can define the second vector of the basis, ${\\bf\\hat{e}_n}$:\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{e}_n} = \\frac{{\\bf\\vec{C}}}{\\Vert{\\bf\\vec{C}}\\Vert}\n", "\\label{eq_7}\n", "\\end{equation}\n", "\n", "\n", "
Figure. A moving particle and a corresponding path basis.
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Binormal versor\n", "\n", "The third vector of the basis is obtained by the cross product between ${\\bf\\hat{e}_n}$ and ${\\bf\\hat{e}_t}$:\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\hat{e}_b} = {\\bf\\hat{e}_t} \\times {\\bf\\hat{e}_n}\n", "\\label{eq_8}\n", "\\end{equation}\n", "\n", "\n", "Note that the vectors ${\\bf\\hat{e}_t}$ , ${\\bf\\hat{e}_n}$ and ${\\bf\\hat{e}_b}$ vary together with the particle movement. This basis is also called as **Frenet-Serret frame**." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Velocity and Acceleration in a path frame" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" }, "variables": { "\\bf\\hat{e}_t": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n", "d({\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n", "d\\bf\\vec{v": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n" } }, "source": [ "### Velocity \n", "\n", "Given the expression of $r(t)$ in a fixed frame we can write the velocity ${\\bf\\vec{v}(t)}$ as a function of the fixed frame of reference ${\\bf\\hat{i}}$, ${\\bf\\hat{j}}$ and ${\\bf\\hat{k}}$ (see http://nbviewer.jupyter.org/github/BMClab/bmc/blob/master/notebooks/KinematicsParticle.ipynb)).\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}}(t) = \\dot{x}{\\bf\\hat{i}}+\\dot{y}{\\bf\\hat{j}}+\\dot{z}{\\bf\\hat{k}}\n", "\\label{eq_9}\n", "\\end{equation}\n", "\n", "\n", "However, this can lead to very complex functions. So it is useful to use the basis find previously ${\\bf\\hat{e}_t}$, ${\\bf\\hat{e}_n}$ and ${\\bf\\hat{e}_b}$.\n", "\n", "The velocity ${\\bf\\vec{v}}$ of the particle is, by the definition of ${\\bf\\hat{e}_t}$, in the direction of ${\\bf\\hat{e}_t}$:\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{v}}={\\Vert\\bf\\vec{v}\\Vert}.{\\bf\\hat{e}_t}\n", "\\label{eq_10}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" }, "variables": { "\\bf\\hat{e}_t": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n", "d({\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n", "d\\bf\\vec{v": "

SyntaxError: unexpected character after line continuation character (, line 1)

\n" } }, "source": [ "### Acceleration\n", "\n", "The acceleration can be written in the fixed frame of reference as:\n", "
\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{a}}(t) = \\ddot{x}{\\bf\\hat{i}}+\\ddot{y}{\\bf\\hat{j}}+\\ddot{z}{\\bf\\hat{k}}\n", "\\label{eq_11}\n", "\\end{equation}\n", "\n", "\n", "But for the same reasons of the velocity vector, it is useful to describe the acceleration vector in the path basis. We know that the acceleration is the time derivative of the velocity:\n", "
\n", "\n", "\\begin{align}\n", "{\\bf\\vec{a}} =& \\frac{{d\\bf\\vec{v}}}{dt}=\\\\\n", " =&\\frac{{d({\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}})}{dt}=\\\\\n", " =&\\dot{\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}+{\\Vert\\bf\\vec{v}\\Vert}\\dot{{\\bf\\hat{e}_t}}=\\\\\n", " =&\\dot{\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}+{\\Vert\\bf\\vec{v}\\Vert}\\frac{d{\\bf\\hat{e}_t}}{ds}\\frac{ds}{dt}=\\\\\n", " =&\\dot{\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}+{\\Vert\\bf\\vec{v}\\Vert}^2\\frac{d{\\bf\\hat{e}_t}}{ds}=\\\\\n", " =&\\dot{\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}+{\\Vert\\bf\\vec{v}\\Vert}^2\\Vert{\\bf\\vec{C}} \\Vert {\\bf\\hat{e}_n}\n", "\\label{eq_12}\n", "\\end{align}\n", "\n", "\n", "The inverse of the size of the curvature vector $\\frac{1}{\\Vert\\bf\\vec{C}\\Vert}$ is know as the curvature radius of the path $\\rho$.\n", "\n", "\n", "\\begin{equation}\n", "{\\bf\\vec{a}} =\\dot{\\Vert\\bf\\vec{v}\\Vert}{\\bf\\hat{e}_t}+\\frac{{\\Vert\\bf\\vec{v}\\Vert}^2}{\\rho}{\\bf\\hat{e}_n}\n", "\\label{eq_13}\n", "\\end{equation}\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Example\n", "For example, consider that a particle follows the path described by the parametric curve below:\n", "
\n", "\n", "\\begin{equation}\n", "\\vec{r}(t) = (10t+100){\\bf{\\hat{i}}} + \\left(-\\frac{9,81}{2}t^2+50t+100\\right){\\bf{\\hat{j}}}\n", "\\label{eq_13}\n", "\\end{equation}\n", "\n", "\n", "This curve could be, for example, from a projectile motion. See http://nbviewer.jupyter.org/github/BMClab/bmc/blob/master/notebooks/ProjectileMotion.ipynb for an explanation on projectile motion." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Solving numerically\n", "\n", "Now we will obtain the path basis numerically. This method is useful when it is not available a mathematical expression of the path. This often happens when you have available data collected experimentally (most of the cases in Biomechanics). \n", "\n", "First, data will be obtained from the expression of $r(t)$. This is done to replicate the example above. You could use data collected experimentally, for example." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.296631Z", "start_time": "2020-10-11T03:44:08.294508Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "t = np.linspace(0, 10, 1000).reshape(-1,1)\n", "r = np.hstack((10*t + 100, -9.81/2*t**2 + 50*t + 100))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Now, to obtain the $\\bf{\\hat{e_t}}$ versor, we can use Equation (4)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.299722Z", "start_time": "2020-10-11T03:44:08.297723Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "dt = t[1]\n", "v = np.diff(r,axis=0)/dt\n", "vNorm = np.linalg.norm(v, axis=1, keepdims=True)\n", "\n", "et = v/vNorm" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "And to obtain the versor $\\bf{\\hat{e_n}}$, we can use Equation (8)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.302775Z", "start_time": "2020-10-11T03:44:08.300705Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "C = np.diff(et,axis=0)/dt\n", "C = C/vNorm[1:]\n", "\n", "CNorm = np.linalg.norm(C, axis=1, keepdims=True)\n", "en = C/CNorm" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.779278Z", "start_time": "2020-10-11T03:44:08.303657Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "fig = plt.figure()\n", "plt.plot(r[:, 0], r[:, 1], '.')\n", "ax = fig.add_axes([0, 0, 1, 1])\n", "time = np.linspace(0, 10, 10)\n", "for i in np.arange(0, len(t)-2, 50):\n", " vec1 = FancyArrowPatch(r[i, :], r[i, :]+10*et[i, :], mutation_scale=20, color='r')\n", " vec2 = FancyArrowPatch(r[i, :], r[i, :]+10*en[i, :], mutation_scale=20, color='g')\n", " ax.add_artist(vec1)\n", " ax.add_artist(vec2)\n", "plt.xlim((80, 250))\n", "plt.ylim((80, 250))\n", "plt.legend([vec1, vec2], [r'$\\vec{e_t}$', r'$\\vec{e_{n}}$'])\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:08.782372Z", "start_time": "2020-10-11T03:44:08.780178Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "v = vNorm*et\n", "vNormDot = np.diff(vNorm, axis=0)/dt\n", "\n", "a = vNormDot*et[1:,:] + CNorm*en*vNorm[1:]**2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.150683Z", "start_time": "2020-10-11T03:44:08.783198Z" }, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "fig = plt.figure()\n", "plt.plot(r[:, 0], r[:, 1], '.')\n", "ax = fig.add_axes([0, 0, 1, 1])\n", "for i in range(0, len(t)-2, 50):\n", " vec1 = FancyArrowPatch(r[i, :], r[i, :]+v[i, :], mutation_scale=10, color='r')\n", " vec2 = FancyArrowPatch(r[i, :], r[i, :]+a[i, :], mutation_scale=10, color='g')\n", " ax.add_artist(vec1)\n", " ax.add_artist(vec2)\n", "plt.xlim((80, 250))\n", "plt.ylim((80, 250))\n", "plt.legend([vec1, vec2], [r'$\\vec{v}$', r'$\\vec{a}$'])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "### Symbolic solution (extra reading)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "The computation here will be performed symbolically, with the symbolic math package of Python, Sympy. Below,a reference frame, called O, and a varible for time (t) are defined." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.154388Z", "start_time": "2020-10-11T03:44:09.152278Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "O = sym.vector.CoordSys3D(' ')\n", "t = sym.symbols('t')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "Below the vector $r(t)$ is defined symbolically." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.276352Z", "start_time": "2020-10-11T03:44:09.155751Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "r = (10*t+100)*O.i + (-9.81/2*t**2+50*t+100)*O.j+0*O.k\n", "r" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.425806Z", "start_time": "2020-10-11T03:44:09.277382Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "p1 = plot_parametric(r.dot(O.i), r.dot(O.j), (t, 0, 10), line_width=4, aspect_ratio=(2, 1))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.547462Z", "start_time": "2020-10-11T03:44:09.426760Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "v = sym.diff(r)\n", "v" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.672532Z", "start_time": "2020-10-11T03:44:09.548563Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "et = v/sym.sqrt(v.dot(v))\n", "et" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:09.812340Z", "start_time": "2020-10-11T03:44:09.673587Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "C = sym.diff(et)/sym.sqrt(v.dot(v))\n", "C" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:10.627457Z", "start_time": "2020-10-11T03:44:09.813393Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "en = C/(sym.sqrt(C.dot(C)))\n", "sym.simplify(en)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:11.193210Z", "start_time": "2020-10-11T03:44:10.628587Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "fig = plt.figure()\n", "ax = fig.add_axes([0, 0, 1, 1]) \n", "time = np.linspace(0, 10, 30)\n", "for instant in time:\n", " vt = FancyArrowPatch([float(r.dot(O.i).subs(t,instant)),float(r.dot(O.j).subs(t,instant))], \n", " [float(r.dot(O.i).subs(t,instant))+10*float(et.dot(O.i).subs(t,instant)),\n", " float(r.dot(O.j).subs(t, instant))+10*float(et.dot(O.j).subs(t,instant))], \n", " mutation_scale=20,\n", " arrowstyle=\"->\",color=\"r\",label='${\\hat{e_t}}$', lw=2)\n", " vn = FancyArrowPatch([float(r.dot(O.i).subs(t, instant)),float(r.dot(O.j).subs(t,instant))], \n", " [float(r.dot(O.i).subs(t, instant))+10*float(en.dot(O.i).subs(t, instant)),\n", " float(r.dot(O.j).subs(t, instant))+10*float(en.dot(O.j).subs(t, instant))], \n", " mutation_scale=20,\n", " arrowstyle=\"->\",color=\"g\",label='${\\hat{e_n}}$', lw=2)\n", " ax.add_artist(vn)\n", " ax.add_artist(vt)\n", "plt.xlim((90, 250))\n", "plt.ylim((90, 250))\n", "plt.xlabel('x')\n", "plt.legend(handles=[vt, vn], fontsize=20)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "Now we can find the vectors ${\\bf\\vec{v}}$ and ${\\bf\\vec{a}}$ described in the path frame." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:11.197721Z", "start_time": "2020-10-11T03:44:11.194309Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "v = sym.sqrt(v.dot(v))*et" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:11.440643Z", "start_time": "2020-10-11T03:44:11.198650Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "a = sym.diff(sym.sqrt(v.dot(v)))*et+v.dot(v)*sym.sqrt(C.dot(C))*en\n", "sym.simplify(sym.simplify(a))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-10-11T03:44:11.708072Z", "start_time": "2020-10-11T03:44:11.441849Z" }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "fig = plt.figure()\n", "ax = fig.add_axes([0, 0, 1, 1]) \n", "time = np.linspace(0, 10, 10)\n", "for instant in time:\n", " vt = FancyArrowPatch([float(r.dot(O.i).subs(t,instant)),float(r.dot(O.j).subs(t,instant))], \n", " [float(r.dot(O.i).subs(t,instant))+float(v.dot(O.i).subs(t,instant)),\n", " float(r.dot(O.j).subs(t, instant))+float(v.dot(O.j).subs(t,instant))], \n", " mutation_scale=20,\n", " arrowstyle=\"->\",color=\"r\",label='${{v}}$', lw=2)\n", " vn = FancyArrowPatch([float(r.dot(O.i).subs(t, instant)),float(r.dot(O.j).subs(t,instant))], \n", " [float(r.dot(O.i).subs(t, instant))+float(a.dot(O.i).subs(t, instant)),\n", " float(r.dot(O.j).subs(t, instant))+float(a.dot(O.j).subs(t, instant))], \n", " mutation_scale=20,\n", " arrowstyle=\"->\",color=\"g\",label='${{a}}$', lw=2)\n", " ax.add_artist(vn)\n", " ax.add_artist(vt)\n", "plt.xlim((60, 250))\n", "plt.ylim((60, 250))\n", "plt.legend(handles=[vt, vn], fontsize=20)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Further Reading\n", "\n", " - Read pages 932-971 of the 18th chapter of the [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html) about path basis vectors." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Video lectures on the Internet\n", "\n", " - [Path Vectors](https://eaulas.usp.br/portal/video?idItem=7800)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Problems\n", "\n", "1. Obtain the vectors $\\hat{e_n}$ and $\\hat{e_t}$ for the problem 18.1.1 from Ruina and Rudra's book.\n", "2. Solve the problem 18.1.9 from Ruina and Rudra's book.\n", "3. Write a Python program to solve the problem 18.1.10 (only the part of $\\hat{e_n}$ and $\\hat{e_t}$).\n", "4. Solve the problems 1.13, 1.15, and 1.16 from the Rade's book." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## References\n", "\n", "+ Ruina A, Rudra P (2019) [Introduction to Statics and Dynamics](http://ruina.tam.cornell.edu/Book/index.html). Oxford University Press. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "hide_input": false, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "nbTranslate": { "displayLangs": [ "pt" ], "hotkey": "alt-t", "langInMainMenu": true, "sourceLang": "en", "targetLang": "pt", "useGoogleTranslate": true }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }