Wurfparabel mit Radiant berechnen

Neue Frage »

Dogatos Auf diesen Beitrag antworten »
Wurfparabel mit Radiant berechnen
Hallo, ich habe ein Projekt, die Wurfkurve im Browser darzustellen. Die Scriptsprache die ich dafür benutze kennt aber keine Winkel, daher muss ich sie folgendermassen umrechnen: Winkel *PI / 180
Dies habe ich in meine Formeln reineditiert, aber jetzt stimmt es nicht mehr. Weiss jemand warum, oder wie man dies anders rechnet?
Guest4432 Auf diesen Beitrag antworten »

Es wäre praktisch, wenn du erwähnen würdest, welche Skriptsprache es ist und beschreibst, was "jetzt stimmt es nicht mehr" bedeutet (vielleicht wenn möglich sogar einen kleinen Ausschnitt aus dem Programm geben, wobei das hier eigentlich ein Mathematik- und kein Informatik-Forum ist)

Rechnest du vielleicht an anderen Stellen aus Versehen noch mit DEG und verfälschst damit das Ergebnis? Hast du vielleicht irgendwo Konstanten falsch umgerechnet? Irgendwo die Umstellung vergessen?

PS: Du meinst wohl sie unterstützt kein Grad (DEG). Die Angabe von Winkeln in Radian (RAD) ist soweit mir bekannt die natürlichste die es gibt und eine Angabe von Winkeln in Grad eher aufgesetzt. D.h. Pi ist für mich eher ein Winkel als die dazugehürige Bezeichnung 180°.
Dogatos Auf diesen Beitrag antworten »

Da es ein Mathe Forum ist, wollte ich eigentlich keinen Code posten. Und ja ich meine Grad. Es handelt sich um HTML5 und Javascript.

function Grad2Radiant(x) {
return x * Math.PI / 180.0;
}

Ich hab mir eine Funktion geschrieben, die ich folgendermassen aufrufe: Grad2Radiant(50). Der Winkel 50° wird dann umgerechnet, und an der stelle an der diese Zeile steht wieder zurück gegeben, damit ich nicht immer wieder das selbe schreiben muss.

var v0 = 2; // Anfangsgeschwindgkeit in m/s
var winkel = 50; // Winkel in Grad
var h = 1; // Hoehe in m
var g = 9.81; // Gravitationskonstante

var a = g / 2;
var b = v0 * (Math.sin(Grad2Radiant(winkel))) - h;
var c = -h;
var t = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / g;
var s = v0 * (Math.cos(Grad2Radiant(winkel))) * t;

var = Variabeln, die man später wieder einsetzen kann. zb bei var a = g / 2; wird die Variable g verwendet. Math.sqrt ist die Wurzel. Math.pow(b, 2) bedeutet b^2.

Das ist eigentlich alles zur berechnung, nacher wird noch gezeichnet, wer das volle script will:

Zitat:

<!DOCTYPE html>
<html>
<body>
<div style="text-align: center;">
<canvas id="Diagramm" height="500" width="900" style="border: 3px solid black">Ihr Browser unterstützt kein Canvas</canvas><br />
<button onClick="wurfparabel();">Start</button>
</div>
<script type="text/javascript">
var canvas = document.getElementById('Diagramm');
var context = canvas.getContext('2d');

function Grad2Radiant(x) { //Winkel von Grad nach Radiant umrechnen
return x * Math.PI / 180.0;
}

function wurfparabel() {
var v0 = 2; // Anfangsgeschwindgkeit in m/s
var winkel = 50; // Winkel in Grad
var h = 1; // Hoehe in m
var g = 9.81; // Gravitationskonstante

var a = g / 2;
var b = v0 * (Math.sin(Grad2Radiant(winkel))) - h;
var c = -h;
var t = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / g;
var s = v0 * (Math.cos(Grad2Radiant(winkel))) * t;

var x = 0;
var y = 500;

// Skalierung
var scalex = 900 / s; //Teilt den Canvas in die 900 Pixel Breite ein
var scaley = 100;
var steps = 100; //Setzt 100 'Steps' als Genauigkeit

context.moveTo(x, y - h * scaley); //Setzt den Anfangspunkt zur Anfangshöhe h
for(var i = 0; i <= steps; i++) {
var sx = s * i / steps;
var sy = -a * Math.pow(sx / (v0 * Math.cos(Grad2Radiant(50))), 2)
+ sx / (v0 * Math.cos(Grad2Radiant(50)))
* v0 * Math.sin(Grad2Radiant(50))
+ h;
context.lineTo(sx * scalex, y - sy * scaley);
context.strokeStyle = 'red';
context.stroke();
}
}
</script>
</body>
</html>


