Bis jetzt sind wir: Anton und Philipp. Idee: Position von Körpern des Sonnensystems vorhersagen. Ziel: a) die nächste Mondfinsternis berechnen alternativ, falls das zu schwer ist b) berechnen, wann andere Planeten von der Erde aus sichtbar sind c) berechnen, wann man von wo die ISS sieht spontane Inspirationen: [[https://de.wikipedia.org/wiki/Mondfinsternis#Schwierigkeiten_der_Vorausberechnung]] [[https://de.wikipedia.org/wiki/Mondfinsternis#Schwierigkeiten_der_Vorausberechnung]] [[http://www.diesonnenseite.de/startseite2/finsternisse_allg/berechnungen_zur_mondfinsternis/pdf/mond.pdf ]] [[ws1516:himmelskoerper:Protokoll]] **Grundlagen des Projekts** In diesem Labor soll versucht werden eine Mondfinsternis so akkurat wie möglich vorherzusagen. Um dies zu Erreichen soll das System Erde-Sonne-Mond mittels einer Python Simulation berechnet werden um so die relative Positionen dieser Himmelskörper zu jedem Zeitpunkt zu ermitteln. Dabei müssen die zugrunde liegenden Differentialgleichungen gelöst werden und daraufhin geprüft werden ob die neu errechneten Positionen die Kriterien für eine Mondfinsternis erfüllen. **Differentialgleichungen** Differentialgleichung sind Gleichungen, die nicht einen Wert als Unbekannte haben sondern eine Funktion. So ist in unserem Fall die Veränderung der Geschwindigkeit über die Zeit von der Beschleunigung abhängig. Von der Geschwindigkeit ist nun wieder die Veränderung der Position abhängig. Also müssen wir in jeden Zeitschritt zwei Differentialgleichungen lösen. Da Differentialgleichung in den meisten und auch in unserem Fall nicht analytisch exakt lösbar sind muss hier ein numerisches Verfahren angewendet werden. Das heißt, dass ein Algorithmus benötigt wird der in jedem Zeitschritt immer den direkt folgenden Wert aus dem Ursprungswert berechnet. Dies kann man durch verschiedene Verfahren bewerkstelligen, wir haben in der eigentlichen Simulation das Runge-Kutta Verfahren 4.Ordnung genutzt. Zur Übung haben wir aber auch des einfachere, aber ungenauere Euler Verfahren implementiert Im Euler Verfahren wird grundlegend die Ausgangsfunktion genommen und mit dem Zeitschritt multipliziert und das Ergebnis auf den Ausgangswert aufaddiert. Das Runge-Kutta Verfahren 4.Ordung hingegen splittet die Gleichung zunächst in 4 Differenzenquotienten aufgeteilt und diese anschließen zusammenaddiert. Sie erfordert einen höheren Rechenaufwand bietet bei gleichem Zeitschritt aber ein deutlich genaueres Ergebnis. Hier wird die Differentialgleichung x' = x mit den beiden Verfahren im Intervall 0-3,5 und dt = 0,175 mit den beiden Verfahren gelöst. Dies hat als analytische Lösung die bekannt e-Funktion und so lässt sich leicht die Genauigkeit überprüfen. import numpy as np import matplotlib.pyplot as plt def euler (f, startwert, intervallende, anzahlschritte, x): # Euler Verfahren h = (intervallende - startwert)/anzahlschritte # berechnet den Zeitschritt abhängig von der den Anzahl der Schritte und dem Intervall tpoints2 = np.linspace(startwert, intervallende, anzahlschritte) # legt die Werte der x-Achse fest. teilt das Intervall in gleich große Schritte auf xpoints2 = [] # Liste für die Funktionswerte for t in tpoints2: xpoints2.append(x) # erweitert xliste in jedem Schritt um den jeweils nächsten x-Wert x += h * f(t,x) # berechnet den neuen Funktionswert nach Euler return tpoints2, xpoints2 def rk4(f, startwert, intervallende, anzahlschritte, x): # Runge-Kutta-Verfahren 4.Ordnung h = (intervallende - startwert)/anzahlschritte # genau wie bei Euler tpoints = np.linspace(startwert, intervallende, anzahlschritte) xpoints = [] for t in tpoints: xpoints.append(x) k1 = h*f(t,x) # berechnet die Teilfunktionen nach Runge-Kutta k2 = h*f(t+0.5*k1,x+0.5*h) k3 = h*f(t+0.5*k2,x+0.5*h) k4 = h*f(t+k3,x+h) x += (k1+2*k2+2*k3+k4)/6 # fasst die 4 Teilfunktionen zusammen und berechnet neuen Funktionswert return tpoints, xpoints def f(t, x): # Funktion x' = x return x vt, vx = rk4(f, 0., 3.5, 20, 1.) # legt Intervall, Anzahl der Schritte und Ausgangswert fest vx1, vt1 = euler (f, 0., 3.5, 20, 1.) plt.plot(vx1, vt1) plt.show() # zeigt das geplottete Ergebnis für Euler plt.plot(vt, vx) plt.show() # zeigt das geplottete Ergebnis für Runge-Kutta 4.Ordnung Euler: {{:ws1516:figure_1.png?400|}} Hier erreicht die Funktion bei x = 1 den Funktionswert 2,4 was noch deutlich vom korrekten Wert e = 2,71... abweicht. Runge-Kutta 4.Ordnung: {{:ws1516:figure_2.png?400|}} Hier erreicht die Funktion bei x = 1 einen Funktionswert von 2,52 was deutlich näher an dem gesuchten Wert liegt. **Vpython** Um eine graphische Ausgabe zu erhalten haben wir mit der Python Erweiterung VPython gearbeitet. In dieser Erweiterung ist eine Vektorklasse implementiert die in einem 3D-Modul Objekten Positionen, Form, Farbe etc übergibt und dieses dann darstellt. Als Übung haben wir zunächst ein kleines Programm mit sich statisch bewegenden Kugeln geschrieben. from visual import * import numpy as np floor = box (pos=(0,0,0), length=50, height=0.5, width=4, color=color.blue) ball = sphere (pos=(0,4,0), radius=1, color=color.red) # Ball wird erzeugt ball.velocity = vector(5,-1,0) # Geschwindigkeit des Balls wird festgelegt dt = 0.01 wall_left= box (pos= (25,5,0), length=1, height=10, widht=4, color=color.blue) # Begrenzungen werden festgelegt wall_right= box (pos= (-25,5,0), length=1, height=10, widht=4, color=color.blue) schnee=[] # List mit diversen kleinen "Schneekugeln" for i in range (5): schnee.append(sphere(pos= ((-25-25)*np.random.rand()+25,10,0) , radius=0.1 , color=color.white)) # Position wird partiell zufaellig erzeugt for flocke in schnee: flocke.velocity= vector (0.,-1.,0.) # Geschwindigkeit wird für jede Schneeflocke festgelegt flocke.timer=1 while 1: # Simulation läuft endlos rate (100) # 100 Schleifendurchläufe werden pro Sekunde durchgeführt ball.pos = ball.pos + ball.velocity*dt # Position des Balls wird nach Euler geupdated if ball.y < ball.radius: ball.velocity.y = abs(ball.velocity.y) else: ball.velocity.y = ball.velocity.y - 9.8*dt # Verhalten des Balls im an den Rändern der erzeugten Box wird festgelegt if ball.x > 25-ball.radius: ball.velocity.x = -(ball.velocity.x) if ball.x < -25+ball.radius: ball.velocity.x = -(ball.velocity.x) if len(schnee)>0 and schnee[-1].y < 9: # Berechnung der Schneeflocken for i in range (5): schnee.append(sphere(pos= ((-25-25)*np.random.rand()+25,10,0) , radius=0.1 , color=color.white)) schnee[-1].velocity=vector (0,-1,0) schnee[-1].timer=1 zu_loeschend=[] for i,flocke in enumerate(schnee): #flocke.velocity= vector (0,-5,0) flocke.pos= flocke.pos+flocke.velocity*dt flocke.timer=flocke.timer+1 if flocke.y < flocke.radius+0.18: # legt fest wenn die Scheeflocke den "Boden" erreicht hat flocke.velocity=vector(0.,0.,0.) else: flocke.velocity= vector (0.,-1.,0.) if flocke.timer > 500: # loescht Schneeflocken wenn ihre Anzahl 500 übersteigt zu_loeschend.append(i) schnee_neu=[ f for (i,f) in enumerate(schnee) if i not in zu_loeschend] **Simulation des Sonnensystems** Um das S