{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "da9de96a", "metadata": { "slideshow": { "slide_type": "skip" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "from IPython.display import HTML\n", "\n", "plt.rcParams[\"figure.figsize\"] = [5, 3.1]" ] }, { "cell_type": "markdown", "id": "867e66a9", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Today: Introduction to dynamic problems\n", "\n", "Tom Ranner" ] }, { "cell_type": "code", "execution_count": null, "id": "2f62b416", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "import qrcode\n", "\n", "\n", "def _vevox():\n", " # TODO read once we have new feedback link\n", " FEEDBACK_URL = \"https://vevox.app/#/m/121658605\"\n", " qr = qrcode.make(FEEDBACK_URL)\n", "\n", " plt.title(\"Vevox.app ID: 121-6580695\")\n", " plt.imshow(qr, cmap=\"Greys_r\")\n", " plt.axis(\"off\")\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "\n", "_vevox()" ] }, { "cell_type": "markdown", "id": "132156e7", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# Static vs dynamic problems\n", "\n", "Examples so far have focussed on **static** problems that don't change in time:\n", "\n", "![Image showing sample temperature and relations in a room](../_images/temperature.svg)" ] }, { "cell_type": "markdown", "id": "66b95a80", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Static vs dynamic problems\n", "\n", "There are many other problems that require models to change in time, that is the models are **dynamic**:" ] }, { "cell_type": "code", "execution_count": null, "id": "324385ca", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "html = \"\"\"\n", "\n", "\n", "\n", "\"\"\"\n", "HTML(html)" ] }, { "cell_type": "markdown", "id": "bc02e9d7", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Rates of change\n", "\n", "Suppose we know that a person is walking at *constant* 3 meters per second (m/s) - what does that mean?\n", "\n", "So how far will they travel in:\n", " - $0.1$ seconds?\n", " - $0.01$ seconds?\n", " - $0.001$ seconds?\n", " - $10^{-6}$ seconds?" ] }, { "cell_type": "markdown", "id": "7519f41d", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "What does this tell us about speed?\n", "\n", "$$\n", "\\text{Distance travelled} = \\text{speed} \\times \\text{time}\n", "$$\n", "That is,\n", "$$\n", "\\text{speed} = \\dfrac{\\text{distance travelled}}{\\text{time}}\n", "$$\n", "\n", "Equivalently, \n", "$$\n", "\\text{speed} = \\dfrac{(\\text{distance at end}) - (\\text{distance at start})}{\\text{time}}.\n", "$$" ] }, { "cell_type": "markdown", "id": "0b177ce2", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The derivative as a rate of change\n", "\n", "What if the object's speed was not constant? For example, $S(t) = -(t-1.0)(t+0.5)$." ] }, { "cell_type": "code", "execution_count": null, "id": "41ff5ecb", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "t = np.linspace(0, 1)\n", "\n", "\n", "def S(t):\n", " return -(t - 1.0) * (t + 0.5)\n", "\n", "\n", "s = S(t)\n", "plt.plot(t, s)\n", "\n", "plt.title(\"an object's speed against time\")\n", "plt.xlabel(\"t: time (s)\")\n", "plt.ylabel(\"s(t): speed (m/s)\")\n", "plt.grid()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "6d5a9b4a", "metadata": {}, "source": [ "How far would the object travel in one second now? -- with difficulty :(" ] }, { "cell_type": "markdown", "id": "1af85644", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We could consider each tenth of a second separately and estimate the distance covered at each tenth (assuming the $s$ is approximately constant in each interval):" ] }, { "cell_type": "code", "execution_count": null, "id": "72c3f21b", "metadata": {}, "outputs": [], "source": [ "D, t = 0.0, 0.0\n", "for i in range(10):\n", " D = D + 0.1 * S(t)\n", " t = t + 0.1" ] }, { "cell_type": "code", "execution_count": null, "id": "e220fe45", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "tt = np.linspace(0, 1)\n", "\n", "\n", "def S(t):\n", " return -(t - 1.0) * (t + 0.5)\n", "\n", "\n", "ss = S(tt)\n", "\n", "plt.plot(tt, ss, label=\"exact\")\n", "\n", "for N in [10]:\n", " dt = 1.0 / N\n", "\n", " t = [0.0]\n", " s = [S(0.0)]\n", "\n", " for i in range(N):\n", " t.append(t[-1] + dt)\n", " s.append(s[-1])\n", " t.append(t[-1])\n", " s.append(S(t[-1]))\n", "\n", " plt.plot(t, s, label=f\"{N} steps\")\n", "\n", "plt.title(\n", " \"an object's speed assuming $S(t)$ approximately constant in each interval time\"\n", ")\n", "plt.xlabel(\"t: time (s)\")\n", "plt.ylabel(\"s(t): speed (m/s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "cc861052", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We could consider each hundredth of a second separately and estimate the distance covered at each hundredth (assuming the $s$ is approximately constant in each interval):" ] }, { "cell_type": "code", "execution_count": null, "id": "366f4b5f", "metadata": {}, "outputs": [], "source": [ "D, t = 0.0, 0.0\n", "for i in range(100):\n", " D = D + 0.01 * S(t)\n", " t = t + 0.01" ] }, { "cell_type": "code", "execution_count": null, "id": "1b676a5b", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "tt = np.linspace(0, 1)\n", "\n", "\n", "def S(t):\n", " return -(t - 1.0) * (t + 0.5)\n", "\n", "\n", "ss = S(tt)\n", "\n", "plt.plot(tt, ss, label=\"exact\")\n", "\n", "for N in [10, 100]:\n", " dt = 1.0 / N\n", "\n", " t = [0.0]\n", " s = [S(0.0)]\n", "\n", " for i in range(N):\n", " t.append(t[-1] + dt)\n", " s.append(s[-1])\n", " t.append(t[-1])\n", " s.append(S(t[-1]))\n", "\n", " plt.plot(t, s, label=f\"steps {N}\")\n", "\n", "plt.title(\n", " \"an object's speed assuming $S(t)$ approximately constant in each interval time\"\n", ")\n", "plt.xlabel(\"t: time (s)\")\n", "plt.ylabel(\"s(t): speed (m/s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "cfd1b437", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We could consider each thousandth of a second separately and estimate the distance covered at each thousandth (assuming the $s$ is approximately constant in each interval):" ] }, { "cell_type": "code", "execution_count": null, "id": "341050ea", "metadata": {}, "outputs": [], "source": [ "D, t = 0.0, 0.0\n", "for i in range(1000):\n", " D = D + 0.001 * S(t)\n", " t = t + 0.001" ] }, { "cell_type": "code", "execution_count": null, "id": "59b34f8b", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "tt = np.linspace(0, 1)\n", "\n", "\n", "def S(t):\n", " return -(t - 1.0) * (t + 0.5)\n", "\n", "\n", "ss = S(tt)\n", "\n", "plt.plot(tt, ss, label=\"exact\")\n", "\n", "for N in [10, 100, 1000]:\n", " dt = 1.0 / N\n", "\n", " t = [0.0]\n", " s = [S(0.0)]\n", "\n", " for i in range(N):\n", " t.append(t[-1] + dt)\n", " s.append(s[-1])\n", " t.append(t[-1])\n", " s.append(S(t[-1]))\n", "\n", " plt.plot(t, s, label=f\"steps {N}\")\n", "\n", "plt.title(\n", " \"an object's speed assuming $S(t)$ approximately constant in each interval time\"\n", ")\n", "plt.xlabel(\"t: time (s)\")\n", "plt.ylabel(\"s(t): speed (m/s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "abd683cd", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### What values do we get?" ] }, { "cell_type": "code", "execution_count": null, "id": "883c8a7c", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "headers = [\"# intervals\", \"increment size dt\", \"total distance\"]\n", "data = []\n", "\n", "for j in range(1, 6):\n", " n = 10**j\n", " dt = 1.0 / n\n", "\n", " D, t = 0.0, 0.0\n", " for i in range(n):\n", " D = D + dt * S(t)\n", " t = t + dt\n", "\n", " data.append([n, dt, D])\n", "\n", "df = pd.DataFrame(data, columns=headers)\n", "df.style.set_caption(\"Total distance as a function of number of steps\")" ] }, { "cell_type": "markdown", "id": "1fab7c0a", "metadata": {}, "source": [ "... we appear to be converging to an answer in the limit as $\\mathrm{d}t \\to 0$..." ] }, { "cell_type": "markdown", "id": "652af1c3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## So what's going on\n", "\n", "At any *instant* of time, the speed is the rate of change in distance:\n", "\n", "$$\n", "\\text{speed} = \\dfrac{\\text{change in distance}}{\\text{time}}\n", "$$\n", "\n", "so\n", "\n", "$$\n", "\\text{change in distance} = \\text{time} \\times \\text{speed}\n", "$$" ] }, { "cell_type": "markdown", "id": "004d0a5f", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Mathematically speaking\n", "\n", "Call the speed $S(t)$ and distance $D(t)$:\n", "\n", "$$\n", "S(t) = \\frac{D(t + \\mathrm{d}t) - D(t)}{\\mathrm{d}t}\n", "$$\n", "\n", "In fact, to obtain a *converged* answer, we must take smaller and smaller choices for $\\mathrm{d}t$:\n", "\n", "$$\n", "S(t) = \\lim_{\\mathrm{d}t \\to 0} \\frac{D(t + \\mathrm{d}t) - D(t)}{\\mathrm{d}t}\n", "$$\n", "\n", "We say that speed, $S(t)$, is the **derivative** of distance, $D(t)$, with respect to time and write $S(t) = D'(t)$. " ] }, { "cell_type": "markdown", "id": "ccc1daf4", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# A graphical interpretation" ] }, { "cell_type": "code", "execution_count": null, "id": "d28f98f2", "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "def D(t):\n", " return -(t**3) / 3 + t**2 / 4 + t / 2\n", "\n", "\n", "def S(t):\n", " return -(t - 1.0) * (t + 0.5)\n", "\n", "\n", "t = np.linspace(0, 1)\n", "plt.plot(t, S(t), label=\"Speed\")\n", "plt.plot(t, D(t), label=\"Distance\")\n", "\n", "plt.title(\"Distance and speed as functions of time\")\n", "plt.xlabel(\"t: time (s)\")\n", "plt.legend()\n", "plt.grid()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "37392b71", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We see the **gradient** (slope) of the orange curve is the **value** of the blue curve." ] }, { "cell_type": "markdown", "id": "6a8824a6", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The derivative as a gradient\n", "\n", "What is the gradient of a line?" ] }, { "cell_type": "code", "execution_count": null, "id": "3b51644f", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "def plot_slope(a, b):\n", " plt.plot([0, a, a, 0], [0, 0, b, 0], \"k\")\n", "\n", " plt.text(a / 2, -0.4, f\"{a}\", fontsize=\"xx-large\")\n", " plt.text(a + 0.1, b / 2, f\"{b}\", fontsize=\"xx-large\")\n", "\n", " plt.axis(\"square\")\n", " plt.axis(\"off\")\n", "\n", "\n", "plt.subplot(131)\n", "plot_slope(2, 1)\n", "\n", "plt.subplot(132)\n", "plot_slope(2, 2)\n", "\n", "plt.subplot(133)\n", "plot_slope(1, 2)\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "e0bde42c", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The equation of a straight line with slope $m$ is given by\n", "\n", "$$\n", "y(t) = m t + c.\n", "$$" ] }, { "cell_type": "markdown", "id": "4c84fbfc", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Slope of a curve\n", "\n", "What is the gradient of a *curve*?\n", "\n", "Well... the gradient of the straight-line approximation (chord) for a small step is\n", "\n", "$$\n", "\\frac{y(t + \\mathrm{d}t) - y(t)}{\\mathrm{d}t}.\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "id": "81d0f2cd", "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "def f(x):\n", " return np.exp(-(x**2))\n", "\n", "\n", "def plot(dt=1.0):\n", " t = np.linspace(-2, 2, 200)\n", " plt.plot(t, f(t))\n", "\n", " plt.plot([0, 0, -2], [0, f(0), f(0)], \"--\")\n", " plt.plot([dt, dt, -2], [0, f(dt), f(dt)], \"--\")\n", "\n", " slope = (f(dt) - f(0)) / dt\n", " plt.plot([0, dt], [f(0), f(dt)], label=f\"{slope=:.1f}\")\n", "\n", " plt.xticks([0, dt], [\"t\", \"t + dt\"])\n", " plt.yticks([f(0), f(dt)], [\"f(t)\", \"f(t + dt)\"])\n", "\n", " plt.legend()\n", " plt.show()\n", "\n", "\n", "plot(1.0)" ] }, { "cell_type": "markdown", "id": "f4717adf", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "What about reducing $\\mathrm{d}t$?" ] }, { "cell_type": "code", "execution_count": null, "id": "fba7ab56", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "plot(0.5)" ] }, { "cell_type": "markdown", "id": "ffc51b91", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Even more?" ] }, { "cell_type": "code", "execution_count": null, "id": "cfa881f0", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "plot(0.25)" ] }, { "cell_type": "markdown", "id": "4c3dc327", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "By taking smaller and smaller values of $\\mathrm{d}t$, it becomes clear that we can assign an instantaneous value to the slope at any point $t$:\n", "\n", "$$\n", "\\lim_{\\mathrm{d}t \\to 0} \\frac{y(t+\\mathrm{d}t) - y(t)}{\\mathrm{d}t}.\n", "$$\n", "\n", "*But this is precisely the definition of derivative $y'(t)$!*" ] }, { "cell_type": "markdown", "id": "d1a1df37", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Do you feel more confident?" ] }, { "cell_type": "code", "execution_count": null, "id": "81d51d82", "metadata": { "tags": [ "remove-input" ] }, "outputs": [], "source": [ "_vevox()" ] } ], "metadata": { "kernelspec": { "display_name": "comp2421-book", "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.12.6" } }, "nbformat": 4, "nbformat_minor": 5 }