Stimmt aber eben wegen den Berechnungen nicht.
Bakatan Auf diesen Beitrag antworten »

1. Codestil
  • Bitte benenne deine Variablen nicht a,b,c. Gib ihnen Namen wie z.B. "xStartSpeed" oder "positiveSolutionOfTimeWhereAltitudeZero" (ja, solch lange Namen sind besser als "t").

  • Schreib nicht alles doppelt und dreifach: gerade im unteren Bereich des codes taucht oft "Grad2Radiant(50)" auf. Dies sollte eigentlich ein "Grad2Radiant(winkel)" sein und dies sollte wiederum eigentlich einen eigenen Bezeichner wie "winkelInRad" (bei mir wäre das einfach "angle" oder "winkel", da ich RAD als natürlicher auffasse, aber bei dir ist das ja bereits für den Winkel in DEG vergeben) bekommen. Als nächstes tauchen sehr oft Ausdrücke wie "v0 * Math.cos(Grad2Radiant(50))" auf. Das sollte eigentlich wie oben beschrieben "v0 * Math.cos(winkelInRad)" sein und das wiederum sollte einen eigenen Bezeichner "xStartSpeed" bekommen. Die Variablen "a", "c", "x" und "y" empfinde ich als nicht notwendig.

  • Ich kann nicht feststellen, ob deine Einrückung bei dem übergang zum Forum verloren gegangen ist oder einfach nie existiert hat. In zweitem Fall: Es ist Standard, u.a. bei öffnenden lokalen Scope-Bereichen einzurücken (also wenn eine geschweifte Klammer auf geht). Das erhöht die Lesbarkeit enorm!

  • Wenn die Bezeichner und Operationen zusammen nicht absolut selbsterklärend sind schreibe mehr Kommentare in den Code (da die Bezeichner z.B. "a", "b", "c" sind ist die Bedeutung eben nicht erkennbar). Hier ist der Code zwar relativ kurz und du hattest vermutlich ursprünglich nicht vor, ihn an andere weiter zu geben, allerdings ist er zusammen mit den vollkommen bedeutungslosen Bezeichnern nahezu unlesbar. Dazu kommen Einführungen wie "a = g/2", welche bekannte Formeln zerstückeln. Man erkennt also nicht einmal mehr Dinge wie 1/2 * g * t² (t hier als Zeit) sondern sieht nur noch at² was nicht sofort als Formel ins Auge springt.

2. Fehler

Essentiell
  • Zitat:
    var b = v0 * (Math.sin(Grad2Radiant(winkel))) - h;
    Das "-h" am Ende ergibt für mich keinerlei Sinn. Erstens ziehst du eine Strecke von einer Geschwindigkeit ab, zweitens habe ich im späteren Verlauf auch sonst keinen Grund hierfür gesehen.

  • Zitat:
    var t = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / g;
    Kommentare! Hier ist es essenziell, sich und anderen klar zu machen, was man tut. Selbst ein einfaches "// Eine der Lösungen von gt²/2 + vt + h = 0 durch Mitternachtsformel" würde Wunder tun, denn dort könntest du deine anderen beiden Fehler bemerken:
    a) Vorzeichenfehler! Später hast du gut erkannt, dass die Gravitation nach unten zeigt und die initiale Geschwindigkeit nach oben. Es muss also "-gt²/2 + vt + h = 0" gelöst werden.
    b) Nach der Korrektur ist die Wahl der Lösung falsch und die sich ergebene Zeit negativ. Das hat schwerwiegende Folgen, man sieht eine (womöglich noch durch dadurch entstehende bugs kaputte) Spiegelung einer Rückwärtsprojektion der Flugkurve.

