¿Se supone que debo modificar la constante gravitatoria con escala y por qué los cambios de fps y escala de tiempo hacen que mi órbita se rompa?

Estoy usando Unity3D y escribiendo C#

  • Masa de la Tierra: 5.972e+22
  • Velocidad de la Tierra: [0,0,0]
  • Radio de la Tierra: 63.71
  • Masa ISS: 4194.55
  • Velocidad inicial de la ISS: [76.50, 0, 0]
  • Altitud ISS: 4
  • Constante gravitacional: 6.67408e-15

Todos los valores son los valores de la vida real / 100, ya que estoy reduciendo las cosas. (por ejemplo, la constante gravitacional fue 6.67408e-11 / 11 = 6.67408e-15.

Aquí está el código...

void Gravity(Gravity body) {
    float dSquared = (body.transform.position - transform.position).sqrMagnitude;
    float force = (body.G * shipMass * body.planetMass) / dSquared;
    Vector3 forceDirection = (body.transform.position - transform.position).normalized;
    Vector3 forceVector = (forceDirection * force);
    shipVelocity += forceVector * Time.deltaTime;

    transform.position += shipVelocity * Time.deltaTime;
}

Para que esto funcione, necesito establecer la constante gravitacional en: 1.59508e-21

Aquí hay una imagen de la órbita, la línea rosa es pasada, no futura (los elementos orbitales calculados que se muestran probablemente sean incorrectos):

Aquí hay una imagen de la órbita después de acelerar el tiempo:

Edición 1:

Usando esta fórmula para la aceleración y la primera parte de la respuesta de Russell Borogove, pude lograr una órbita circular usando estos valores:

  • Masa de la Tierra: 5.972e+22
  • Velocidad de la Tierra: [0,0,0]
  • Radio de la Tierra: 63.71
  • Masa ISS: 4194.55
  • Velocidad inicial de la ISS: [0.0765, 0, 0]
  • Altitud ISS: 4
  • Constante gravitacional: 6.67408e-24 (desplazada -15 y luego +2 órdenes de magnitud)

y este código:

void Gravity(Gravity body) {
    float dSquared = (body.transform.position - transform.position).sqrMagnitude;
    float M = body.planetMass;
    Vector3 forceDirection = (body.transform.position - transform.position).normalized;
    float g = G * M / dSquared;
    Vector3 forceVector = (forceDirection * g);
    shipVelocity += forceVector * Time.deltaTime;
}

Edición 2: Se agregaron cálculos de gravedad usando el script del acumulador de Russell Borogove a continuación...

void Update() {
    Gravity(orbitee);
    ApplyForce();
}

void ApplyForce() {
    transform.position += shipVelocity * Time.deltaTime;
    transform.Rotate(transform.forward * shipTorque * Time.deltaTime);
}

void Gravity(Gravity body) {
    accumulator += Time.deltaTime;
    while (accumulator > 0.0f) {
        float dSquared = (body.transform.position - transform.position).sqrMagnitude;
        float M = body.planetMass;
        Vector3 forceDirection = (body.transform.position - transform.position).normalized;
        float g = G * M / dSquared;
        Vector3 forceVector = (forceDirection * g);
        shipVelocity += forceVector * simtime;
        accumulator -= simtime;
    }
}

Edición 3: Script de elementos orbitales actualizado (probablemente no 100% correcto)

    //Mass of satellite
    float m1 = shipMass;

    //Mass of planet
    float m2 = orbiting.planetMass;
    float M = m2;

    //Relative Position Vector
    Vector3 r = FindRelativePosition(orbitee.transform.position, transform);

    //Relative Velocity Vector
    Vector3 v = shipCurVel;
    //#!# add relative to planet velocity

    //Specific Angular Momentum
    Vector3 h = Vector3.Cross(r, v);

    //Standard Gravitational Parameter
    float µ = G * (m1 + m2);
    //float µ = G * M;

    //Eccentricity Vector
    Vector3 evec = (Vector3.Cross(v, h) / µ) - (r / Vector3.Magnitude(r));

    //Eccentricity
    float e = Vector3.Magnitude(evec);

    //Vector to Ascending Node #!#
    Vector3 n = Vector3.Cross(new Vector3(0, 0, 1), h);

    //True Anomaly
    float t = Mathf.Acos((Vector3.Dot(evec, r)) / (e * Vector3.Magnitude(r)));
    if (Vector3.Dot(r, v) < 0)
        t = (2 * Mathf.PI) - t;

    //Eccentric Anomaly
    float E = 2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)));

    //Longitude of Ascending Node (2D)
    float Ω = 0;

    //Inclination (2D)
    float i = 0;

    //Argument of Periapsis
    float ω = Mathf.Atan2(evec.y, evec.x);
    float ωdegrees = ω * (180 / Mathf.PI);
    //float ω = Mathf.Acos((Vector3.Dot(n, evec)) / (e * Vector3.Magnitude(n)));

    //Mean Anomaly 
    float MA = E - (e * Mathf.Sin(E));

    //Semi-Major Axis
    float a = 1 / ((2 / Vector3.Magnitude(r)) - (Mathf.Pow(Vector3.Magnitude(v), 2) / µ));

    //Apoapsis
    float ap = a * (1 + e);

    //Periapsis
    float pe = a * (1 - e);

    //Orbital Period
    float T = (2 * Mathf.PI) * Mathf.Sqrt(Mathf.Pow(a, 3) / µ)/60;

Edición más reciente: se solucionó el problema que tenía con la excentricidad incorrecta: estaba calculando incorrectamente la posición relativa.

