我有兴趣做一个“太阳系”模拟器,它可以让我模拟行星和恒星的旋转和重力。
我希望能够说,模拟我们的太阳系,并以不同的速度模拟它(即,观察地球和其他行星在太阳,几年等周围绕太阳旋转)。我希望能够添加行星并改变行星质量等,以了解它将如何影响系统。
有没有人有任何资源可以指出我正确的方向来编写这种模拟器?
是否有为此目的而设计的现有物理引擎?
答案 0 :(得分:9)
一切都是here,一般来说,是Jean Meeus写的所有内容。
答案 1 :(得分:8)
您需要了解并了解Newton's Law of Universal Gravitation和Kepler's Laws of Planetary Motion。这两个很简单,我相信你已经听过他们,如果不是在高中学习的话。最后,如果您希望模拟器尽可能准确,您应该熟悉n-Body problem。
你应该从简单开始。尝试制作一个Sun
对象和围绕它的Earth
对象。这应该会给你一个非常可靠的开始,并且很容易从那里扩展。行星物体看起来像:
Class Planet {
float x;
float y;
float z; // If you want to work in 3D
double velocity;
int mass;
}
请记住F = MA
,其余的只是无聊的数学:P
答案 2 :(得分:6)
答案 3 :(得分:4)
您可能需要查看免费空间模拟器Celestia。我相信你可以用它来创造虚构的太阳系,它是open source。
答案 4 :(得分:2)
你需要实现的是适当的微分方程(Keplers定律)和使用Runge-Kutta。 (至少这对我有用,但可能有更好的方法)
网上有很多这样的模拟器。
这是一个简单的实现在500行的c代码。 (montion algorhitm要少得多) http://astro.berkeley.edu/~dperley/programs/ssms.html
同时检查:
http://en.wikipedia.org/wiki/Kepler_problem
http://en.wikipedia.org/wiki/Two-body_problem
http://en.wikipedia.org/wiki/N-body_problem
答案 5 :(得分:2)
在物理学中,这被称为N-Body Problem。它之所以出名,是因为对于有三个以上行星的系统,你不能手动解决这个问题。幸运的是,您可以非常轻松地使用计算机获得近似解决方案。
可以找到一篇关于从头开始编写此代码的好文章here。
但是,我觉得一句警告在这里很重要。您可能无法获得预期的结果。如果你想看看如何:
问题在于此。
是的,现代天文学家关心的是土星的质量如何改变地球围绕太阳的轨道。但这是一个非常小的影响。如果你要绘制太阳周围行星的路径,那么太阳系中还有其他行星就没那么重要了。太阳太大了,它会淹没所有其他引力。唯一的例外是:
要清楚,是的,你将能够计算出行星之间的一些相互作用。但是,如果你创造一个真实的太阳系,那么这些相互作用对于肉眼来说并不重要。
尝试一下,然后找出来!
答案 6 :(得分:1)
查看nMod,一个用C ++编写并使用OpenGL的n-body建模工具包。它有一个非常好的太阳能系统模型,它附带它,它应该很容易修改。此外,他对一般的n体仿真有很好的维基。创建这个的同一个人也在创建一个名为Moody的新程序,但它看起来并不是那么远。
另外,如果你要用不止一些物体进行n体模拟,你应该真正看一下fast multipole method(也称为快速多极算法)。它可以减少从O(N ^ 2)到O(N)的计算次数,从而真正加快仿真速度。根据这篇文章的作者,它也是top ten most successful algorithms of the 20th century之一。
答案 7 :(得分:1)
模拟行星物理的算法。
以下是我的Android应用中Keppler部件的实现。主要部分在我的网站上,您可以下载整个来源:http://www.barrythomas.co.uk/keppler.html
这是我在下一步拍摄地球的方法。在轨道中的位置。想象一下这样的步骤,比如绕着一个圆圈,一次一个圆圈,在一个与你想要追踪的行星具有相同周期的圆圈上。在这个方法之外,我使用全局double作为步数计数器 - 称为dTime,它包含多个旋转度。
传递给该方法的关键参数是,dEccentricty,dScalar(缩放系数,因此轨道全部适合显示),dYear(地球年代轨道的持续时间)和定向轨道,使近日点处于表盘上的正确位置,可以说是dLongPeri - 近日点的经度。
<强> drawPlanet:强>
public void drawPlanet (double dEccentricity, double dScalar, double dYear, Canvas canvas, Paint paint,
String sName, Bitmap bmp, double dLongPeri)
{
double dE, dr, dv, dSatX, dSatY, dSatXCorrected, dSatYCorrected;
float fX, fY;
int iSunXOffset = getWidth() / 2;
int iSunYOffset = getHeight() / 2;
// get the value of E from the angle travelled in this 'tick'
dE = getE (dTime * (1 / dYear), dEccentricity);
// get r: the length of 'radius' vector
dr = getRfromE (dE, dEccentricity, dScalar);
// calculate v - the true anomaly
dv = 2 * Math.atan (
Math.sqrt((1 + dEccentricity) / (1 - dEccentricity))
*
Math.tan(dE / 2)
);
// get X and Y coords based on the origin
dSatX = dr / Math.sin(Math.PI / 2) * Math.sin(dv);
dSatY = Math.sin((Math.PI / 2) - dv) * (dSatX / Math.sin(dv));
// now correct for Longitude of Perihelion for this planet
dSatXCorrected = dSatX * (float)Math.cos (Math.toRadians(dLongPeri)) -
dSatY * (float)Math.sin(Math.toRadians(dLongPeri));
dSatYCorrected = dSatX * (float)Math.sin (Math.toRadians(dLongPeri)) +
dSatY * (float)Math.cos(Math.toRadians(dLongPeri));
// offset the origin to nearer the centre of the display
fX = (float)dSatXCorrected + (float)iSunXOffset;
fY = (float)dSatYCorrected + (float)iSunYOffset;
if (bDrawOrbits)
{
// draw the path of the orbit travelled
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
// get the size of the rect which encloses the elliptical orbit
dE = getE (0.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.bottom = (float)dr;
dE = getE (180.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.top = (float)(0 - dr);
// calculate minor axis from major axis and eccentricity
// http://www.1728.org/ellipse.htm
double dMajor = rectOval.bottom - rectOval.top;
double dMinor = Math.sqrt(1 - (dEccentricity * dEccentricity)) * dMajor;
rectOval.left = 0 - (float)(dMinor / 2);
rectOval.right = (float)(dMinor / 2);
rectOval.left += (float)iSunXOffset;
rectOval.right += (float)iSunXOffset;
rectOval.top += (float)iSunYOffset;
rectOval.bottom += (float)iSunYOffset;
// now correct for Longitude of Perihelion for this orbit's path
canvas.save();
canvas.rotate((float)dLongPeri, (float)iSunXOffset, (float)iSunYOffset);
canvas.drawOval(rectOval, paint);
canvas.restore();
}
int iBitmapHeight = bmp.getHeight();
canvas.drawBitmap(bmp, fX - (iBitmapHeight / 2), fY - (iBitmapHeight / 2), null);
// draw planet label
myPaint.setColor(Color.WHITE);
paint.setTextSize(30);
canvas.drawText(sName, fX+20, fY-20, paint);
}
上述方法调用另外两种方法,它们提供E(平均异常)的值和r,即在行星末端找到的向量的长度。
<强> GETE:强>
public double getE (double dTime, double dEccentricity)
{
// we are passed the degree count in degrees (duh)
// and the eccentricity value
// the method returns E
double dM1, dD, dE0, dE = 0; // return value E = the mean anomaly
double dM; // local value of M in radians
dM = Math.toRadians (dTime);
int iSign = 1;
if (dM > 0) iSign = 1; else iSign = -1;
dM = Math.abs(dM) / (2 * Math.PI); // Meeus, p 206, line 110
dM = (dM - (long)dM) * (2 * Math.PI) * iSign; // line 120
if (dM < 0)
dM = dM + (2 * Math.PI); // line 130
iSign = 1;
if (dM > Math.PI) iSign = -1; // line 150
if (dM > Math.PI) dM = 2 * Math.PI - dM; // line 160
dE0 = Math.PI / 2; // line 170
dD = Math.PI / 4; // line 170
for (int i = 0; i < 33; i++) // line 180
{
dM1 = dE0 - dEccentricity * Math.sin(dE0); // line 190
dE0 = dE0 + dD * Math.signum((float)(dM - dM1));
dD = dD / 2;
}
dE = dE0 * iSign;
return dE;
}
<强> getRfromE:强>
public double getRfromE (double dE, double dEccentricty, double dScalar)
{
return Math.min(getWidth(), getHeight()) / 2 * dScalar * (1 - (dEccentricty * Math.cos(dE)));
}
答案 8 :(得分:1)
它看起来非常难,需要强大的物理知识,但事实上它很容易,你只需要知道2个公式和对矢量的基本理解:
行星1和行星2之间的吸引力(或重力),质量m1和m2以及它们之间的距离d:Fg = G * m1 * m2 / d ^ 2; Fg = m * a。 G是常数,通过替换随机值来找到它,以便加速&#34; a&#34;不会太小而且不会太大&#34; 0.01&#34;或&#34; 0.1&#34;。
如果你的总矢量力在那个时刻作用于当前行星,你可以找到即时加速度a =(总力)/(当前行星的质量)。如果您有当前的加速度和当前速度和当前位置,您可以找到新的速度和新位置
如果你想看起来真实,你可以使用以下supereasy algorythm(伪代码):
int n; // # of planets
Vector2D planetPosition[n];
Vector2D planetVelocity[n]; // initially set by (0, 0)
double planetMass[n];
while (true){
for (int i = 0; i < n; i++){
Vector2D totalForce = (0, 0); // acting on planet i
for (int j = 0; j < n; j++){
if (j == i)
continue; // force between some planet and itself is 0
Fg = G * planetMass[i] * planetMass[j] / distance(i, j) ^ 2;
// Fg is a scalar value representing magnitude of force acting
// between planet[i] and planet[j]
// vectorFg is a vector form of force Fg
// (planetPosition[j] - planetPosition[i]) is a vector value
// (planetPosition[j]-planetPosition[i])/(planetPosition[j]-plantetPosition[i]).magnitude() is a
// unit vector with direction from planet[i] to planet[j]
vectorFg = Fg * (planetPosition[j] - planetPosition[i]) /
(planetPosition[j] - planetPosition[i]).magnitude();
totalForce += vectorFg;
}
Vector2D acceleration = totalForce / planetMass[i];
planetVelocity[i] += acceleration;
}
// it is important to separate two for's, if you want to know why ask in the comments
for (int i = 0; i < n; i++)
planetPosition[i] += planetVelocity[i];
sleep 17 ms;
draw planets;
}
答案 9 :(得分:0)
如果您正在模拟物理,我强烈推荐Box2D 这是一个很棒的物理模拟器,通过物理模拟真的可以减少你需要的锅炉板数量。
答案 10 :(得分:-1)
Fundamentals of Astrodynamics仍然需要在母校为本科航空航天工程师阅读。这往往涵盖了地球轨道上的物体的轨道力学......但这可能是您需要开始理解的物理和数学水平。
+1 @Stefano Borini建议“Jean Meeus撰写的所有内容。”
答案 11 :(得分:-4)
Dear Friend here is the graphics code that simulate solar system
Kindly refer through it
/*Arpana*/
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<math.h>
#include<dos.h>
void main()
{
int i=0,j=260,k=30,l=150,m=90;
int n=230,o=10,p=280,q=220;
float pi=3.1424,a,b,c,d,e,f,g,h,z;
int gd=DETECT,gm;
initgraph(&gd,&gm,"c:\tc\bgi");
outtextxy(0,10,"SOLAR SYSTEM-Appu");
outtextxy(500,10,"press any key...");
circle(320,240,20); /* sun */
setfillstyle(1,4);
floodfill(320,240,15);
outtextxy(310,237,"sun");
circle(260,240,8);
setfillstyle(1,2);
floodfill(258,240,15);
floodfill(262,240,15);
outtextxy(240,220,"mercury");
circle(320,300,12);
setfillstyle(1,1);
floodfill(320,298,15);
floodfill(320,302,15);
outtextxy(335,300,"venus");
circle(320,160,10);
setfillstyle(1,5);
floodfill(320,161,15);
floodfill(320,159,15);
outtextxy(332,150, "earth");
circle(453,300,11);
setfillstyle(1,6);
floodfill(445,300,15);
floodfill(448,309,15);
outtextxy(458,280,"mars");
circle(520,240,14);
setfillstyle(1,7);
floodfill(519,240,15);
floodfill(521,240,15);
outtextxy(500,257,"jupiter");
circle(169,122,12);
setfillstyle(1,12);
floodfill(159,125,15);
floodfill(175,125,15);
outtextxy(130,137,"saturn");
circle(320,420,9);
setfillstyle(1,13);
floodfill(320,417,15);
floodfill(320,423,15);
outtextxy(310,400,"urenus");
circle(40,240,9);
setfillstyle(1,10);
floodfill(38,240,15);
floodfill(42,240,15);
outtextxy(25,220,"neptune");
circle(150,420,7);
setfillstyle(1,14);
floodfill(150,419,15);
floodfill(149,422,15);
outtextxy(120,430,"pluto");
getch();
while(!kbhit()) /*animation*/
{
a=(pi/180)*i;
b=(pi/180)*j;
c=(pi/180)*k;
d=(pi/180)*l;
e=(pi/180)*m;
f=(pi/180)*n;
g=(pi/180)*o;
h=(pi/180)*p;
z=(pi/180)*q;
cleardevice();
circle(320,240,20);
setfillstyle(1,4);
floodfill(320,240,15);
outtextxy(310,237,"sun");
circle(320+60*sin(a),240-35*cos(a),8);
setfillstyle(1,2);
pieslice(320+60*sin(a),240-35*cos(a),0,360,8);
circle(320+100*sin(b),240-60*cos(b),12);
setfillstyle(1,1);
pieslice(320+100*sin(b),240-60*cos(b),0,360,12);
circle(320+130*sin(c),240-80*cos(c),10);
setfillstyle(1,5);
pieslice(320+130*sin(c),240-80*cos(c),0,360,10);
circle(320+170*sin(d),240-100*cos(d),11);
setfillstyle(1,6);
pieslice(320+170*sin(d),240-100*cos(d),0,360,11);
circle(320+200*sin(e),240-130*cos(e),14);
setfillstyle(1,7);
pieslice(320+200*sin(e),240-130*cos(e),0,360,14);
circle(320+230*sin(f),240-155*cos(f),12);
setfillstyle(1,12);
pieslice(320+230*sin(f),240-155*cos(f),0,360,12);
circle(320+260*sin(g),240-180*cos(g),9);
setfillstyle(1,13);
pieslice(320+260*sin(g),240-180*cos(g),0,360,9);
circle(320+280*sin(h),240-200*cos(h),9);
setfillstyle(1,10);
pieslice(320+280*sin(h),240-200*cos(h),0,360,9);
circle(320+300*sin(z),240-220*cos(z),7);
setfillstyle(1,14);
pieslice(320+300*sin(z),240-220*cos(z),0,360,7);
delay(20);
i++;
j++;
k++;
l++;
m++;
n++;
o++;
p++;
q+=2;
}
getch();
}