Details
  • Die Skalierung in Y-Richtung anders zu wählen als in X-Richtung führt zu Streckungen, die Winkel verzerren. Das kann einem ziemlich komisch vorkommen, wenn man einen Winkel einstellt aber im Bild es nach einem anderen aussieht.

  • Das generelle Prinzip, ständig von Geschwindigkeit auf Strecke und dann wieder zurück zu Zeit zu rechnen ist relativ ungünstig. Computer haben keine Zahlen mit unbegrenzter Genauigkeit und so entstehen immer mehr und mehr Rundungsfehler. Hier ist das dank kurzer Rechnung noch unkritisch, man sollte allerdings generell solch unnötigen hin und her Multiplikationen bzw Divisionen vermeiden. Deshalb würde ich im Loop lieber die Zeit inkrementieren anstatt der zurück gelegten X-Distanz.

3. Vorschlag für erste Ausbesserungen

Dies ist keineswegs eine perfekte Lösung, es ist um die vier Uhr morgens und ich habe keine Zeit es weiter zu verbessern. So finde ich es z.B. unpraktisch, dass sich die Skalierung ändert, je nachdem wie weit die Flugkurve ist. Ohne eine Skala an den Seiten ist das meines Erachtens ziemlich verwirrend. Zudem denke ich, ein klassischer leap-frog könnte schöner zu lesen und schneller zu berechnen sein. Viele checks fehlen ausserdem - bei 90° entsteht eine Division durch Null, abgesehen davon, dass durch Skalierung kein sinnvolles Ergebnis möglich ist. Meine Namensgebung ist auch durch fortgeschrittene Uhrzeit bedingt eher übereilt gewählt worden - vermutlich kann man leicht kürzere und prägnantere Bezeichner wählen. Optimal formatiert für Leserlichkeit ist das Dokument wohl auch nicht.

Zudem möchte ich Anmerken, dass in der Regel solche Arten von Korrekturen hier nicht stattfinden. Meiner Meinung nach gab es hier allerdings nicht viele Möglichkeiten, Hinweise zu geben ohne gleich die ganze Lösung darzustellen. Zudem war vieles über Codestil.
code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
<!DOCTYPE html>
<html>
<body>
<div style="text-align: center;">
<canvas id="Diagramm" height="500" width="900" style="border: 3px solid black">Ihr Browser unterstützt kein Canvas</canvas><br />
<button onClick="wurfparabel();">Start</button>
</div>
<script type="text/javascript">
var canvas = document.getElementById('Diagramm');
var context = canvas.getContext('2d');

//Winkel von Grad nach Radiant umrechnen
function Grad2Radiant(x) {
	return x * Math.PI / 180.0;
}

function wurfparabel() {
	var initialVelocity = 20.0; // Anfangsgeschwindgkeit in m/s
	var winkel = 90.0; // Winkel in Grad
	var winkelInRad = Grad2Radiant(winkel);
	var startHoehe = 5.0; // Hoehe in m
	var g = 9.81; // Gravitationskonstante

	var yStartSpeed = initialVelocity * Math.sin(winkelInRad);
	var xStartSpeed = initialVelocity * Math.cos(winkelInRad);
	
	// Mitternachtsformel. -gt²/2 + yStartSpeed * t + h = 0, positive Lösung
	var positiveSolutionOfTimeWhereAltitudeZero = (-yStartSpeed - Math.sqrt(Math.pow(yStartSpeed, 2) - 4 * (-g / 2) * startHoehe)) / (-g);
	
	var XDistanceUntilAltitudeZero = xStartSpeed * positiveSolutionOfTimeWhereAltitudeZero;

	// Skalierung
	var scaleX = canvas.width / XDistanceUntilAltitudeZero; // Streckt/staucht den Canvas so, dass Abwurfpunkt genau am linken und Auftreffpunkt am rechten Rand ist
	var scaleY = canvas.width / XDistanceUntilAltitudeZero; // Selbe Streckung um Proportionen und Winkel zu erhalten
	var steps = 100; //Setzt 100 'Steps' als Genauigkeit

	// Bedenke, dass bei canvas (0,0) linke oben ist und die Y-Achste nach unten läuft.
	context.moveTo(0, canvas.height - startHoehe * scaleY); //Setzt den Anfangspunkt zur Anfangshöhe startHoehe
	var currentCoordX, currentCoordY, time;
	for(var i = 0; i <= steps; i++) {
		time = positiveSolutionOfTimeWhereAltitudeZero * i / steps;
		currentCoordX = xStartSpeed * time;
		// Altitude is -gt²/2 + yStartSpeed * t + startHoehe
		currentCoordY = -(g / 2) * Math.pow(time, 2) // Jetzt sogar eine sofort erkennbare Formel
				+ yStartSpeed * time
				+ startHoehe;
		context.lineTo(currentCoordX * scaleX, canvas.height - currentCoordY * scaleY);
		context.strokeStyle = 'red';
		context.stroke(); 
	}
}
</script>
</body>
</html>
Dogatos Auf diesen Beitrag antworten »

