{
"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",
""
]
},
{
"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
}