Winkel Theta und Richtung berechnen um Koordinate zu treffen, Ballistik



  • Hallo,

    ich hab' vor drei Wochen angefangen mir C++ beizubringen, durch Bücher und Online-Tutorials. Momentan arbeite ich an einem DOS-Box-Programm, einem Feuerleitrechner welchen ich als Hilfe in eine Militärsim nutzen möchte.

    Man gibt die Koordinaten vom Geschütz und Ziel ein. Der Rechner gibt dann mit entsprechender Mündungsgeschwindigkeit den Winkel auf den das Geschützrohr eingestellt werden muss und die Richtung in "mil" (Strich o. Milliradian) aus, in die das Geschütz ausgerichtet werden muss.

    Probleme habe ich damit den Winkel Theta (θ) mit folgender Formel auszurechnen:
    https://wikimedia.org/api/rest_v1/media/math/render/svg/4db61cb4c3140b763d9480e51f90050967288397

    ..und den richtigen Wert für Richtung zu errechnen

    Beim kompilieren gibt es keine Fehler, trotzdem sind beide Ergebnisse immer zwei bestimmte falsche Werte, die sich auch nach Programm-Neustart und Änderung der Koordinaten nicht verändern.

    Unten nun der Code, Variablen hab' ich schon mit Werten initialisiert.
    Achtung ! In die Theta-Formel hab' ich einen Umbruch gesetzt damit sie ins Forum passt.

    Ergebnisse laut Excel sollten folgende sein:
    Richtung = 310° = 5516 mil
    Winkel Theta = 63° = 1127 mil

    Berechnung Theta:

    #include <math.h>
    
    #define PI 3.141592653589793
    
    using namespace std;
    
    int main()
    {
        int x1 = 8296, y1 = 10603;
        int x2 = 7081, y2 = 11633;
        int h1 = 12;
        int h2 = 27;
        int Muendungsgeschw = 140;
        int a = x1 - x2;
        int b = y1 - y2;
        int Entfernung;
        long double A = pow(a, 2);
        long double B = pow(b, 2);
        Entfernung = sqrt(A+B);
        int Entfernung_2 = pow(Entfernung, 2);
        int Entfernung_4 = pow(Entfernung, 4);
    
        double Gravitation = 9.81;
        double Winkel1;
        int H = h1 - h2;
    
        long double Muendungsgeschw_2 = pow(Muendungsgeschw, 2);
        long double Muendungsgeschw_4 = pow(Muendungsgeschw, 4);
    
        Winkel1 = atan(Muendungsgeschw_2 + sqrt(((Muendungsgeschw_4 - Gravitation)*
    ((Gravitation*Entfernung_2)+(2*H*Muendungsgeschw_2))))/(Gravitation*Entfernung))*180 / PI;
        return Winkel1*17.7778;
    }
    

    Berechnung Richtung

    #include <math.h>
    
    #define PI 3.141592653589793
    
    using namespace std;
    
    int main()
    {
        int x1 = 8296, y1 = 10603;
        int x2 = 7081, y2 = 11633;
        int h1 = 12;
        int h2 = 27;
        int UngfRichtung = 270;
        //Wenn Ungefähre Richtung zum Ziel 0°-180° = 90, sonst = 270
        double a = x1 - x2;
        double b = y1 - y2;
        double c;
        double Richtung;
        c = a / b;
        Richtung = UngfRichtung - ( atan(c)*180 / PI ) ;
        return Richtung*17.7778;
    }
    

    Ich würde mich über Antwort, Korrektur oder besseren Lösungsvorschlag sehr freuen. Danke im Voraus für die Hilfe.



  • Benutze cout, um dir das Ergebnis anzuzeigen, nicht den Exitcode von main! Der ist nicht dafür gemacht.



  • Hallo Jan,

    Willkommen im C++-Forum.

    manni66 sagte es schon; gebe Deine Ergebnisse über cout aus.
    Bei der Formel hilft korrektes Abschreiben. Produkte brauchst Du nicht in Klammern setzen, Punktrechnung geht auch in C++ vor Strichrechnung.

    Benenne die Variablen möglichst so wie sie auch z.B. in der Formel heißen; also z.B. ' g ' statt ' Gravitation '. Oder benenne sie so, dass Du ihre Herkunft wieder erkennst; also besser ' dx ' statt ' a ' (für Delta-X).
    Benutze durchweg ' double ' als Datentyp für physikalische Werte, dann liegst Du bei Berechnungen dieser Art immer richtig. Mit ' int ' kann es schwer zu findende Fehler geben!

    Wenn Du von 1 nach 2 schießt, so müssen alle Differenzen wert_2-wert_1 heißen und nicht umgekehrt!
    Mache globale Konstanten 'const'. So stellst Du besser heraus, dass es sich hier um Konstanten handelt und Du änderst sie nicht aus Versehen.
    Runde keine Werte, wenn es nicht nötig ist; hier grad2mil=160./9 .

    Wenn man Winkel berechnet, die im Intervall von -Pi bis +Pi liegen, so benutzt man std::atan2.

    Anbei eine verbesserte Version Deines Programms:

    #include <cmath>    // <math.h> ist veraltet!
    #include <iostream> // cout, etc.
    
    namespace
    {
        double const PI = std::acos(-1.);
        double const rad2Grad = 180./PI;
        double const g = 9.80665;   // Normfallbeschleunigung nach DIN 1305
        double const grad2mil = 160./9; // 1mil = 1Strich = 1/1600 eines Viertelkreises
    }
    
    // rechnet einen Winkel in rad im Intervall [-pi .. +pi] nach Grad in das Intervall [0 .. 360] um
    double toGrad( double winkel_in_rad )
    {
        double ergebnis = winkel_in_rad * rad2Grad;
        if( ergebnis < 0 )
            ergebnis += 360.;
        return ergebnis;
    }
    
    int main()
    {
        using namespace std;    // möglichst lokal verwenden
        double x1 = 8296, y1 = 10603;
        double h1 = 12;
        double x2 = 7081, y2 = 11633;
        double h2 = 27;
        double v = 140;
    
        double dx = x2 - x1; // es wird von 1 nach 2 geschossen!
        double dy = y2 - y1;
        double Entfernung_2 = pow(dx, 2) + pow(dy, 2);    // Quadrat der Entfernung
        double Entfernung = sqrt( Entfernung_2 );
        double dh = h2 - h1; 
        double v_2 = pow(v, 2);
        double v_4 = pow(v, 4);
    
        double theta = toGrad( atan( (v_2 + sqrt( (v_4 - g*(g*Entfernung_2 + 2*dh*v_2)) )) / (g*Entfernung)) );
        cout << "theta=" << theta << "Grad =" << theta*grad2mil << "mil" << endl;
        double richtung = toGrad( atan2(dx, dy) );
        cout << "richtung=" << richtung << "Grad = " << richtung*grad2mil << "mil" << endl;
    
        return 0;   // 0 -> OK
    }
    

    ... und mache Dir mal Gedanken um das '+/-'Zeichen in der Formel!
    Unter Umständen ist für Deine Anwendung das '-' die bessere Wahl.

    Gruß
    Werner



  • Herzlichen Dank euch beiden für die Hilfe ! Ich konnte den Code von Werner gestern noch im Testprojekt ausprobieren, funktioniert.

    Ursprünglich hatte ich die Berechnungen für Entfernung, Winkel und
    Richtung auf drei Quelldateien aufgeteilt. Für's Forum hab' ich das in
    "funktionsfähigen" Code zusammenkopiert, daher der Exit durch "return irgendeinErgebnis".

    Benutze cout, um dir das Ergebnis anzuzeigen, nicht den Exitcode von main!
    Der ist nicht dafür gemacht.

    Wenn ich nun wieder auf verschiedene Dateien aufteile sollte ich dann durch
    cout direkt das Ergebnis aus der Funktion ausgeben lassen, statt den Wert erst
    in eine Variable ins main() zu bringen und dann dort durch "cout" ausgeben zu lassen ?

    Und ich würde gerne, da ich nun mit den Grundlegenden Funktion tatsächlich auf die richtigen Ergebnisse kommen kann, einmal die Konstanten von Werner und
    die Variablen für die Koordinaten als Globale Variablen, in einer der Headerdateien, für alle Quellcodedateien verfügbar machen.

    Ich werd' mich heut Nachmittag mal dransetzten und gucken ob das alles so klappt.
    Nochmals Danke für die Hilfe !



  • Jan. schrieb:

    Wenn ich nun wieder auf verschiedene Dateien aufteile sollte ich dann durch
    cout direkt das Ergebnis aus der Funktion ausgeben lassen, statt den Wert erst
    in eine Variable ins main() zu bringen und dann dort durch "cout" ausgeben zu lassen ?

    Wenn du die Funktionen nur genau für dieses eine Programm brauchst, kannst du cout direkt in der Funktion benutzen. Allgemeiner verwendbar wird es mit Returnwerten.

    Jan. schrieb:

    Und ich würde gerne, da ich nun mit den Grundlegenden Funktion tatsächlich auf die richtigen Ergebnisse kommen kann, einmal die Konstanten von Werner und
    die Variablen für die Koordinaten als Globale Variablen, in einer der Headerdateien, für alle Quellcodedateien verfügbar machen.

    Das ist keine gute Idee. Benutze lokale Variablen für die Benutzereingabe. Diese Werte kannst du dann per Parameter an die Funktionen übergeben.



  • Okay, danke für den Hinweis.

    In der momentanen Programmversion (noch ohne Werners Lösung) werden immer wieder eigendlich gleiche
    Parameter abgefragt:

    int main ()
    {
    
    cin >> x1 >> y1 >> x2 >> y2;
    
    Entfernung = EntfernungRechnen (x1, x2, y1, y2);
    winkel = WinkelRechnen (x1, x2, y1, y2, h1, h2, v);
    }
    

    Ich dachte ich speichere die x1 bis y2 Variablen einfach in globalen Variablen
    und die Funktionen greifen sich diese dann ab. Aber so geht's wohl nicht. Hät ich spätestens heut Nachmittag gemerkt. 😃

    Gedanke ist keine oder wenig Redundanzen zu haben.

    Aber ich will hier auch nicht mit solchem Anfängerkram nerven.
    Ich steh gerade noch am Anfang. :p



  • Selbstverständlich geht das auch mit globalen Variablen. Das ist aber keine gute Lösung. Was machst du z.B., wenn du ein zweites Ziel anpeilen willst?

    C++ bietet aber auch Möglichkeiten, Werte zu größeren Einheiten zusammenzufassen. Beispiel:

    struct Point { int x; int y; };
    
    int main ()
    {
     Point geschuetz, ziel;
     cin >> geschuetz.x >> geschuetz.y >> ziel.x >> ziel.y;
    
     Entfernung = EntfernungRechnen (geschuetz, ziel);
     winkel = WinkelRechnen (geschuetz, ziel, h1, h2, v);
    }
    

Anmelden zum Antworten