1. Die Variabeln sind so benannt, weil es alles Buchstaben sind, die in Formeln so verwendet werden. t, s, v usw. die a, b und c Variabeln sind von der Quadratischen Gleichung. Ich geb zu, da ists nicht wirklich offensichtlich, aber sind eben nur Platzhalter um in der Formel einzufügen, ich hatte sowieso vor die noch direkt in die Formel rein zu schreiben, aber wenn dann etwas nicht stimmt, ists viel zu unübersichtlich.

2. Oh, das hab ich übersehen, dass ich 50 anstatt die Winkel-Variable benutzt habe. War auch 4 Uhr Morgens oder so, vielen Dank. smile

3. Geht bei einem Zitat verloren, Code habe ich nicht gefunden, aber werde ich das nächste mal verwenden.

4. Der Schlaggebende Punkt, der in diesem Fall sogar sehr wichtig ist, ist, dass das Script noch lange nicht fertig ist. Ich bin noch am testen und habs deshalb gern so einfach wie möglich, und schreib nicht einfach alles fertig und teste es dann irgendwie und muss alles neuschreiben, weil irgendwo was nicht stimmt. Die Variabeln mit dem Winkel usw sind Platzhalter, diese werden später Dynamisch und durch Boxen verändert, also ändert sich auch der Wert, kann zb auf einmal 30Meter sein, deshalb braucht es eine Skalierung. In solchen Fällen geb ich das Script selten weiter, aber es wurde im vorherigen Post danach gefragt. Ich ändere viel daran, deshalb kommentier ich lieber nur Sachen, die sich wahrscheinlich nicht ändern und die anderen lass ich noch offen. Der Rahmen wird auch noch angepasst, der sieht momentan so aus, aber beachte, dass auch dieser noch nicht fertig ist, bringt ja nichts, wenn ich den Ramen an einem Script anpasse, das nicht funktioniert:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
        function Rahmen(){
	        context.moveTo(20,0);
	        context.lineTo(20,500);
	        context.lineTo(10,510);
	        context.moveTo(20,500);
	        context.lineTo(920,500);
	        context.lineWidth = 2;
                context.stroke(); 
                context.fillText('0',1, 519);
                context.fillText('x',900, 519);
	        context.fillText('y',1, 20);
	    }


Da kommt dann noch eine Skalierung hin, die sich auch Dynamisch anpasst.



Wie schon in Punkt 4 erwähnt, das Script enthält noch nicht alle Basisfunktionen, und da ich auch keine komplette Lösung wollte hab ich das auch im Anfangspost nicht erwähnt, aber dein Script ist sicher trotzdem nützlich, sich mal durchzuschauen.

Muss jetzt leider los, den ersten Fehler hab ich schon behoben, den zweiten noch nicht, mach ich wenn ich wieder zurück komme, und wenn sich was ändert, schreib ich nochmal.

Ich danke dir aufjedenfall für eine Mühe, hilft mir sicher. smile
Neue Frage »
Antworten »



Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »