| Autor |
Beitrag |
F34r0fTh3D4rk
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Mo 15.05.06 19:17
ok mein 10.000 ball topic
der ball verliert nach und nach an höhe, als hätte er reibung, ich kann mir beim besten willen nicht erklären warum (der code ist recht kompliziert gehalten, ich wollte überprüfen, wer schuld ist, mensch oder maschine  )
hier der source: unmuted-music.de/ball.zip
so langsam versteh ich die welt nicht mehr
mfg
|
|
Fabian W.
      
Beiträge: 1766
Win 7
D7 PE
|
Verfasst: Mo 15.05.06 19:30
Ich hab den Code nur überflogen, aber wenn der Ball den Rand verlässt rufst du doch Ball.StepBackward; auf, und dabei setzt du wenn ichs richtig gesehen habe die vektoren immer ein stückweit zurück position.x := position.x - velocity.x * timestep;Diese Änderung der Vektoren wirk sich nunmal auf die Geschwindigkeit aus.
mfg
//EDit kompletter quatsch was ich da plappere, das sind ja garkeine Vektoren... sry, ich schaus mir später an, aber im Moment bin ich vom ZK-lernen verwirrt... 
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Di 16.05.06 06:51
Hallo F34r0fTh3D4rk
Das Problem war das Du den Weg zwar zeitrelativ gemacht hast, aber nicht die Gravitation.
Ändere mal die Proceduren StepForward und StepBackward so ab:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TBall.StepForward; var timestep: double; begin timestep := TBTimer.compute; velocity.y := velocity.y + g * timestep; position.x := position.x + velocity.x * timestep; position.y := position.y + velocity.y * timestep; end;
procedure TBall.StepBackward; var timestep: double; begin timestep := TBTimer.compute; velocity.y := velocity.y - g * timestep; position.x := position.x - velocity.x * timestep; position.y := position.y - velocity.y * timestep; end; |
//zusatz:
Bringt leider nur den Effekt das der Ball langsamer fällt ung der "Energieverlust" geringer ist.
//Edit.
Ein weiterer Fehler ist das es sich hier um eine beschleunigte Bewegung handelt.
daraus ergibt sich die Formel:
Quelltext
Muss jetzt Schluss machen.
Vielleicht habe ich heute nachmittag mehr Zeit.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Di 16.05.06 07:24
Wieso nimmt die Geschwindigkeit bei 'StepBackward' ab? Nimm das weg und es klappt. Deine Geschwindigkeitsabnahme ist doch im StepForward drin (bei negativer Velocity).
Die Geschwindigkeit ändert sich aber auch, wie Tilo schon meint, zeitabhängig. ich habe es mit g*timestep*10 versucht und das sah ganz nett aus.
Besser wäre es noch, die Reflexion noch genauer zu gestalten, also nicht das der Ball unten halb verschwindet, sondern bis maximal (Y=Height-Radius) geht.
_________________ Na denn, dann. Bis dann, denn.
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 12:57
Hi F34r0fTh3D4rk
Grundsätzlich gleiches Problem wie HIER www.delphi-forum.de/...mp;highlight=gravity
Du berechnest die Simulation in dedizierten Zeitabschnitten. Dabei wirst du den exakten Zeitpunkt der Kollision nicht erwischen. Durch deine Schleifenbedingnung "Ball.position.y + Ball.radius <= IMG_Draw.Height;" brichst du ab, wenn der nächste Durchlauf über die Bande gehen würde.
Ergo verlierst du bei jeder Kollision ein Höhenpotential zwischen 0 - Radius. Ergo wird dein Ball immer niedriger hüpfen.
Lösung: Berechne die Kollision dediziert und exakt.
MfG Simon
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 12:58
das problem ist ja, dass wenn der ball über die kante hinausgeht jan hängen bleiben kann, ich kann natürlich auch die richtung abfragen, aber auf die dauer bringt das glaube ich auch nichts, ich glaube der fehler liegt wirklich bei der beschleunigung
// dort ist das gleiche problem, aber wie die dedizierte lösung funktioniert steht da nicht
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 13:13
Ich bin davon ausgegangen, das du das schon drin hast.
-> "velocity.y := velocity.y + g * timestep;"
den der Fehler ist ja klar!
wenn du mit Geschwindigkeiten rechnest, solltest du auch Geschwindigkeiten addieren/subtrahieren.
m/s = m/s + m/s² ? Nö oder? m/s = m/s + m/s² * s ist deutlich besser.
Das ändert aber nichts an dem inhärenten Fehler in der Simulationsberechnung (siehe Oben).
MfG
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 13:19
wie mache ich das denn am besten, von mir aus fang ich nochmal neu an, das soll ja möglichst accurate (mir fällt das deutsche wort grad net ein) sein, denn es soll ja nicht bei einem ball bleiben und reibung lass ich erstmal außen vor. die masse sollte da aber noch rein
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 13:52
Auf die Schnelle
Position:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TMainForm.T_DrawTimer(Sender: TObject); begin if Ball.position.y + Ball.radius > IMG_Draw.Height then begin repeat Ball.StepBackward; until Ball.position.y + Ball.radius <= IMG_Draw.Height; -> Ansatt einfach die Geschwindigkeit zu invertieren sollte hier gnau berechnet werden wann die Kollision sattfindet, welche Geschwindigkeit der Ball dabei hat, Welche Geschwindigkeit und Position der Ball zum Eventzeitpunkt hat end; if Ball.position.y + Ball.radius = IMG_Draw.Height then Ball.velocity.y := - Ball.velocity.y; Ball.StepForward; IMG_Draw.canvas.Rectangle(0, 0, IMG_Draw.Width, IMG_Draw.Height); DrawBall; end; |
Vorgehen:
Was habe ich?
Zeit t1 - Letzte Berechnung
Position X1 - Letzte Berechnung
Position b - Boden
Zeit t2 - Jetzige Berechnung
Irgentwo zwischen t1 und t2 knallt der Ball auf den Boden.
Berechnung von Irgentwo:
Bei t1 hat der Ball noch die Höhe s = x1-b. Das ist der Weg den der Ball noch zurücklegen wird.
Mit der Formal
s = a/2 * t² + v0 * t + s0 | v0 Geschwindigkeit bei t1; s0 = x1
kannst du t berechnen.
Damit kannst du exakt die Geschwindig bei der Kollision berechnen. Diese invertieren. Und abschliesend StepForward mit der Zeit t2-t berechnen.
Viel Spass bei der Umsetzung.
PS: Die Position für v = 0 sollte analog berechnet werden.
Zuletzt bearbeitet von Simon Joker am Di 16.05.06 13:56, insgesamt 1-mal bearbeitet
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 13:55
also liegt der fehler bei der kollision ?
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 13:59
Ja und bei dem was Tilo moniert hat. Wobei das mit Geschwindigkeit + Beschleunigung der bösere Fehler ist, weil das nicht nur eine Rundungsungenauigkeit ist sonder ein echter mathematischer Fehler, der von einem Physiklehrer mit "Fünf. Setzen!" kommentiert würde. 
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 14:15
vielleicht bringt ihr mir ein wenig licht in die sache, das wäre einfacher ^^ etwas zu einem bestimmten zeitpunkt berechnen usw ist ja kein ding, aber die zeit ist ja unbekannt, das ganze wird ja simuliert Oo
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 15:02
Ich hatte schon angedeutet.
Das ist die Formel die du braucht um den Zeitpunkt der Kollision zuberechnen.
s = a/2 * t² + v0 * t + s0
s -> verbleibende Höhe des Balls nach letzter Berechnung
a -> Erdbeschleunigung oder was auch immer
t -> Zeit die benötigt wird um die verbleibende Höhe zufallen DAS SUCHST DU!
v0 -> Geschwindigkeit nach letzer Berechnung
s0 -> Position nach letzer Berechnung
1. Gleichung lösen (Lösung Quatratische Gleichung - siehe Tafelwerk)
2. Zeitpunk der Kollision tk ergibts sich aus t1 + t mit t1 = Zeit letzter Berechnung
3. mit tk kannst du die Geschwindigkeit bei Kollision Vk berechnen
4. Vk invertieren
5. Position für Zeit der neuen Berechnung berechnen
Auslösen mußt due die Berechnung, wenn der Ball mit der nächsten Berechnung sicher über die Begrenzung (Boden) kommt. Das wäre bei dir die Abbruchbedingung deiner Repeat-Schleife.
MfG
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 15:06
ich versteh im moment nicht mal mehr die beschleunigung, also das hier:
Delphi-Quelltext
ist falsch, wie muss es dann heißen ?
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 15:22
V(t) = a * t ist die verkürtzte Schreibweise! Nur gültig wenn V0 = 0 also beginnend bei Stillstand
Korrekt ist
V(t) = V0 + a * t
wobei halt V0 die Anfangsgeschwindigkeit ist.
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Di 16.05.06 17:40
und das t wäre dann delta t oder wie ? wozu brauch ich das, denn in der simulation wird t ja nicht benötigt.
mit nem timer mit 50 ticks, habe ich ja eine 20stel sekunde, das muss ich dann noch einbeziehen oder ? vielleicht kann mir jemand ein musterbeispiel zeigen, sonst check ich das wohl nie ^^ (man schaue sich meine ganzen anderen topics dazu an, ich mach seit nem jahr fast nichts anderes und jedes mal verzweifle ich daran  )
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Di 16.05.06 20:13
Ja t ist dt, oder in deinem Beispiel timestep. Das ist so schon Ok. Du Berechnest ja die Veränderungen seit der letzten Berechnung, und dafür mußt du die Zeit verwenden, die seit dem vergangen ist.
| Zitat: |
... wozu brauch ich das, denn in der simulation wird t ja nicht benötigt. ...
|
Das ist Unsinn. Du verwendest sie ja schon und sie geht in jeder deiner Berechnungen ein. Du gibst sie nur nicht aus.
1.
Du hast einen elementaren Fehler begangen, denn hat Tilo im 3. oder 4. Post korrigiert. Das war einfach ne falsche Formel.
2.
Der zweite Fehler steckt sozusagen im System und tritt bei allen Simulationenen auf die einzelne Zustände berechnen. Für zeitliche Verläufe ist das noch am einfachsten zu verstehen.
Nehmen wir als Beispiel eine einfache lineare Bewegung. Sie lässt sich mit der Formel
s = V * t
beschreiben.
Berechnet oder mißt man jetzt jede Sekunde s hat man in 10 Sekunden 10 wunderschöne einzelne Werte. Stellt man sie dar ergibt sich eine bildschöner linearer Verlauf, anhand dessen wir uns nun erlauben Aussagen über den Zustand zwischen den Messpunkte zumachen. Und das ist genau das Problem, denn es ist ist FALSCH!! Diese so zuversichtlich geäußerte Voraussage trifft nur zu, wenn V konstant ist. Wenn diese Bedingung durch irgendetwas nicht erfüllt wird ist die Simulation nicht zutreffend.
Nehmen wir ein einfaches Beispiel. Du fährst mit dem Auto zur Arbeit und misst die Zeit beim Start und bei der Ankunft. Das Ergebniss ist eine Geschwindigkeit, die deine Fahr korrekt beschreibt. ABER sie sagt nichts über den Verlauf der Fahrt aus, ob du an Ampeln gestanden hast ect. wird nicht erfasst.
Durch Erhöhung der Messpunkte kann die Genauigkeit verbessert werden, aber grundsätzlich bleibt das Problem bestehen.
Keine gequantelte Messung/Berechnung kann einen stetigen Verlauf korrekt beschreiben, sondern sie bleibt immer einen Näherung.
So nun zu deinem Beispiel "Fallbeschleunigung". Die Formeln sind klar
V = V0 + a * t
s = a/2*t² + V0 * t + s0
Die Berechnungen erfolgen zu beliebigen Zeitpunkten und ergeben eigentlich einen schönen Verlauf.
Pseudo Code:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| a := -9.81; repeat T[x] := GetTime; V[x] := a * T[x]; s[x] := a / SQR(T[x]); V[x] := V[x-1] + a * (T[x] - T[x-1]); s[x] := a / SQR(T[x] - T[x-1]) + V[x-1] * (T[x] - T[x-1]) + s[x-1]; if s[x] < BodenHoehe then begin end; inc(x); until CancelParam; |
Die Störung im System ist nun die Kollision mit dem Boden. Diese wird irgendwann zwischen T[x-1] und T[x] stattfinden. Für eine Korrektur muß dieser Zeitpunkt (nennen wir ihn T[k]) genau berechnet werden. Also sozusagen eine Zwischenberechnung eingeschoben werden, die die Zustände zwischen unseren normalen Messpunkten bestimmt, damit wir darüber eine Aussage treffen können.
Wie das geht habe ich oben schon beschrieben.
MfG Simon
Edit: Korrektur der Formel
Zuletzt bearbeitet von Simon Joker am Mi 17.05.06 13:30, insgesamt 1-mal bearbeitet
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: Mi 17.05.06 10:19
Hallo,
Ich habe mal den Code etwas umgestellt und auf das wesentliche reduziert:
Damit man es physikalisch richtig betrachten kann:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TMainForm.DrawBall; begin IMG_Draw.canvas.Ellipse(IMG_Draw.width div 2-round(Ball.radius), IMG_Draw.Height-round(Ball.position.y - Ball.radius), IMG_Draw.width div 2+round(Ball.radius), IMG_Draw.Height-round(Ball.position.y + Ball.radius));
end; |
desweiteren das hier:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TMainForm.T_DrawTimer(Sender: TObject); begin Ball.NextStep; IMG_Draw.canvas.Rectangle(0, 0, IMG_Draw.Width, IMG_Draw.Height); DrawBall; end; |
Und die NextStepProcedure:
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:
| procedure TBall.NextStep; var timestep: double; timek,times:double; newVY:double; newY:double; va:double; begin timestep:=1; newY:=position.y+velocity.y*timestep-g*timestep*timestep/2; if newY<=radius then begin timek:=-(velocity.y/g)-sqrt((velocity.y*velocity.y)/(g*g)-2*position.y/g); va:=velocity.y-g*timek; times:=timestep-timek; position.y:=radius-va*times-g*times*times/2; velocity.y:=-va-g*times; end else begin position.y:=newY; velocity.y:=velocity.y-g*timestep; end; end; |
TimeStep habe ich auf 1 Sekunde gesetzt damit man das Problem erkennt:
in der markierten Zeile kommt als erste Zeit ein Wert von timek=1,2763256101 raus.
Der Fehler liegt also in der BErechnung der Kollisionszeit. Ich finde den Fehler aber nicht. Soweit ich es sehe ist die Formel physikalisch korrekt.
|
|
Simon Joker
      
Beiträge: 236
Erhaltene Danke: 1
|
Verfasst: Mi 17.05.06 13:29
Hi Tilo
Du hast einen Fehler bei der Normierung gemacht. s ist nicht gleich Null, wenn man nur mit den Koordinaten des Balles rechnet, sondern s = radius.
Damit ergibt sich das hier:
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:
| procedure TBall.NextStep; var timestep: double; timek,times:double; newVY:double; newY:double; va:double; p, q : single; begin timestep := 0.2; newY:= position.y + velocity.y*timestep + g/2*timestep*timestep; if newY <= radius then begin p := velocity.y/g; q := 2*(position.y-radius)/g; timek := -p + sqrt( p*p - q); va:= velocity.y + g*timek; times := timestep-timek; velocity.y := -va ; position.y := radius; position.y := position.y + velocity.y*times + g/2*times*times; velocity.y := velocity.y + g*times; end else begin position.y := newY; velocity.y := velocity.y + g*timestep; end; end; |
Man beachte: Wenn V in die Höhe positiv ist, ist die Fallbeschleunigung negativ, also g = -9.81; Meine Korrektur erfordert die negative Fallbeschleunigung.
MfG Simon
|
|
F34r0fTh3D4rk 
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Mi 17.05.06 17:22
ich glaube jetzt habe ichs verstanden:
/\t ist der die Zeit zwischen v0 und v1 bzw s0 und s1.
da immer in sekunden gerechnet wird, kann ich dort also mein timerinterval / 1000
nehmen, dann habe ich ja die interpolation der zeit.
und dieses /\ brauch ich auch, wenn ich die zeit der kollision berechnen will, bzw das ist dann ja ein neues.
ich werde das gleich mal alles ausprobieren
ich kann ne menge über schwingungen und wellen erzählen, aber mechanik ist zu lange her, da hatten wir in mathematik noch nicht einmal vektorrechnung
die timek zeile mag er nicht, ungültige gleichkomma operation Oo
Delphi-Quelltext 1:
| timek := -(-p + sqrt(-(p * p - q))); |
geht auch net, es liegt an der negativen zahl unter der wurzel, so gehts:
Delphi-Quelltext 1:
| timek := -(-p + sqrt(abs(p * p - q))); |
irgendwas stimmt da aber noch nicht, die geschwindigkeit ist ja nach unten hin positiv und die kollision erfolgt ja bei image1.height - radius oder position.y + radius >= image1.height, aber dann klappt das net so wirklich
|
|