Está utilizando la masa del barco para calcular la fuerza, pero no la divide por la masa cuando la aplica como aceleración (una verificación rápida, 1.595 (mantisa de su G) x 4194 (masa del barco) produce aproximadamente 6700 (mantisa coincidente de G correcto) así que ese es probablemente el problema). En general, es más fácil omitir la fuerza de cálculo y solo calcular la aceleración, que es independiente de la masa del barco. Y nuevamente estás mezclando unidades de 100m y 100km.
Lo intentaré e informaré. Entonces, ¿la velocidad debería ser 0.0765 en lugar de 76.5?
Probablemente esté bien si obtiene el número correcto de ceros en su G.
¿G cambia con la escala o es algo que debería ser constante? Tuve que hacerlo significativamente más pequeño en comparación con el cambio en todos los demás parámetros.
Claro que lo hace. Elaborado en respuesta.

Respuestas (1)

Gran G es 6.67408e-11 m 3 kg -1 seg - 2 .

Entonces, si usa unidades de 100 km de manera uniforme en lugar de unidades de m, eso es 5 magnitudes diferentes, por lo que G tiene que cambiar en 15 magnitudes porque la dimensión lineal está al cubo.

Las unidades de masa son 100 kg, G usa -1 de esas, por lo que G va en sentido contrario en 2 magnitudes.

No tengo idea de lo que estás haciendo con los segundos. Si los segundos son segundos (y se necesitan 90 minutos para completar una órbita), entonces no hay cambio en G. Si está usando algún otro factor de conversión, entonces duplique la cantidad de ceros por los que está cambiando los segundos para cambiar G.

En cuanto a la inestabilidad, eso es inevitable cuando haces simulaciones de pasos de tiempo de funciones continuas. Puedes dividir tu intervalo de tiempo de actualización de Unity en una pequeña cantidad fija y ejecutar tu función de simulación varias veces para cada cuadro de juego:

float accumulator = 0.0f;
float simtime = 0.001f;

void Update( void )
{
    accumulator += Time.deltaTime;
    while (accumulator > 0.0f)
    {
         SimulateGravityForTime( simtime );
         accumulator -= simtime;
    }
}

Esto ejecuta su sim una vez por cada milisegundo de tiempo transcurrido en el cuadro. Eso debería mantener las cosas bastante estables. El acumulador está ahí para retener fracciones de milisegundos de cuadro a cuadro. Pasará más tiempo de CPU haciendo cálculos repetidos, pero una computadora moderna debería poder permitírselo fácilmente.


Con respecto a las unidades, si estuviera en su lugar, separaría la vista (basada en las transformaciones de Unity) del modelo (la simulación física). Esto le permitiría ejecutar la simulación completamente en unidades estándar, eliminando mucha confusión y reduciendo la probabilidad de errores. Dentro del modelo de física, siempre usaría unidades m/kg/s y realizaría un seguimiento de las posiciones en vectores que no forman parte de las transformaciones de Unity. Una vez por cuadro, convertiría cuidadosamente a unidades de Unity y establecería las posiciones de las transformaciones.

+1 por gran respuesta, +1 por incluir un pequeño código, -1 por ayudar e instigar unidades físicas creativas e individualizadas sin siquiera una pequeña advertencia sobre lo que puede salir mal en el futuro. :) Incluso las pulgadas frente a los centímetros casi matan al Hubble.
Creo que he sido tan claro en las discusiones que he tenido con OP (en los comentarios en esta pregunta y en la anterior) que es importante prestar atención a las unidades. Dicho esto, agregaré un poco sobre la separación del modelo de vista.
Bien: comenzaré a trabajar en una forma de cambiar mi voto a +2 que merece su respuesta. Se trata de un desbordamiento de enteros y algo sobre el martilleo de filas y luego algunos taquiones, pero todavía no estoy allí. (humor)
@RussellBorogove Terminé la gravedad y usé su script acumulador aquí . Cuando convierto T en minutos, puede ver que coincide con el período orbital de 90 m aquí . He editado mi publicación para incluir el script de elementos orbitales. ¿Parece haber algún problema con mis elementos orbitales? Estoy seguro de que AP y PE están incompletos o son incorrectos, ya que necesito modificarlos por radio para obtener números cercanos, o la magnitud de r para obtener números precisos en t: 0.
@RussellBorogove, debe tenerse en cuenta que he convertido ω en grados en la salida de la segunda imagen, cuando normalmente está en radianes.
Bueno, la excentricidad debe estar cerca de cero (circular) en lugar de cerca de 1 (escape). No estoy seguro del resto.
Tendré que resolver eso ya que la excentricidad se usa en muchos de los otros cálculos.
No estoy seguro de mi cálculo de E ya que la notación que se muestra aquí me confunde, no sé si se supone que debo usar: Mathf.Atan2(Mathf.Tan(t / 2), Mathf.Sqrt((1 + e) / (1 - e)))o2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)))
@RussellBorogove Supongo que lo más probable es que tenga un problema de escalado de unidades con mi µ
Si aplico v = v / 100o v /= 100después de encontrar la velocidad v , el AP sale correcto, ¿entonces algo todavía está mal por un orden de magnitud en alguna parte?
La entrada 2en Atan2las bibliotecas matemáticas informáticas se refiere a dos argumentos, sin multiplicar por 2. Un argumento Atanno puede diferenciar entre ( + / + ) y ( - / - ) entradas, lo cual es importante en algunas aplicaciones trigonométricas. No sé si este es uno de ellos. La segunda de sus opciones se ve bien, la primera necesita un archivo 2 *. Si sus resultados son cuerdos para la mitad de la órbita y locos para la otra mitad, necesita Atan2.