Chỉ cần từ chối một chút trước đó: Tôi chưa bao giờ nghiên cứu thiên văn học hay bất kỳ ngành khoa học chính xác nào cho vấn đề đó (thậm chí không phải CNTT), vì vậy tôi đang cố gắng lấp đầy khoảng trống này bằng cách tự học. Thiên văn học là một trong những lĩnh vực đã thu hút sự chú ý của tôi và ý tưởng tự học của tôi là hướng đến phương pháp ứng dụng. Vì vậy, đi thẳng vào vấn đề - đây là mô hình mô phỏng quỹ đạo mà tôi tình cờ làm việc khi có thời gian / tâm trạng. Mục tiêu chính của tôi là tạo ra hệ mặt trời hoàn chỉnh trong chuyển động và khả năng lên kế hoạch phóng tàu vũ trụ tới các hành tinh khác.
Bạn có thể tự do chọn dự án này bất cứ lúc nào và vui chơi thử nghiệm!
cập nhật !!! (Ngày 10 tháng 11)
- vận tốc bây giờ là deltaV thích hợp và cho chuyển động bổ sung bây giờ tính toán vectơ tổng của vận tốc
- bạn có thể đặt bao nhiêu vật thể tĩnh tùy thích, vào mỗi lần đối tượng đơn vị trong chuyển động kiểm tra các vectơ trọng lực từ tất cả các nguồn (và kiểm tra va chạm)
- cải thiện đáng kể hiệu suất tính toán
- một bản sửa lỗi cho tài khoản mod tương tác trong matplotlib. Có vẻ như đây là tùy chọn mặc định chỉ dành cho ipython. Python3 thông thường yêu cầu tuyên bố đó rõ ràng.
Về cơ bản, giờ đây có thể "phóng" một tàu vũ trụ từ bề mặt Trái đất và thực hiện một nhiệm vụ lên Mặt trăng bằng cách điều chỉnh vectơ deltaV thông qua giveMotion (). Dòng tiếp theo đang cố gắng thực hiện biến thời gian toàn cầu để cho phép chuyển động đồng thời, ví dụ Mặt trăng quay quanh Trái đất trong khi tàu vũ trụ thử vận động hỗ trợ trọng lực.
Bình luận và đề xuất cải tiến luôn được chào đón!
Thực hiện trong Python3 với thư viện 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)
Làm thế nào nó hoạt động
Tất cả sôi sục xuống hai điều:
- Tạo đối tượng như
Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)
với các tham số vị trí trên lưới (1 đơn vị lưới là 1000km theo mặc định nhưng điều này cũng có thể thay đổi), bán kính theo đơn vị lưới và khối lượng tính bằng kg. - Cung cấp cho đối tượng một số deltaV như
Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)
rõ ràng nó cầnCraft = Object(...)
phải được tạo ở vị trí đầu tiên như đã đề cập ở điểm trước. Các tham số ở đây tínhdeltaV
bằng m / s (lưu ý rằng hiện tại gia tốc là tức thời),motionDirection
là hướng của deltaV tính theo độ (từ vị trí hiện tại tưởng tượng vòng tròn 360 độ quanh đối tượng, vì vậy hướng là một điểm trên vòng tròn đó) và cuối cùngtime
là tham số là bao nhiêu giây sau khi quỹ đạo đẩy deltaV của đối tượng sẽ được theo dõi. Sau đógiveMotion()
bắt đầu từ vị trí cuối cùng của trước đógiveMotion()
.
Câu hỏi:
- Đây có phải là một thuật toán hợp lệ để tính toán quỹ đạo?
- Những cải tiến rõ ràng sẽ được thực hiện là gì?
- Tôi đã xem xét biến "timeScale" sẽ tối ưu hóa các tính toán, vì có thể không cần thiết phải tính toán lại các vectơ và vị trí cho mỗi giây. Bất kỳ suy nghĩ về cách nó nên được thực hiện hoặc nói chung là một ý tưởng tốt? (mất độ chính xác so với hiệu suất được cải thiện)
Về cơ bản mục tiêu của tôi là bắt đầu một cuộc thảo luận về chủ đề này và xem nó dẫn đến đâu. Và, nếu có thể, hãy học (hoặc thậm chí tốt hơn - dạy) một cái gì đó mới và thú vị.
Hãy thử nghiệm!
Hãy thử sử dụng:
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)
Với hai lần đốt - một lần tiến lên quỹ đạo Trái đất và một lần lùi ở quỹ đạo Mặt trăng, tôi đã đạt được quỹ đạo Mặt trăng ổn định. Là những gần với giá trị lý thuyết dự kiến?
Bài tập được đề xuất: Hãy thử trong 3 lần đốt - quỹ đạo Trái đất ổn định từ bề mặt Trái đất, đốt trước để tiếp cận Mặt trăng, đốt ngược để ổn định quỹ đạo quanh Mặt trăng. Sau đó cố gắng giảm thiểu deltaV.
Lưu ý: Tôi dự định cập nhật mã với các bình luận mở rộng cho những người không quen với cú pháp python3.