# 练习：2D轨道力学模拟（Python）

12

• 速度现在是适当的deltaV，并且通过给予附加运动来计算速度的和向量
• 您可以在每个运动的单位对象上放置任意数量的静态对象，以检查所有来源的重力矢量（并检查碰撞）
• 大大提高了计算性能
• 在matplotlib中解决交互式mod的问题。看起来这是仅适用于ipython的默认选项。常规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.mass = mass
self.placeObject()
self.velocity = 0
Object._instances.append(self)

def placeObject(self):
plt.show()

def giveMotion(self, deltaV, motionDirection, time):
if self.velocity != 0:
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_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[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)


1. 使用对象Earth = Object(name="Earth", position=(50.0, 50.0), radius=6.371, mass=5.972e24)在网格上的位置参数创建对象（默认情况下，网格的1个单位为1000 km，但是也可以更改），以网格为单位的半径和以kg为单位的质量。
2. 给对象一些deltaV，例如，Craft.giveMotion(deltaV=8500.0, motionDirection=100, time=130000)显然需要Craft = Object(...)首先创建，如前所述。此处的参数deltaV以m / s为单位（请注意，现在加速度是瞬时的），motionDirection是以度为单位的deltaV的方向（从当前位置想象物体周围360度的圆，因此方向是该圆上的一个点），最后参数time是多少秒之后，将监视对象的delV推入轨迹。随后giveMotion()从上一个的最后一个位置开始giveMotion()

1. 这是计算轨道的有效算法吗？
2. 有哪些明显的改进要做？
3. 我一直在考虑“ 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)


Statespace 2014年

barrycarter 2014年

Statespace 2014年

1

barrycarter 2014年

11

${m}_{1},{m}_{2}$$m_1, m_2$

$F=ma$
$a$$a$

${F}_{21}=\frac{G{m}_{1}{m}_{2}}{|{r}_{21}{|}^{3}}{r}_{21}$

${r}_{21}$$r_{21}$${F}_{12}=-{F}_{21}$$F_{12}=-F_{21}$${r}_{12}=-{r}_{21}$$r_{12}=-r_{21}$$\left({x}_{1},{y}_{1}\right)$$(x_1,y_1)$$\left({x}_{2},{y}_{2}\right)$$(x_2,y_2)$

${r}_{21}=\left(\begin{array}{c}{x}_{1}-{x}_{2}\\ {y}_{1}-{y}_{2}\end{array}\right).$

$|r|=\sqrt{\left({x}_{1}-{x}_{2}{\right)}^{2}+\left({y}_{1}-{y}_{2}{\right)}^{2}}.$
$a=F/m$$a=F/m$

$\begin{array}{rl}{x}_{1}^{″}\left(t\right)& =\frac{G{m}_{2}\left({x}_{2}-{x}_{1}\right)}{|r{|}^{3}}\\ {y}_{1}^{″}\left(t\right)& =\frac{G{m}_{2}\left({y}_{2}-{y}_{1}\right)}{|r{|}^{3}}\\ {x}_{2}^{″}\left(t\right)& =\frac{G{m}_{1}\left({x}_{1}-{x}_{2}\right)}{|r{|}^{3}}\\ {y}_{2}^{″}\left(t\right)& =\frac{G{m}_{1}\left({y}_{1}-{y}_{2}\right)}{|r{|}^{3}}.\end{array}$

Statespace 2014年

statespace 2014年

chrispap 2014年