What are some algorithms that will allow me to simulate planetary physics?

独自空忆成欢 提交于 2019-12-02 15:51:20
Stefano Borini

It's everything here and in general, everything that Jean Meeus has written.

You need to know and understand Newton's Law of Universal Gravitation and Kepler's Laws of Planetary Motion. These two are simple and I'm sure you've heard about them, if not studied them in high school. Finally, if you want your simulator to be as accurate as possible, you should familiarize yourself with the n-Body problem.

You should start out simple. Try making a Sun object and an Earth object that revolves around it. That should give you a very solid start and it's fairly easy to expand from there. A planet object would look something like:

Class Planet {   float x;   float y;   float z; // If you want to work in 3D   double velocity;   int mass; } 

Just remember that F = MA and the rest just just boring math :P

This is a great tutorial on N-body problems in general.

http://www.artcompsci.org/#msa

It's written using Ruby but pretty easy to map into other languages etc. It covers some of the common integration approaches; Forward-Euler, Leapfrog and Hermite.

High Performance Mark

You might want to take a look at Celestia, a free space simulator. I believe that you can use it to create fictitious solar systems and it is open source.

All you need to implement is proper differential equation (Keplers law) and using Runge-Kutta. (at lest this worked for me, but there are probably better methods)

There are loads of such simulators online.

Here is one simple one implemented in 500lines of c code. (montion algorhitm is much less) http://astro.berkeley.edu/~dperley/programs/ssms.html.

Also check this:
http://en.wikipedia.org/wiki/Kepler_problem
http://en.wikipedia.org/wiki/Two-body_problem
http://en.wikipedia.org/wiki/N-body_problem

In physics this is known as the N-Body Problem. It is famous because you can not solve this by hand for a system with more than three planets. Luckily, you can get approximate solutions with a computer very easily.

A nice paper on writing this code from the ground up can be found here.

However, I feel a word of warning is important here. You may not get the results you expect. If you want to see how:

  1. the mass of a planet affects its orbital speed around the Sun, cool. You will see that.
  2. the different planets interact with each other, you will be bummed.

The problem is this.

Yeah, modern astronomers are concerned with how Saturn's mass changes the Earth's orbit around the Sun. But this is a VERY minor effect. If you are going to plot the path of a planet around the Sun, it will hardly matter that there are other planets in the Solar System. The Sun is so big it will drown out all other gravity. The only exceptions to this are:

  1. If your planets have very elliptical orbits. This will cause the planets to potentially get closer together, so they interact more.
  2. If your planets are almost the exact same distance from the Sun. They will interact more.
  3. If you make your planets so comically large they compete with the Sun for gravity in the outer Solar System.

To be clear, yes, you will be able to calculate some interactions between planets. But no, these interactions will not be significant to the naked eye if you create a realistic Solar System.

Try it though, and find out!

Check out nMod, a n-body modeling toolkit written in C++ and using OpenGL. It has a pretty well populated solar system model that comes with it and it should be easy to modify. Also, he has a pretty good wiki about n-body simulation in general. The same guy who created this is also making a new program called Moody, but it doesn't appear to be as far along.

In addition, if you are going to do n-body simulations with more than just a few objects, you should really look at the fast multipole method (also called the fast multipole algorithm). It can the reduce number of computations from O(N^2) to O(N) to really speed up your simulation. It is also one of the top ten most successful algorithms of the 20th century, according to the author of this article.

Barry

Algorithms to simulate planetary physics.

Here is an implementation of the Keppler parts, in my Android app. The main parts are on my web site for you can download the whole source: http://www.barrythomas.co.uk/keppler.html

This is my method for drawing the planet at the 'next' position in the orbit. Think of the steps like stepping round a circle, one degree at a time, on a circle which has the same period as the planet you are trying to track. Outside of this method I use a global double as the step counter - called dTime, which contains a number of degrees of rotation.

The key parameters passed to the method are, dEccentricty, dScalar (a scaling factor so the orbit all fits on the display), dYear (the duration of the orbit in Earth years) and to orient the orbit so that perihelion is at the right place on the dial, so to speak, dLongPeri - the Longitude of Perihelion.

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); } 

The method above calls two further methods which provide values of E (the mean anomaly) and r, the length of the vector at the end of which the planet is found.

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))); } 

It looks like it is very hard and requires strong knowledge of physics but in fact it is very easy, you need to know only 2 formulas and basic understanding of vectors:

Attractional force (or gravitational force) between planet1 and planet2 with mass m1 and m2 and distance between them d: Fg = G*m1*m2/d^2; Fg = m*a. G is a constant, find it by substituting random values so that acceleration "a" will not be too small and not too big approximately "0.01" or "0.1".

If you have total vector force which is acting on a current planet at that instant of time, you can find instant acceleration a=(total Force)/(mass of current planet). And if you have current acceleration and current velocity and current position, you can find new velocity and new position

If you want to look it real you can use following supereasy algorythm (pseudocode):

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; } 

If you're simulating physics, I highly recommend Box2D.
It's a great physics simulator, and will really cut down the amount of boiler plate you'll need, with physics simulating.

Fundamentals of Astrodynamics by Bate, Muller, and White is still required reading at my alma mater for undergrad Aerospace engineers. This tends to cover the orbital mechanics of bodies in Earth orbit...but that is likely the level of physics and math you will need to start your understanding.

+1 for @Stefano Borini's suggestion for "everything that Jean Meeus has written."

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(); } 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!