algorithm - ¿Cuáles son algunos algoritmos que me permitirán simular la física planetaria?
meta tags seo 2018 (12)
Estoy interesado en hacer un simulador del "Sistema Solar" que me permita simular las fuerzas rotacionales y gravitacionales de los planetas y las estrellas.
Me gustaría poder decir, simular nuestro sistema solar y simularlo a distintas velocidades (es decir, ver a la Tierra y otros planetas girar alrededor del Sol a través de días, años, etc.). Me gustaría poder agregar planetas y cambiar planetas en masa, etc., para ver cómo afectaría al sistema.
¿Alguien tiene recursos que me orienten en la dirección correcta para escribir este tipo de simulador?
¿Hay algún motor de física existente que esté diseñado para este propósito?
Debe conocer y comprender la Ley de gravitación universal de Newton y las Leyes de movimiento planetario de Kepler . Estos dos son simples y estoy seguro de que has oído hablar de ellos, si no los has estudiado en la escuela secundaria. Finalmente, si desea que su simulador sea lo más preciso posible, debe familiarizarse con el problema n-Body .
Usted debe comenzar simple. Intenta hacer un objeto Sun
y un objeto Earth
que gire alrededor de él. Eso debería darle un comienzo muy sólido y es bastante fácil expandirse desde allí. Un objeto planetario se vería algo así como:
Class Planet {
float x;
float y;
float z; // If you want to work in 3D
double velocity;
int mass;
}
Solo recuerda que F = MA
y el resto solo son matemáticas aburridas: P
Echa un vistazo a nMod , un kit de herramientas de modelado de n cuerpos escrito en C ++ y que utiliza OpenGL. Tiene un modelo de sistema solar bastante bien poblado que viene con él y debería ser fácil de modificar. Además, tiene una wiki bastante buena sobre simulación de n-body en general. El mismo tipo que creó esto también está creando un nuevo programa llamado Moody , pero no parece estar tan avanzado.
Además, si va a hacer simulaciones de n cuerpos con más de unos pocos objetos, debería mirar el método rápido de multipolo (también llamado algoritmo de multipolo rápido). Puede reducir el número de cálculos de O (N ^ 2) a O (N) para realmente acelerar su simulación. También es uno de los diez algoritmos más exitosos del siglo XX , según el autor de este artículo.
En física, esto se conoce como el problema N-Body . Es famoso porque no se puede resolver esto a mano para un sistema con más de tres planetas. Por suerte, puede obtener soluciones aproximadas con una computadora muy fácilmente.
Un buen artículo sobre cómo escribir este código desde cero se puede encontrar aquí .
Sin embargo, siento que una advertencia es importante aquí. Es posible que no obtenga los resultados que espera. Si quieres ver como:
- La masa de un planeta afecta su velocidad orbital alrededor del Sol, fresca. Usted verá eso.
- Los diferentes planetas interactúan entre sí, serás abatido.
El problema es este.
Sí, a los astrónomos modernos les preocupa cómo la masa de Saturno cambia la órbita de la Tierra alrededor del Sol. Pero este es un efecto MUY menor. Si va a trazar el camino de un planeta alrededor del Sol, no importará que haya otros planetas en el Sistema Solar. El Sol es tan grande que ahogará toda otra gravedad. Las únicas excepciones a esto son:
- Si tus planetas tienen órbitas muy elípticas. Esto hará que los planetas se acerquen potencialmente, por lo que interactúan más.
- Si tus planetas están casi a la misma distancia del Sol. Ellos interactuarán más.
- Si haces tus planetas tan cómicamente grandes, compiten con el Sol por la gravedad en el Sistema Solar exterior.
Para ser claros, sí, podrás calcular algunas interacciones entre planetas. Pero no, estas interacciones no serán significativas a simple vista si creas un Sistema Solar realista.
¡Pruébalo y descúbrelo!
Es posible que desee echar un vistazo a Celestia , un simulador de espacio libre. Creo que puedes usarlo para crear sistemas solares ficticios y es de código abierto .
Es todo here y en general, todo lo que ha escrito Jean Meeus.
Este es un gran tutorial sobre problemas de N-body en general.
http://www.artcompsci.org/#msa
Está escrito en Ruby pero es bastante fácil de mapear en otros idiomas, etc. Cubre algunos de los enfoques de integración comunes; Forward-Euler, Leapfrog y Hermite.
Parece que es muy difícil y requiere un gran conocimiento de la física, pero en realidad es muy fácil, solo necesitas saber 2 fórmulas y un conocimiento básico de los vectores:
Fuerza de atracción (o fuerza gravitacional) entre el planeta 1 y el planeta 2 con masa m1 y m2 y la distancia entre ellos d: Fg = G * m1 * m2 / d ^ 2; Fg = m * a. G es una constante, encuéntrela sustituyendo valores aleatorios para que la aceleración "a" no sea demasiado pequeña ni demasiado grande, aproximadamente "0.01" o "0.1".
Si tienes una fuerza vectorial total que actúa sobre un planeta actual en ese instante de tiempo, puedes encontrar una aceleración instantánea a = (Fuerza total) / (masa del planeta actual). Y si tiene la aceleración actual y la velocidad actual y la posición actual, puede encontrar una nueva velocidad y una nueva posición
Si quieres verlo de verdad, puedes usar el siguiente algoritmo de supereasy (pseudocódigo):
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;
}
Si estás simulando la física, recomiendo altamente Box2D .
Es un gran simulador de física, y realmente reducirá la cantidad de placa de caldera que necesitará, con simulación de física.
Todo lo que necesita implementar es una ecuación diferencial adecuada (ley de Keplers) y usar Runge-Kutta. (al menos esto me funcionó, pero probablemente hay mejores métodos)
Hay montones de simuladores de este tipo en línea.
Aquí hay uno simple implementado en 500 líneas de código c. (montion algorhitm is much less) http://astro.berkeley.edu/~dperley/programs/ssms.html .
También compruebe esto:
http://en.wikipedia.org/wiki/Kepler_problem
http://en.wikipedia.org/wiki/Two-body_problem
http://en.wikipedia.org/wiki/N-body_problem
Los fundamentos de la astrodinámica de Bate, Muller y White aún requieren lectura en mi alma mater para los ingenieros de pregrado aeroespacial. Esto tiende a cubrir la mecánica orbital de los cuerpos en la órbita de la Tierra ... pero ese es probablemente el nivel de física y matemáticas que necesitará para comenzar su comprensión.
+1 por la sugerencia de @Stefano Borini para "todo lo que Jean Meeus ha escrito".
Algoritmos para simular la física planetaria.
Aquí hay una implementación de las partes Keppler, en mi aplicación para Android. Las partes principales están en mi sitio web para que pueda descargar la fuente completa: http://www.barrythomas.co.uk/keppler.html
Este es mi método para dibujar el planeta en la posición "siguiente" en la órbita. Piense en los pasos como caminar alrededor de un círculo, un grado a la vez, en un círculo que tiene el mismo período que el planeta que está tratando de rastrear. Fuera de este método, uso un doble global como contador de pasos, denominado dTime, que contiene varios grados de rotación.
Los parámetros clave que se le pasaron al método son, dEccentricty, dScalar (un factor de escala para que la órbita se ajuste a la pantalla), dYear (la duración de la órbita en años terrestres) y orientar la órbita para que el perihelio esté en el lugar correcto en el dial, por así decirlo, dLongPeri - La Longitud del Perihelio.
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);
}
El método anterior llama a dos métodos adicionales que proporcionan valores de E (la anomalía media) y r, la longitud del vector al final del cual se encuentra el planeta.
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)));
}
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();
}