Solo un piccolo disclaimer in anticipo: non ho mai studiato astronomia o scienze esatte per quella materia (nemmeno l'IT), quindi sto cercando di colmare questa lacuna con l'autoeducazione. L'astronomia è una delle aree che ha catturato la mia attenzione e la mia idea di autoeducazione si basa sull'approccio applicato. Quindi, dritto al punto - questo è il modello di simulazione orbitale su cui sto lavorando casualmente quando ho tempo / umore. Il mio obiettivo principale è creare un sistema solare completo in movimento e la capacità di pianificare il lancio di veicoli spaziali su altri pianeti.
Sei libero di ritirare questo progetto in qualsiasi momento e divertirti a sperimentare!
aggiornare!!! (Nov10)
- la velocità è ora deltaV corretta e dare movimento aggiuntivo ora calcola il vettore di somma della velocità
- puoi posizionare tutti gli oggetti statici che desideri, su ogni oggetto unitario in movimento controlla i vettori di gravità da tutte le fonti (e verifica la collisione)
- notevolmente migliorato le prestazioni dei calcoli
- una correzione per tenere conto della mod interattiva in matplotlib. Sembra che questa sia l'opzione predefinita solo per ipython. Python3 regolare richiede esplicitamente tale affermazione.
Fondamentalmente è ora possibile "lanciare" un veicolo spaziale dalla superficie della Terra e tracciare una missione sulla Luna effettuando correzioni vettoriali deltaV tramite giveMotion (). Il prossimo in linea sta cercando di implementare la variabile temporale globale per abilitare il movimento simultaneo, ad esempio la Luna orbita attorno alla Terra, mentre il veicolo spaziale prova una manovra di gravità assistita.
Commenti e suggerimenti per miglioramenti sono sempre ben accetti!
Fatto in Python3 con libreria matplotlib
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)
Come funziona
Tutto si riduce a due cose:
- Creazione di oggetti come
Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)
con i parametri di posizione sulla griglia (1 unità di griglia è 1000 km di default ma anche questo può essere cambiato), raggio in unità di griglia e massa in kg. - Dare all'oggetto deltaV come
Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)
ovviamenteCraft = Object(...)
deve essere creato in primo luogo, come indicato nel punto precedente. I parametri qui sonodeltaV
in m / s (nota che per ora l'accelerazione è istantanea),motionDirection
è la direzione del deltaV in gradi (dalla posizione corrente immagina un cerchio a 360 gradi attorno all'oggetto, quindi la direzione è un punto su quel cerchio) e infine il parametrotime
è quanti secondi dopo che la traiettoria push deltaV dell'oggetto sarà monitorata.giveMotion()
Inizio successivo dall'ultima posizione precedentegiveMotion()
.
Domande:
- È un algoritmo valido per calcolare le orbite?
- Quali sono gli ovvi miglioramenti da apportare?
- Ho preso in considerazione la variabile "timeScale" che ottimizzerà i calcoli, in quanto potrebbe non essere necessario ricalcolare i vettori e le posizioni per ogni secondo. Qualche idea su come dovrebbe essere implementata o è generalmente una buona idea? (perdita di precisione rispetto a prestazioni migliorate)
Fondamentalmente il mio obiettivo è iniziare una discussione sull'argomento e vedere dove conduce. E, se possibile, imparare (o anche meglio - insegnare) qualcosa di nuovo e interessante.
Sentiti libero di sperimentare!
Prova a usare:
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)
Con due ustioni - uno progrado in orbita terrestre e uno retrogrado in orbita lunare ho raggiunto un'orbita lunare stabile. Sono vicini ai valori teoricamente previsti?
Esercizio suggerito: provalo in 3 ustioni: orbita terrestre stabile dalla superficie terrestre, ustioni progradi per raggiungere la Luna, ustioni retrogrado per stabilizzare l'orbita attorno alla Luna. Quindi provare a minimizzare deltaV.
Nota: ho intenzione di aggiornare il codice con ampi commenti per coloro che non hanno familiarità con la sintassi di python3.