From 500b41c95fdc832bf77c8cffdf3886b95ed1ee44 Mon Sep 17 00:00:00 2001 From: sschuma Date: Thu, 12 Jul 2018 07:56:09 +0200 Subject: [PATCH] add new example: double pendulum --- AM18_ex4.ipynb | 577 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 577 insertions(+) create mode 100644 AM18_ex4.ipynb diff --git a/AM18_ex4.ipynb b/AM18_ex4.ipynb new file mode 100644 index 0000000..0393b9b --- /dev/null +++ b/AM18_ex4.ipynb @@ -0,0 +1,577 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Doppelpendel\n", + "\n", + "\n", + "In der Vorlesung habt ihr das Doppelpendel als Beispiel für ein System mit holonom-skleronomen Zwangsbedingungen kennengelernt.\n", + "Dieses Pendel zeigt chaotisches Verhalten und seine Bewegungsgleichungen sind nur unter Einschränkung (Kleinwinkelnäherung) analytisch lösbar.\n", + "\n", + "In diesem Notebook wollen wir die analytische Lösung mit der numerischen vergleichen, um uns die Limitierung der Kleinwinkelnäherung zu verdeutlichen und das Verhalten des Pendels jenseits dieser Einschränkung zu erforschen.\n", + "\n", + "\n", + "## Bewegungsgleichungen\n", + "\n", + "(siehe https://de.wikipedia.org/wiki/Doppelpendel)\n", + "\n", + "\n", + "Wenn $l_1$ und $l_2$ die Längen der (masselosen) Verbindungsstangen,$m_1$ und $m_2$ die Pendelmassen, $\\theta_1, \\theta_2$ die Auslenkung vom Lot und $g$ die Erdbeschleunigung bezeichnet, dann findet man für die Positionen von $m_1 $ und $m_2 $:\n", + "\n", + "\\begin{align}\n", + "x_1 &= l_1 \\sin(\\theta_1)\\\\\n", + "y_1 &= -l_1 \\cos(\\theta_1)\n", + "\\end{align}\n", + "\n", + "\\begin{align}\n", + "x_2 &= l_1 \\sin(\\theta_1) + l_2 \\sin(\\theta_2)\\\\\n", + "y_2 &= -l_1 \\cos(\\theta_1) -l_2 \\cos(\\theta_2)\n", + "\\end{align}\n", + "\n", + "Damit lassen sich die Geschwindigkeiten der Massen, welche für den nächsten Schritt notwendig sind, bestimmen, wobei $\\dot{\\theta_1}$ die zeitliche Ableitung von $\\theta_1 $ ist:\n", + "\n", + "\\begin{align}\n", + "u_1 &= \\frac{\\partial x_1}{\\partial t} = \\dot{\\theta_1} l_1 \\cos(\\theta_1)\\\\\n", + "v_1 &= \\frac{\\partial y_1}{\\partial t} = \\dot{\\theta_1} l_1 \\sin(\\theta_1)\n", + "\\end{align}\n", + "\n", + "und\n", + "\n", + "\\begin{align}\n", + "u_2 &= \\frac{\\partial x_2}{\\partial t} + u_1 = \\dot{\\theta_2} l_2 \\cos(\\theta_2) + u_1\\\\\n", + "v_2 &= \\frac{\\partial y_2}{\\partial t} + v_1 = \\dot{\\theta_2} l_2 \\sin(\\theta_2) + v_1\n", + "\\end{align}\n", + "\n", + "Unter Verwendung des Lagrange-Formalismus $L = T - V$ wobei $T $ die kinetische Energie der beiden Pendelmassen und $V $ ihre potentielle Energie im konstanten Gravitationsfeld ist, mit\n", + "\n", + "\\begin{align}\n", + "T_1 &= \\frac{1}{2} m_1 (u_1^2 + v_1^2)\\\\\n", + "T_2 &= \\frac{1}{2} m_2 (u_2^2 + v_2^2)\\\\\n", + "V_1 &= m_1 g y_1\\\\\n", + "V_2 &= m_2 g y_2\n", + "\\end{align}\n", + "\n", + "erhält man\n", + "\n", + "\\begin{align}\n", + "T &= T_1 + T_2 = \\frac{1}{2} m_1\\dot{\\theta_1^2} l_1^2+ \\frac{1}{2} \\left(m_2 \\dot{\\theta_2^2} l_2^2 + m_2 \\dot{\\theta_1^2} l_1^2 + 2 m_2 \\dot{\\theta_1} l_1 \\dot{\\theta_2} l_2 \\cos(\\theta_1 - \\theta_2)\\right)\\\\\n", + "V &= V_1 + V_2 = -m_1 g l_1 \\cos(\\theta_1) -m_2 g l_1 \\cos(\\theta_1) - m_2 g l_2 \\cos(\\theta_2)\n", + "\\end{align}\n", + "\n", + "Damit ergibt sich für die Lagrange-Funktion dann\n", + "\n", + "\n", + "\\begin{align}\n", + "L &= \\frac{1}{2} (m_1 + m_2) \\dot{\\theta_1}^2 l_1^2 + \\frac{1}{2} m_2 \\dot{\\theta_2}^2 l_2^2 + m_2 \\dot{\\theta_1} l_1 \\dot{\\theta_2} l_2 \\cos(\\theta_1 - \\theta_2) + (m_1 + m_2) g l_1 \\cos(\\theta_1) + m_2 g l_2 \\cos(\\theta_2)\n", + "\\end{align}\n", + "\n", + "\n", + "\n", + "\n", + "Unter Verwendung der Euler-Lagrange-Gleichung\n", + "\n", + "\\begin{align}\\frac{\\mathrm d}{\\mathrm dt} \\frac{\\partial L}{\\partial \\dot{\\theta_i}} - \\frac{\\partial L}{\\partial \\theta_i} = 0\\end{align}\n", + "\n", + "erhält man damit nach einigen Umformungen\n", + "\n", + "\n", + "\\begin{equation}\n", + "\\ddot{\\theta_1} = -\\frac{m_2}{m_1 + m_2} \\frac{l_2}{l_1} (\\ddot{\\theta_2} \\cos(\\theta_1 - \\theta_2) + \\dot{\\theta_2^2} \\sin(\\theta_1 - \\theta_2)) - \\frac{g}{l_1} \\sin(\\theta_1)\\end{equation}\n", + "\n", + "$$\\ddot{\\theta_2} = - \\frac{l_1}{l_2} (\\ddot{\\theta_1} \\cos(\\theta_1 - \\theta_2) - \\dot{\\theta_1^2} \\sin(\\theta_1 - \\theta_2)) - \\frac{g}{l_2} \\sin(\\theta_2)$$\n", + "\n", + "\n", + "\n", + "Die Bewegungsgleichungen für die generalisierten Koordinaten $\\theta_{1}$ und $\\theta_{2}$ stellen ein nichtlineares System von zwei gekoppelten Differentialgleichungen dar, welches analytisch nicht lösbar ist. Es kann bei vier bekannten Anfangswerten ($\\theta_1, \\theta_2, \\dot{\\theta_1}, \\dot{\\theta_2} $) mit numerischen Verfahren gelöst werden. Hierbei werden also die anfänglichen Auslenkungen (z.Bsp. ''30°'' und ''30°'') und die anfänglichen Geschwindigkeiten (z.Bsp. 0 $\\frac{rad}{s}$) eingegeben und damit dann die Evolution des Pendels berechnet.\n", + "\n", + "Eine detaillierte Herleitung der Bewegunsgleichung in der Kleinwinkelnäherung findet ihr unter: https://www.math24.net/double-pendulum/.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Importieren der benötigten Bibliotheken" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named 'scipy'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\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 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmatplotlib\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0manimation\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mIPython\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdisplay\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mHTML\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mImage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mscipy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconstants\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpi\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\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[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msin\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcos\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msqrt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named 'scipy'" + ] + } + ], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from matplotlib import animation, rc\n", + "from IPython.display import HTML, display, Image\n", + "from scipy.constants import pi,g \n", + "import numpy as np\n", + "from numpy import sin, cos, sqrt\n", + "import scipy.integrate as integrate" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Bild zur Veranschaulichung (from JabberWok via Wikimedia Commons)\n", + "Image(url='https://upload.wikimedia.org/wikipedia/commons/7/78/Double-Pendulum.svg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Eingabe unserer Systemgrößen und Startbedingungen\n", + "\n", + "An dieser Stelle kann man mit den verschiedensten Werten experimentieren, um zu sehen ob unsere Numerische Integration von der Lösung mit Hilfe der Kleinwinkelnäherung abweicht.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dt = 0.05 #Zeitschritt\n", + "t = np.arange(0.0, 20, dt) # Array mit Zeitschritten von t=0....20s\n", + "\n", + "# Anfangswerte für numerische Lösung: Winkel th und Winkelgeschwindikeiten w\n", + "th1 = 20.00 #30, 180, 90 \n", + "w1 = 0.0\n", + "th2 = 30.0 # 180,60\n", + "w2 = 0.0\n", + "\n", + "\n", + "# Längen und Massen für das Pendel\n", + "\n", + "l= l1 = l2 =1.0 # Länge Pendel 1 und 2 in m (für die Kleinwinkelnäherung wurden gleiche Längen angenommen)\n", + "m1 = 5.0 # mass of pendulum 1 in kg\n", + "m2 = 1.0 # mass of pendulum 2 in kg" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Definition unserer Funktionen zum Lösen unserer Bewegunsgleichungen\n", + "### Kleinwinkelnäherung\n", + "Aus unseren Bewegunsgleichungen\n", + "\n", + "$$(m_1+m_2)l_1^2 \\ddot\\theta_1 + m_2 l_1 l_2 \\ddot\\theta_2\\cos(\\theta_1 -\\theta_2)+m_2 l_1 l_2\\dot\\theta_2^2\\sin(\\theta_1-\\theta_2)+(m_1+m_2)gl_1\\sin(\\theta_1)=0 $$\n", + "\n", + "\n", + "$$ m_2l_2^2 \\ddot\\theta_2 + m_2 l_1 l_2 \\dot\\theta_1\\cos(\\theta_1 -\\theta_2)+m_2 l_1 l_2\\dot\\theta_1^2\\sin(\\theta_1-\\theta_2)+m_2 gl_2\\sin(\\theta_2)=0$$\n", + "\n", + "können wir wir durch die Annahme, dass ausschließlich kleine Auslenkungswinkel vorherschen folgende Näherungen treffen:\n", + "\n", + "\n", + "$\\sin(\\theta)\\approx\\theta)$,$\\cos(\\theta)\\approx1$,$\\sin(\\theta_1-\\theta_2)\\approx 0$,$\\sin(\\theta_1-\\theta_2)\\approx1$\n", + "\n", + "So erhalten wir nach kürzen\n", + "\n", + "$$(m_1+m_2)l_1 \\ddot\\theta_1 + m_2 l_2 \\ddot\\theta_2+(m_1+m_2)g\\theta_1=0 $$\n", + "\n", + "\n", + "$$ l_2 \\ddot\\theta_2 + l_1 \\dot\\theta_1+ g\\theta_2=0$$\n", + "\n", + "Dieses System von Differentialgleichungen können wir nun lösen und erhalten unter der Anahme, dass $l_1=l_2=l$$$$$\n", + "und Einführen von $\\mu=\\frac{m_2}{m_1}$ unsere charakteristischen Frequenzen\n", + "\n", + "\n", + "$\\omega_{1,2}^2=\\frac{g}{l}\\cdot(1\\pm\\mu+\\sqrt{(1+\\mu)\\cdot\\mu})$$$$$\n", + "\n", + "und die von den Startbedinungen abhängigen Bewegungsgleichungen\n", + "\n", + "\n", + "$\\theta_1(t)=C1\\cdot cos(\\omega_1 t +\\phi_1)+C_2cos(\\omega_2t+\\phi_2)$$$$$\n", + "\n", + "$\\theta_2(t)=C1\\cdot-\\sqrt{\\frac{1+\\mu}{\\mu}}\\cdot cos(\\omega_1 t +\\phi_1)+C_2\\cdot-\\sqrt{\\frac{1+\\mu}{\\mu}} \\cdot cos(\\omega_2t+\\phi_2)$$$$$\n", + "\n", + "Durch Lösen des Gleichungssystems für t=0 mit den gestzen Startwinkeln lassen sich die Konstanten $C_1$ und $C_2$ bestimmen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mu=m2/m1 # Verhältnis der Massen\n", + "mu_=sqrt((1+mu)/mu)\n", + "phi1=phi2=0 # Start-Phasen=0 \n", + "\n", + "# Kleinwinkelnäherung charakteristische frequenzen (siehe Herleitung)\n", + "aw1=sqrt(g/l)*sqrt(1+mu+sqrt((1+mu)*mu))\n", + "aw2=sqrt(g/l)*sqrt(1+mu-sqrt((1+mu)*mu))\n", + "\n", + "\n", + "\n", + "#Bestimmten der Vorfaktoren für die Bewegungsgleichung der Kleinwinkelnäherung\n", + "# np.radians()? # Umwandlung in Bogenmaß\n", + "C1 = np.radians(th1)/2-np.radians(th2)/(2*mu_)\n", + "C2 = np.radians(th1)/2+np.radians(th2)/(2*mu_)\n", + "\n", + "# Funktion für die Bewegungsgleichung in der Kleinwinkelnäherung\n", + "def theta_t(time):\n", + " theta1=C1*cos(aw1*time+phi1)+C2*cos(aw2*time+phi2)\n", + " theta2=C1*(-mu_)*cos(aw1*time+phi1)+C2*mu_*cos(aw2*time+phi2)\n", + " return theta1, theta2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### System von Differentialgleichungen zur numerischen Integration\n", + "\n", + "(siehe https://matplotlib.org/gallery/animation/double_pendulum_sgskip.html)\n", + "\n", + "Durch Umformen unserer Bewegundgleichungen (ohne Kleinwinkelnäherung) können wir folgendes System von Differentialgleichugnen 1. Ordnung aufstellen:\n", + "\n", + "$\\dot\\theta_1=\\omega_1$\n", + "\n", + "\n", + "\n", + "$del = \\theta_2 - \\theta_1$ \n", + "\n", + "\n", + "$den1 = (m_1 + m_2)l_1 - m_2l_1\\cos^2(del)$\n", + "\n", + "\n", + "\n", + "\n", + " $\\ddot\\theta_1=\\frac{d}{dt}\\omega_1 =\\frac{ (m_2l_1\\omega_1^2\\cdot \\sin(del)\\cos(del) +\n", + " m_2g\\sin(\\theta_2)\\cos(del) +\n", + " m_2l_2\\omega_2^2\\sin(del) -\n", + " (m_1 + m_2)g\\sin(\\theta_1))}{den1}$\n", + " \n", + "$\\dot\\theta_2=\\omega_2$\n", + "\n", + "$den2 = \\frac{l_2}{l_1}\\cdot den1$\n", + "\n", + "\n", + "$\\ddot\\theta_2=\\frac{d}{dt}\\omega_2=\\frac{ (-m_2l_2\\omega_2^2\\sin(del)\\cos(del) +\n", + " (m_1 + m_2)g\\sin(\\theta_1)\\cos(del) -\n", + " (m_1 + m_2)l_1\\omega_1^2\\sin(del) -\n", + " (m_1 + m_2)g\\sin(\\theta_2))}{den2} $" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Initialisieren der Anfangswerte für das numerische Lösungsverfahren\n", + "state = np.radians([th1, w1, th2, w2])\n", + "\n", + "def derivs(state, t):\n", + " \n", + " dydx = np.zeros_like(state) #Vektor für die Winkel und Winkelgeschwindigkeiten\n", + " dydx[0] = state[1] # d/dt th_1=w1\n", + "\n", + " del_ = state[2] - state[0] \n", + " den1 = (m1 + m2)*l1 - m2*l1*cos(del_)*cos(del_)\n", + " dydx[1] = (m2*l1*state[1]*state[1]*sin(del_)*cos(del_) +\n", + " m2*g*sin(state[2])*cos(del_) +\n", + " m2*l2*state[3]*state[3]*sin(del_) -\n", + " (m1 + m2)*g*sin(state[0]))/den1 #d/dt w1\n", + " \n", + " dydx[2] = state[3] #d/dt th2=w2\n", + "\n", + " den2 = (l2/l1)*den1\n", + " dydx[3] = (-m2*l2*state[3]*state[3]*sin(del_)*cos(del_) +\n", + " (m1 + m2)*g*sin(state[0])*cos(del_) -\n", + " (m1 + m2)*l1*state[1]*state[1]*sin(del_) -\n", + " (m1 + m2)*g*sin(state[2]))/den2 # d/dt w2\n", + "\n", + " return dydx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lösen der Bewegungsgleichungen\n", + "\n", + "Um unsere Bewegungsgleichungen zu integrieren verwenden hier die scipy funktion integrate.odeint.\n", + "Diese benötigt das Gleichungssystem, die Startbedingungen und das Zeitintervall und liefert uns ein array mit den errechneten Werten für Winkel und Winkelgeschwindigkeiten im Eingabeformat zurück.\n", + "(In CWR werdet Algorithmen zum numerischen Integrieren von Differentialgleichungen kennen lernen und selber implementieren.)\n", + "\n", + "Unsere analytische Lösung in der Kleinwinkelnäherung erhalten wir durch aufrufen unserer vorher definierten Funktion theta_t." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Hilfe zur Funktion odeint: Auskommentieren für Anzeige\n", + "#integrate.odeint?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Numerische Lösung \n", + "# Der Returnvalue ist ein array der gleichen Form wie state[]\n", + "# (hat 4 spalten -->eine für jeden winkel bzw winkelgeschwindigkeite zu jedem t) \n", + "n_trj = integrate.odeint(derivs, state, t) \n", + "\n", + "# Analytzische Lösung Kleinwinkelnäherung\n", + "# der Rückgabewert unserer Funktion sind jeweils die beiden Winkel\n", + "# Durch Übergabe unseres Zeitarrays erhalten wir je ein Array von Werte für theta1 und theta2\n", + "ath1,ath2= theta_t(t)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Umwandeln in kartesische Koordinaten" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Funktion für die Umwandlung in kartesische Koordinaten\n", + "\n", + "def kart_coord(th1,th2):\n", + " x1 = l1*sin(th1) \n", + " y1 = -l1*cos(th1)\n", + "\n", + " x2 = l2*sin(th2) + x1\n", + " y2 = -l2*cos(th2) + y1\n", + " \n", + " return x1,y1,x2,y2\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Speichern der Kartesischen Koordinaten in arrays\n", + "# nx,ny --> numerische Lösung \n", + "nx1,ny1,nx2,ny2= kart_coord(n_trj[:, 0],n_trj[:,2]) # die Formulierung y[:,0] schneidet die zweite Spalte aus unserem Array y\n", + "# ax,ay --> analytische Lösung\n", + "ax1,ay1,ax2,ay2= kart_coord(ath1,ath2) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotten der Bewegung" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Wir wollen unsere Bewegung als vier Subplots der selben Figure plotten\n", + "# dazu verwenden wir plt.subplots, welches uns ein Tupel zurück liefert\n", + "# fig kann man verwenden um einstllungen auf \"globaler\" Ebene durchzuführen\n", + "# ax sind die Achsenobjekte und entsprechen unserern 4 Subplots\n", + "\n", + "# Verwendet man die Optionen sharex/sharey\n", + "# werden in allen plots die gleichen Achsenlimits gesetzt\n", + "fig, ax = plt.subplots(2,2, figsize=(12,10),sharex= 'col', sharey= 'col')\n", + "\n", + "# Im folgenden werden für jeden Subplot die Werte und Beschriftungen etc. gesetzt\n", + "ax[0,0].plot(nx1, ny1)\n", + "ax[0,1].plot(nx2, ny2)\n", + "ax[1,0].plot(ax1, ay1)\n", + "ax[1,1].plot(ax2, ay2)\n", + "ax[0,0].set(xlabel='x', ylabel='y',title='Bewegung m1 - Numerische Lösung')\n", + "ax[0,1].set(xlabel='x', ylabel='y',title='Bewegung m2 - Numerische Lösung')\n", + "ax[1,0].set(xlabel='x', ylabel='y',title='Bewegung m1 - Analytische Lösung')\n", + "ax[1,1].set(xlabel='x', ylabel='y',title='Bewegung m2 - Analytische Lösung')\n", + "ax[0,0].grid()\n", + "ax[0,1].grid()\n", + "ax[1,0].grid()\n", + "ax[1,1].grid()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(2, figsize=(12,10))\n", + "\n", + "ax[0].plot(t,ath1, label=\"small angle approx.\")\n", + "ax[1].plot(t,ath2, label=\"small angle approx.\")\n", + "ax[0].plot(t,n_trj[:, 0], label= \"numerical\")\n", + "ax[1].plot(t,n_trj[:, 2], label= \"numerical\")\n", + "ax[0].set(xlabel='t [s]', ylabel=r\"$\\theta_1(t) [rad]$\",title=r\"$\\theta_1$\")\n", + "ax[1].set(xlabel='t [s]', ylabel=r\"$\\theta_2(t) [rad]$\",title=r\"$\\theta_2$\")\n", + "for axes in ax:\n", + " axes.legend()\n", + " axes.grid()\n", + "\n", + "\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Erstellen einer Animation\n", + "\n", + "Um eine Animation zu erstellen geht man im Grunde vor die auch bei jedem anderen Plot. Allerdings wird nun eine Funktion benötigt die den Plot zu jedem errechneten Zeitpunkt neu erstellt:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax= plt.subplots(1,2, figsize=(12,5),sharey=True) # Wir Deklarieren unseren Plot mit zwei nebeneinander liegenden Subplots (plt.subplot? für Hilfe)\n", + "\n", + "# Eigenschaften der Subplots definieren:\n", + "# ax[0] soll unser chaotisches Pendel ausgeben und ax[1] unser Pendel mit Kleinwinkelnäherung\n", + "ax[0].set_xlim((-3,3))\n", + "ax[0].set_ylim((-3,3))\n", + "ax[0].grid() \n", + "ax[0].set(xlabel='x', ylabel='y',title='Pendelbewegung - Numerische Lösung')\n", + "\n", + "ax[1].set(xlabel='x', ylabel='y',title='Pendelbewegund - Analytische Lösung')\n", + "ax[1].set_xlim((-3,3))\n", + "ax[1].set_ylim((-3,3))\n", + "ax[1].grid() \n", + "\n", + "line1, = ax[0].plot([], [], 'o-', lw=7) # erzeugt verbindungslinie\n", + "line2, = ax[1].plot([], [], 'o-', lw=7) # erzeugt verbindungslinie\n", + "time_template = 'time = %.1fs' # erzeugt string template für zeit ausgabe\n", + "time_text = ax[0].text(0.05, 0.9, '', transform=ax[0].transAxes) # setzt position für Zeitangabe subplot ax[0]\n", + "\n", + "def init(): # Initialisieren der Animation mit leerem Frame\n", + " line1.set_data([], [])\n", + " line2.set_data([], [])\n", + " time_text.set_text('')\n", + " return line1, line2, time_text\n", + "\n", + "\n", + "def animate(i): # Animationsfunktion. Erzeugt Plots zu jedem Zeitpunkt in t\n", + " n_thisx = [0, nx1[i], nx2[i]] # Positionen Numerische Lösung\n", + " n_thisy = [0, ny1[i], ny2[i]]\n", + "\n", + " a_thisx = [0, ax1[i], ax2[i]] # Positionen Analytische Lösung\n", + " a_thisy = [0, ay1[i], ay2[i]]\n", + "\n", + " line1.set_data(n_thisx,n_thisy) # Setzt Verbindunglinien (Pendelleine)\n", + " line2.set_data(a_thisx,a_thisy) \n", + " time_text.set_text(time_template % (i*dt)) # Erzeugt Zeit-String\n", + "\n", + " return line1, line2, time_text \n", + "\n", + "# Erzeugt die Animation:\n", + "#animation.FuncAnimation?\n", + "ani = animation.FuncAnimation(fig, animate, np.arange(1, len(t)),interval=25, blit=True, init_func=init) \n", + "\n", + "# Verhindert Ausgabe des Plots (ohne Animation)\n", + "plt.close(ani._fig)\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Erstellen eines Videos\n", + "\n", + "Die einzelnen Frames die in der Variable ani gespeichert sind werden nun in ein HTML5-video umgewandelt.\n", + "Dies kann eine Weile dauern. Nicht die Gedult verlieren. :)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "HTML(ani.to_html5_video())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quellen" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://www.math24.net/double-pendulum/\n", + "https://itp.tugraz.at/LV/Analytische_Mechanik/node12.html#SECTION001255000000000000000\n", + "https://scipython.com/blog/the-double-pendulum/\n", + "https://matplotlib.org/gallery/animation/double_pendulum_sgskip.html\n", + "https://de.wikipedia.org/wiki/Doppelpendel\n", + "http://tiao.io/posts/notebooks/embedding-matplotlib-animations-in-jupyter-as-interactive-javascript-widgets/\n", + "https://matplotlib.org/gallery/subplots_axes_and_figures/subplots_demo.html" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}