研究性学习报告

一、研究背景

在高中物理必修二中,我们学习了牛顿运动定律和万有引力定律的有关内容,领略了宇宙中无穷的奥秘。

虽然在现阶段的物理界中,牛顿定律的理论基础已经被爱因斯坦的广义相对论所取代。但它在大多数应用中仍然被用作重力效应的经典近似。只有在需要极端精确的时候,或者在处理非常强大的引力场的时候,比如那些在极其密集的物体上,或者在非常近的距离时,才需要相对论。

介于一种学以致用的精神,考虑到我们的计算机基本水平,我们产生了对于模拟万有引力的极大兴趣。

二、研究方法

1.物理原理

在这个模型中,我们将每个星球抽象为一个有质量的质点,运用经典力学中的万有引力定律和质点运动规律进行运算。

(1).万有引力定律

定义:任意两个质点由通过连心线方向上的力相互吸引。该吸引力的大小与它们的质量乘积成正比,与它们距离的平方成反比,与两物体的化学本质或物理状态以及中介物质无关。

矢量表达式:

F12=Gm1m2r2r^F12:21G:6.6748×1011 m3kg1s2m1 m2:12r:21r^r2r1r2r1:12F_{12}=G\frac{m_1m_2}{r^2}\hat{r}\\\\ {F} _{12}:物体2作用于物体1的万有引力\\ G: 万有引力常数,其值约等于6.6748\times 10^{-11}\ m^3kg^{-1}s^{-2}\\ m_1\ m_2:分别为物体1和物体2的质量\\ r:物体2和物体1之间的距离\\ {\displaystyle \mathbf {\hat {r}} \equiv {\frac {\mathbf {r} _{2}-\mathbf {r} _{1}}{\vert \mathbf {r} _{2}-\mathbf {r} _{1}\vert }}}:物体1到物体2的单位矢量

(2).质点运动规律

设质量为m的质点Q,在F1,F2,…,FN诸力的作用下运动。若以a表示质点的加速度,则由牛顿第二定律有:

ma=Fma=\sum_{}^{} F

又因为加速度a是位移的二阶导数,可得:

d2ydt2=F\frac{\mathrm{d}^2 y}{\mathrm{d} t^2} =\sum F

式中r为质点的矢径,这是矢量形式的质点运动微分方程。

在物理中,速度、位移、加速度均为有方向的矢量;对于计算机中,二维矢量的方向不便于表示,此时联想到所学的正交分解法,通过三角函数将有方向的向量分别分解到两个垂直的方向上。这样就便于计算机进行存储和计算。

在直角坐标轴上投影,得:

mx=Fxmy=Fy}\left.\begin{matrix} m\overline{x}=\sum F_x \\ m\overline{y}=\sum F_y \\ \end{matrix}\right\}

2.计算机原理

(1).工具及模块

  • Python3.6及以上版本
  • Python第三方库模块pygame用以可视化表现
  • Python第三方库模块easygui用以与用户进行可视化交互操作
  • Python第三方库模块matplotlib用以记录基本数据和进行数学操作

(2).原理

在物理中,速度、位移、加速度均为有方向的矢量;对于计算机中,二维矢量的方向不便于表示,此时联想到所学的正交分解法,通过三角函数将有方向的向量分别分解到两个垂直的方向上。这样就便于计算机进行存储和计算。

数据结构与存储

介于这一点,对于进行星球部分的数据结构如下:

1
2
3
4
5
6
7
8
9
10
11
class plt(object):
def __init__(self,st ,pos, vel, mass, acc):
self.status = pygame.transform.scale(pygame.image.load("./resources/" + st).convert(),(10,10))
screen.blit(self.status, (pos[0],pos[1]))
self.rect = pygame.image.load("./resources/" + st).get_rect()
self.pos = pos
self.acc = acc
self.vel = vel
self.mass = mass
self.recordline = [[],[]]
self.recordspeed = [[1],[math.sqrt(self.vel[0] ** 2 + self.vel[1] ** 2)]]

在这个类中,

  • *.status存储在屏幕上绘制星球所需的图片
  • *.rect存储星球图片在渲染过程中的大小
  • *.pos存储星球的坐标位置,是类似于(200,200)的一个二元向量结构,分别表示在X轴和Y轴方向上的数值,以下的加速度、速度等都是如此
  • *.acc存储星球的加速度,二元向量结构
  • *.vel存储星球的速度,二元向量结构
  • *.mass存储星球的质量
  • *.recordline记录星球的轨迹,*.recordspeed记录星球的速度

以上,便实现了对于星球数据的基本存储。

计算
1
2
3
4
5
6
7
8
def cal(a, b):
x=b.pos[0]-a.pos[0]
y=b.pos[1]-a.pos[1]
dis=math.sqrt(x ** 2 + y ** 2)
sin=x/dis
cos=y/dis
f=G*a.mass*b.mass/(dis ** 2)
return f*sin,f*cos

在这个函数中,传入两个刚刚新建的plt类变量。通过计算两者横纵坐标之差,根据勾股定理计算距离,接着计算出两者万有引力大小。根据横纵坐标之差,夹角的sin值和cos值进一步将万有引力分解到X轴和Y轴上,函数最终返回值是两者的万有引力分解到X轴方向和Y轴方向上的二元向量。

