Nur ein kleiner Disclaimer vorweg: Ich habe nie Astronomie oder irgendwelche exakten Wissenschaften (nicht einmal IT) studiert, also versuche ich, diese Lücke durch Selbststudium zu füllen. Astronomie ist einer der Bereiche, die meine Aufmerksamkeit erregt haben, und meine Vorstellung von Selbstbildung ist ein direkt angewandter Ansatz. Also, gleich auf den Punkt - dies ist ein Orbital-Simulationsmodell, an dem ich beiläufig arbeite, wenn ich Zeit / Laune habe. Mein Hauptziel ist es, ein komplettes Sonnensystem in Bewegung zu setzen und Raumschiffstarts zu anderen Planeten zu planen.
Es steht Ihnen allen frei, dieses Projekt jederzeit wieder aufzunehmen und viel Spaß beim Experimentieren!
aktualisieren!!! (November 10)
Grundsätzlich ist es jetzt möglich, ein Raumschiff von der Erdoberfläche zu "starten" und eine Mission zum Mond zu planen, indem deltaV-Vektorkorrekturen über giveMotion() vorgenommen werden. Als nächstes wird versucht, eine globale Zeitvariable zu implementieren, um eine gleichzeitige Bewegung zu ermöglichen, z. B. der Mond umkreist die Erde, während das Raumschiff ein Gravitationsunterstützungsmanöver ausprobiert.
Kommentare und Verbesserungsvorschläge sind jederzeit willkommen!
Fertig in Python3 mit Matplotlib-Bibliothek
import matplotlib.pyplot as plt
import math
plt.ion()
G = 6.673e-11 # gravity constant
gridArea = [0, 200, 0, 200] # margins of the coordinate grid
gridScale = 1000000 # 1 unit of grid equals 1000000m or 1000km
plt.clf() # clear plot area
plt.axis(gridArea) # create new coordinate grid
plt.grid(b="on") # place grid
class Object:
_instances = []
def __init__(self, name, position, radius, mass):
self.name = name
self.position = position
self.radius = radius # in grid values
self.mass = mass
self.placeObject()
self.velocity = 0
Object._instances.append(self)
def placeObject(self):
drawObject = plt.Circle(self.position, radius=self.radius, fill=False, color="black")
plt.gca().add_patch(drawObject)
plt.show()
def giveMotion(self, deltaV, motionDirection, time):
if self.velocity != 0:
x_comp = math.sin(math.radians(self.motionDirection))*self.velocity
y_comp = math.cos(math.radians(self.motionDirection))*self.velocity
x_comp += math.sin(math.radians(motionDirection))*deltaV
y_comp += math.cos(math.radians(motionDirection))*deltaV
self.velocity = math.sqrt((x_comp**2)+(y_comp**2))
if x_comp > 0 and y_comp > 0: # calculate degrees depending on the coordinate quadrant
self.motionDirection = math.degrees(math.asin(abs(x_comp)/self.velocity)) # update motion direction
elif x_comp > 0 and y_comp < 0:
self.motionDirection = math.degrees(math.asin(abs(y_comp)/self.velocity)) + 90
elif x_comp < 0 and y_comp < 0:
self.motionDirection = math.degrees(math.asin(abs(x_comp)/self.velocity)) + 180
else:
self.motionDirection = math.degrees(math.asin(abs(y_comp)/self.velocity)) + 270
else:
self.velocity = self.velocity + deltaV # in m/s
self.motionDirection = motionDirection # degrees
self.time = time # in seconds
self.vectorUpdate()
def vectorUpdate(self):
self.placeObject()
data = []
for t in range(self.time):
motionForce = self.mass * self.velocity # F = m * v
x_net = 0
y_net = 0
for x in [y for y in Object._instances if y is not self]:
distance = math.sqrt(((self.position[0]-x.position[0])**2) +
(self.position[1]-x.position[1])**2)
gravityForce = G*(self.mass * x.mass)/((distance*gridScale)**2)
x_pos = self.position[0] - x.position[0]
y_pos = self.position[1] - x.position[1]
if x_pos <= 0 and y_pos > 0: # calculate degrees depending on the coordinate quadrant
gravityDirection = math.degrees(math.asin(abs(y_pos)/distance))+90
elif x_pos > 0 and y_pos >= 0:
gravityDirection = math.degrees(math.asin(abs(x_pos)/distance))+180
elif x_pos >= 0 and y_pos < 0:
gravityDirection = math.degrees(math.asin(abs(y_pos)/distance))+270
else:
gravityDirection = math.degrees(math.asin(abs(x_pos)/distance))
x_gF = gravityForce * math.sin(math.radians(gravityDirection)) # x component of vector
y_gF = gravityForce * math.cos(math.radians(gravityDirection)) # y component of vector
x_net += x_gF
y_net += y_gF
x_mF = motionForce * math.sin(math.radians(self.motionDirection))
y_mF = motionForce * math.cos(math.radians(self.motionDirection))
x_net += x_mF
y_net += y_mF
netForce = math.sqrt((x_net**2)+(y_net**2))
if x_net > 0 and y_net > 0: # calculate degrees depending on the coordinate quadrant
self.motionDirection = math.degrees(math.asin(abs(x_net)/netForce)) # update motion direction
elif x_net > 0 and y_net < 0:
self.motionDirection = math.degrees(math.asin(abs(y_net)/netForce)) + 90
elif x_net < 0 and y_net < 0:
self.motionDirection = math.degrees(math.asin(abs(x_net)/netForce)) + 180
else:
self.motionDirection = math.degrees(math.asin(abs(y_net)/netForce)) + 270
self.velocity = netForce/self.mass # update velocity
traveled = self.velocity/gridScale # grid distance traveled per 1 sec
self.position = (self.position[0] + math.sin(math.radians(self.motionDirection))*traveled,
self.position[1] + math.cos(math.radians(self.motionDirection))*traveled) # update pos
data.append([self.position[0], self.position[1]])
collision = 0
for x in [y for y in Object._instances if y is not self]:
if (self.position[0] - x.position[0])**2 + (self.position[1] - x.position[1])**2 <= x.radius**2:
collision = 1
break
if collision != 0:
print("Collision!")
break
plt.plot([x[0] for x in data], [x[1] for x in data])
Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)
Moon = Object(name="Moon", position=(100.0, 100.0), radius=1.737, mass = 7.347e22) # position not to real scale
Craft = Object(name="SpaceCraft", position=(49.0, 40.0), radius=1, mass=1.0e4)
Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)
Craft.giveMotion(deltaV=2000.0, motionDirection=90, time=60000)
plt.show(block=True)
Wie es funktioniert
Es läuft alles auf zwei Dinge hinaus:
Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)
mit Parametern der Position auf dem Gitter (1 Einheit des Gitters ist standardmäßig 1000 km, aber dies kann auch geändert werden), Radius in Gittereinheiten und Masse in kg.Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)
offensichtlich erforderlich ist, um es Craft = Object(...)
zuerst zu erstellen, wie im vorherigen Punkt erwähnt. Die Parameter hier sind deltaV
in m/s (beachten Sie, dass die Beschleunigung momentan momentan ist), motionDirection
die Richtung von deltaV in Grad (stellen Sie sich von der aktuellen Position aus einen 360-Grad-Kreis um das Objekt vor, also ist die Richtung ein Punkt auf diesem Kreis) und schließlich time
ist der Parameter, wie viele Sekunden danach wird die deltaV-Push-Trajektorie des Objekts überwacht. Nachfolgender giveMotion()
Start von der letzten Position des vorherigen giveMotion()
.Fragen:
Grundsätzlich ist es mein Ziel, eine Diskussion über das Thema zu beginnen und zu sehen, wohin es führt. Und, wenn möglich, etwas Neues und Interessantes lernen (oder noch besser - lehren).
Fühlen Sie sich frei zu experimentieren!
Versuchen Sie es mit:
Earth = Object(name="Earth", position=(50.0, 100.0), radius=6.371, mass=5.972e24)
Moon = Object(name="Moon", position=(434.0, 100.0), radius=1.737, mass = 7.347e22)
Craft = Object(name="SpaceCraft", position=(43.0, 100.0), radius=1, mass=1.0e4)
Craft.giveMotion(deltaV=10575.0, motionDirection=180, time=322000)
Craft.giveMotion(deltaV=400.0, motionDirection=180, time=50000)
Mit zwei Zündungen - einer prograden auf der Erdumlaufbahn und einer rückläufigen auf der Mondumlaufbahn - erreichte ich eine stabile Mondumlaufbahn. Sind diese nahe an den theoretisch erwarteten Werten?
Vorgeschlagene Übung: Probieren Sie es in 3 Durchläufen aus – stabile Erdumlaufbahn von der Erdoberfläche, progrades Durchbrennen, um den Mond zu erreichen, rückläufiges Durchbrennen, um die Umlaufbahn um den Mond zu stabilisieren. Versuchen Sie dann, deltaV zu minimieren.
Hinweis: Ich plane, den Code mit ausführlichen Kommentaren für diejenigen zu aktualisieren, die mit der python3-Syntax nicht vertraut sind.
Die beiden beteiligten Körper sollen Massen haben . Beginnen Sie mit dem zweiten Newtonschen Gesetz
wo ist der relative Positionsvektor für die beiden fraglichen Körper. Die Kraft auf Körper 1 von Körper 2 ist natürlich seit . Wenn wir die Positionen mit bezeichnen und , dann
und
Zusammen mit den Anfangspositionen und -geschwindigkeiten umfasst dieses System gewöhnlicher Differentialgleichungen (ODEs) ein Anfangswertproblem. Der übliche Ansatz besteht darin, dies als System erster Ordnung aus 8 Gleichungen zu schreiben und eine Runge-Kutta- oder Mehrschrittmethode anzuwenden, um sie zu lösen.
Wenn Sie etwas Einfaches wie Vorwärts-Euler oder Rückwärts-Euler anwenden, sehen Sie, wie sich die Erde ins Unendliche bzw. in Richtung Sonne windet, aber das ist ein Effekt der numerischen Fehler. Wenn Sie eine genauere Methode verwenden, wie die klassische Runge-Kutta-Methode 4. Ordnung, werden Sie feststellen, dass sie eine Weile nahe an einer wahren Umlaufbahn bleibt, sich aber schließlich immer noch nach innen windet (solange der Zeitschritt klein genug ist). oder geht gegen unendlich (wenn der Zeitschritt zu groß ist). Der richtige Ansatz besteht darin, eine symplektische Methode zu verwenden, die die Erde auf der richtigen Umlaufbahn hält – obwohl ihre Phase aufgrund numerischer Fehler immer noch verschoben sein wird.
Für das 2-Körper-Problem ist es möglich, ein einfacheres System abzuleiten, indem Sie Ihr Koordinatensystem um den Massenmittelpunkt herum aufbauen. Aber ich denke, die obige Formulierung ist klarer, wenn dies neu für Sie ist.
Benutzer2449
Zustandsraum
Benutzer21
Zustandsraum
Benutzer21
Zustandsraum
Zustandsraum