Soll ich die Gravitationskonstante mit der Skala ändern und warum führen Änderungen der fps- und Zeitskala dazu, dass meine Umlaufbahn bricht?

Ich benutze Unity3D und schreibe C#

  • Erdmasse: 5.972e+22
  • Erdgeschwindigkeit: [0,0,0]
  • Erdradius: 63,71
  • ISS-Masse: 4194,55
  • Startgeschwindigkeit der ISS: [76.50, 0, 0]
  • ISS-Höhe: 4
  • Gravitationskonstante: 6,67408e-15

Alle Werte sind die realen Werte / 100, da ich die Dinge verkleinere. (z. B. Gravitationskonstante war 6,67408e-11 / 11 = 6,67408e-15.

Hier ist der Code...

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

Damit dies funktioniert, muss ich die Gravitationskonstante auf 1,59508e-21 einstellen

Hier ist ein Bild der Umlaufbahn, die rosa Linie ist der vergangene, nicht der zukünftige Pfad (die angezeigten berechneten Umlaufbahnelemente sind höchstwahrscheinlich falsch):

Hier ist ein Bild der Umlaufbahn, nachdem ich die Zeit beschleunigt habe:

Bearbeiten 1:

Mit dieser Beschleunigungsformel und dem ersten Teil von Russell Borogoves Antwort konnte ich mit diesen Werten eine kreisförmige Umlaufbahn erreichen:

  • Erdmasse: 5.972e+22
  • Erdgeschwindigkeit: [0,0,0]
  • Erdradius: 63,71
  • ISS-Masse: 4194,55
  • Startgeschwindigkeit der ISS: [0,0765, 0, 0]
  • ISS-Höhe: 4
  • Gravitationskonstante: 6,67408e-24 (verschoben -15 dann +2 Größenordnungen)

und dieser Code:

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

Bearbeiten 2: Gravitationsberechnungen mit Russell Borogoves Akkumulator-Skript unten hinzugefügt ...

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

Bearbeiten 3: Aktualisiertes Skript für Orbitalelemente (wahrscheinlich nicht 100% korrekt)

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

Letzte Änderung: Problem behoben, das ich mit falscher Exzentrizität hatte - die relative Position wurde falsch berechnet.

Sie verwenden die Schiffsmasse, um die Kraft zu berechnen, teilen sie jedoch nicht durch die Masse, wenn Sie sie als Beschleunigung anwenden (eine schnelle Überprüfung, 1,595 (Mantisse Ihres G) x 4194 (Schiffsmasse) ergibt etwa 6700 (übereinstimmende Mantisse des korrekten G) das ist wahrscheinlich das Problem). Es ist im Allgemeinen einfacher, die Rechenkraft zu überspringen und nur die Beschleunigung zu berechnen, die unabhängig von der Schiffsmasse ist. Und wieder verwechselst du 100-m- und 100-km-Einheiten.
Ich werde das mal ausprobieren und berichten. Die Geschwindigkeit sollte also 0,0765 statt 76,5 betragen?
Es ist wahrscheinlich in Ordnung, wenn Sie die richtige Anzahl von Nullen in Ihrem G haben.
Ändert sich G mit der Skalierung oder sollte es konstant sein? Ich musste es im Vergleich zu der Änderung aller anderen Parameter deutlich kleiner machen.
Natürlich tut es das. Als Antwort ausgearbeitet.

Antworten (1)

Großes G ist 6,67408e-11 m 3 kg -1 s - 2 .

Wenn Sie also einheitlich 100-km-Einheiten anstelle von m-Einheiten verwenden, sind das 5 Größenordnungen unterschiedlich, also muss sich G um 15 Größenordnungen ändern, da die lineare Dimension dreifach ist.

Masseneinheiten sind 100 kg, G verwendet -1 davon, also geht G um 2 Größenordnungen in die andere Richtung.

Ich habe keine Ahnung, was du mit Sekunden machst. Wenn Sekunden Sekunden sind (und es 90 Minuten dauert, um eine Umlaufbahn zu absolvieren), ändert sich G nicht. Wenn Sie einen anderen Umrechnungsfaktor verwenden, verdoppeln Sie die Anzahl der Nullen, um die Sie Sekunden verschieben, um G zu ändern.

Die Instabilität ist unvermeidlich, wenn Sie Zeitschrittsimulationen kontinuierlicher Funktionen durchführen. Sie können Ihre Unity Update-Zeitscheibe in ein kleines festes Quantum aufteilen und Ihre Simulationsfunktion mehrmals für jeden Spielrahmen ausführen:

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

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

Dadurch wird Ihr Sim einmal für jede im Frame verstrichene Millisekunde ausgeführt. Das sollte die Dinge ziemlich stabil halten. Der Akkumulator dient dazu, Bruchteile von Millisekunden von Frame zu Frame zu speichern. Sie verbringen mehr CPU-Zeit mit wiederholten Berechnungen, aber ein moderner Computer sollte sich das problemlos leisten können.


In Bezug auf die Einheiten würde ich an Ihrer Stelle die Ansicht (basierend auf Unity-Transformationen) vom Modell (der Physiksimulation) trennen. Auf diese Weise könnten Sie die Simulation vollständig in Standardeinheiten ausführen, wodurch viel Verwirrung vermieden und die Wahrscheinlichkeit von Fehlern verringert wird. Innerhalb des Physikmodells würden Sie immer m/kg/s-Einheiten verwenden und Positionen in Vektoren verfolgen, die nicht Teil von Unity-Transformationen sind. Einmal pro Frame würden Sie sorgfältig in Unity-Einheiten konvertieren und die Positionen der Transformationen festlegen.

+1 für eine großartige Antwort, +1 für das Einfügen eines kleinen Codes, -1 für die Unterstützung und Unterstützung kreativer und individualisierter physischer Einheiten, ohne auch nur einen kleinen Vorbehalt darüber zu haben, was später schief gehen kann. :) Sogar Zoll gegen Zentimeter hätte Hubble fast getötet.
Ich denke, ich habe in den Diskussionen, die ich mit OP geführt habe (in Kommentaren zu dieser und der vorherigen Frage), deutlich gemacht, dass es wichtig ist, auf die Einheiten zu achten. Abgesehen davon werde ich etwas über die Trennung von Ansichtsmodellen hinzufügen.
Gut - ich werde anfangen, an einer Möglichkeit zu arbeiten, meine Stimme auf +2 zu ändern, was Ihre Antwort verdient. Es beinhaltet Integer-Überlauf und etwas über Row-Hammering und dann einige Tachyonen, aber ich bin noch nicht so weit. (Humor)
@RussellBorogove Ich habe die Schwerkraft beendet und Ihr Akkumulator-Skript hier verwendet . Wenn ich T in Minuten umwandle, können Sie sehen, dass es hier mit der 90-m-Umlaufzeit übereinstimmt . Ich habe meinen Beitrag so bearbeitet, dass er das Skript für Orbitalelemente enthält. Scheint irgendetwas mit meinen Orbitalelementen nicht in Ordnung zu sein? Ich bin mir sicher, dass AP und PE unvollständig oder falsch sind, da ich sie nach Radius ändern muss, um nahe liegende Zahlen zu erhalten, oder nach der Größe von r, um genaue Zahlen bei t: 0 zu erhalten.
@RussellBorogove Es sollte beachtet werden, dass ich ω in der Ausgabe im zweiten Bild in Grad konvertiert habe, wenn es normalerweise in Radiant ist.
Nun, die Exzentrizität sollte nahe Null (kreisförmig) statt nahe 1 (Flucht) sein. Beim Rest bin ich mir nicht sicher.
Ich muss das herausfinden, da Exzentrizität in vielen anderen Berechnungen verwendet wird.
Ich bin mir meiner Berechnung von E nicht sicher, da mich die hier gezeigte Notation verwirrt, ich weiß nicht, ob ich verwenden soll: Mathf.Atan2(Mathf.Tan(t / 2), Mathf.Sqrt((1 + e) / (1 - e)))oder2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)))
@RussellBorogove Ich vermute, dass ich höchstwahrscheinlich auf ein Problem mit der Einheitenskalierung mit meinem µ stoße
Wenn ich anwende v = v / 100oder v /= 100nachdem ich die Geschwindigkeit v gefunden habe , kommt der AP richtig heraus, also ist irgendwo noch etwas um eine Größenordnung daneben?
Das 2in Atan2in mathematischen Computerbibliotheken bezieht sich auf zwei Argumente, die nicht mit 2 multipliziert werden. Ein Argument Atankann den Unterschied zwischen ( + / + ) und ( - / - ) Eingaben nicht erkennen, was in einigen Trig-Anwendungen wichtig ist - ich weiß es nicht weiß nicht, ob das einer von ihnen ist. Die zweite Ihrer Optionen sieht richtig aus, die erste benötigt eine 2 *. Wenn Ihre Ergebnisse für die Hälfte des Orbits vernünftig und für die andere Hälfte verrückt sind, benötigen Sie Atan2.