渲染循环

具体请看程序内注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
while (1 == 1):
clock.tick(FPS)
event = pygame.event.get()
for i in event: #鼠标按键监测
if i.type == pygame.QUIT: #按下esc退出模拟
sys.exit()
elif i.type == pygame.MOUSEBUTTONDOWN: #左键暂停
pos = i.pos
tmp = i.button
if tmp == 1:
ret = Game_pause(speed, FPS, multiple)
if (ret[0] == 0):
sys.exit()
else:
speed = ret[1]
FPS = ret[2]
multiple = ret[3]
G = GO * multiple
if tmp == 3:
ret = Game_reject(pos)

planet1 = planet
for i in planet1: #列举目前屏幕内的所有星球
pos = i.pos
m = i.mass
xt = yt = 0

for j in planet: #计算对于第i个星球,其余星球对其的作用力并累加
if (j.pos != i.pos) and (j != i):
x, y = cal(i, j)
xt += x
yt += y

accel[0] = xt/m #计算在x轴方向上的加速度
accel[1] = yt/m #计算在y轴方向上的加速度

#计算速度(时间取一帧的时间为1,所以不用乘)
i.vel[0] += accel[0]
i.vel[1] += accel[1]

#计算位置变化
pos[0] = pos[0] + i.vel[0]
pos[1] = pos[1] + i.vel[1]
i.pos = pos
i.rect = i.rect.move(i.vel[0], i.vel[1])

for j in planet1: #判定是否超出边界,如果超出边界就删除
if (j.pos[0] > WIDTH) or (j.pos[0] < 0) or (j.pos[1] > HEIGHT) or (j.pos[1] < 0):
planet.remove(j)

planet = planet1 #最后统一更新所有星球信息
screen.fill(BLACK)
for j in planet:
j = Update_Record(j) #更新每个星球记录的速度与位置
screen.blit(j.status, j.pos)
pygame.display.flip()

有部分游戏暂停时的交互、更新记录等函数未完整给出。

交互

pygame模块中有关于按键事件的监测,easygui模块中可以轻松调用一些简单的可交互式窗口,便于用户进行最基本的操作,如修改星球、添加星球、修改基本参数、查看数据记录等。

具体代码实现部分过长,可以去开源托管网站(下一章节有提及)查看。

三、研究成果

整个项目现以完成,并在以下两个平台开源:

simulate-gravity: 模拟引力 - Gitee.com https://gitee.com/wzcwzc0/simulate-gravity/tree/main/

wzcwzc05/simulate-gravity https://github.com/wzcwzc05/simulate-gravity/tree/main

1.安装及运行项目

(1).Windows

从官方网站https://www.python.org/downloads/下载Python安装包。

注意安装时勾选Add to Path,自动加入环境变量。

img

并进行完整安装(包含pip包管理器)

img

TIPS: Windows 7及以下系统不再支持Python3.9及以上版本。

出现如下两张图即为成功:

img

img

下一步使用pip包管理器安装项目依赖的第三方库:

1
pip install pygame easygui matplotlib

如果在中途出现大量错误信息,有可能是pip源在国外,导致下载失败,可以使用清华源:

1
pip install pygame easygui matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

出现以下的环境即为安装成功:

image-20220313230144982

此时来到项目目录下执行python main.py即可运行项目

(2).Linux

Linux往往安装系统时自带Python,不过还是要检查一下python版本:

image-20220313230401566

可以看到版本是3.10.2,只要版本在3.6以上皆可以兼容。

下一步使用pip包管理器安装项目依赖的第三方库:

1
pip install pygame easygui matplotlib

如果在中途出现大量错误信息,有可能是pip源在国外,导致下载失败,可以使用清华源:

1
pip install pygame easygui matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

出现以下的环境即为安装成功:

image-20220313230144982

此时来到项目目录下执行python main.py即可运行项目

2.演示图

image-20220203215808967image-20220203220127591image-20220203215952869image-20220203220042715

四、示例

下面演示模拟构建一个存在一个质量为10000的中心天体的恒星系。

首先左键暂停,添加中心天体:

2022-02-11_10-36

计算质量为1的行星在距离为200时进行匀速圆周运动所需的线速度:

G=6.67408e11(10)已知:G=6.67408e-11(放大10倍)

m1=10000m2=1r=200m_1=10000 \quad m_2=1 \quad r=200

F=Gm1m2r2=0.166852F = G \frac{m_1m_2}{r^2} = 0.166852

F=F=m1v2rv=Frm1=5.7767118F_{向心}=F=m_1\frac{v^2}{r} \quad v=\sqrt{\frac{Fr}{m_1}}=5.7767118

添加行星:

image-20220211105838663

最终结果:

image-20220211105937038image-20220211110014297

速度误差范围在可接受范围内,可近似认为是匀速圆周运动。

五、改进及其建议

虽然程序的大体已经完成,基本功能已经得到实现,但依旧存在与用户交互效果不够好等问题。

在核心原理上,万有引力定律属于经典力学范畴,对于广义相对论存在一定的不足,后期可以考虑使用引力场代替力的计算。

同时在两个星球距离过近时,并未加入碰撞或撕裂等判断,导致一些不合理现象的产生,后期可以加入碰撞或撕裂的判断。