事前にちょっとした免責事項:私は天文学やその問題に関して(ITでさえも)正確な科学を勉強したことがないので、独学でこのギャップを埋めようとしています。天文学は私の注目を集めた分野の1つであり、独学の私の考えは応用アプローチに向かっています。要するに、これは軌道シミュレーションモデルであり、時間/気分があるときに気軽に取り組んでいます。私の主な目標は、他の惑星への宇宙船の打ち上げを計画する能力と運動中の完全な太陽系を作成することです。
このプロジェクトをいつでも自由に選んで、実験を楽しんでください!
更新!!!(Nov10)
- 速度は適切なdeltaVになり、追加のモーションを与えることで速度の合計ベクトルが計算されるようになりました
- モーション内のユニットオブジェクトがすべてのソースからの重力ベクトルをチェックする(および衝突をチェックする)たびに、必要な数の静的オブジェクトを配置できます。
- 計算のパフォーマンスが大幅に向上しました
- matplotlibのインタラクティブなmodを説明する修正。これはipython専用のデフォルトオプションのようです。通常のpython3では、そのステートメントが明示的に必要です。
基本的に、地球の表面から宇宙船を「発射」し、giveMotion()を介してdeltaVベクトル補正を行うことにより、月へのミッションを計画することが可能になりました。次に、グローバル時間変数を実装して同時運動を可能にしようとしています。たとえば、月が地球を周回し、宇宙船が重力支援操縦を試みます。
改善のためのコメントと提案はいつでも歓迎します!
matplotlibライブラリを使用してPython3で実行
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)
使い方
それはすべて、次の2つに要約されます。
Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)
グリッド上の位置のパラメーター(グリッドの1単位はデフォルトで1000kmですが、これも変更できます)、グリッド単位の半径、kg単位の質量でオブジェクトを作成します。- 前のポイントで述べたように、最初にオブジェクトを作成
Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)
する必要Craft = Object(...)
があることなど、オブジェクトにdeltaVを与える。ここでのパラメーターdeltaV
はm / s(現在は加速度は瞬間的です)、motionDirection
度単位のdeltaVの方向(現在の位置からオブジェクトの周りの360度の円を想像してください。方向はその円上の点です)、最後にパラメーターtime
は秒数ですオブジェクトのdeltaVプッシュ軌道が監視された後。次giveMotion()
の前の最後の位置から開始しgiveMotion()
ます。
質問:
- これは軌道を計算するための有効なアルゴリズムですか?
- 明らかな改善点は何ですか?
- 1秒ごとにベクトルと位置を再計算する必要がないため、計算を最適化する「timeScale」変数を検討しています。それがどのように実装されるべきかについての考えはありますか、それは一般的に良いアイデアですか?(精度の低下とパフォーマンスの向上)
基本的に、私の目的は、トピックに関する議論を開始し、それがどこにつながるかを確認することです。そして、可能であれば、新しくて面白いものを学びます(または、さらに良いことを教えます)。
気軽に実験してください!
使用してみてください:
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)
2回の火傷で-1回は地球軌道で前進し、1回は月軌道で逆行して、安定した月軌道を達成しました。これらは理論上の期待値に近いですか?
推奨される運動:3回の火傷で試してください-地球表面からの安定した地球軌道、月に到達するための前進火傷、月の周りの軌道を安定させるための逆行火傷。次に、deltaVを最小化してください。
注:python3構文に慣れていない人のために、広範なコメントでコードを更新する予定です。