Physikalische Beschleunigung richtig in Simulation abbilden



  • Hi,

    im Rahmen eines Praktikum-Projekts programmiere ich gerade eine Simulation und arbeite mich dabei in WPF ein. Es geht u.a. um beschleunigte Bewegung, bei der bei mir was falsches rauskommt und ich nicht genau weiss woran das liegt. Vielleicht kann mir jemand einen Tipp geben.
    Ein Transport-Plattform mit Vmax = 1 m/s und a = 0,3 m/s^2 wird simuliert.
    Für die zeitliche Auflösung habe ich mir einen Timer eingerichtet, der alle 1/10 sec tickt und dann im Timer-Event die Berechnungen ausführt.

    Deklariert habe ich die Properties so:

    Vector position = new Vector(0, 0);
    Vector velocity = new Vector(0, 0);
    Vector acceleration = new Vector(0.03, 0);
    

    Und im Timer-Event läuft die Berechnung so:

    velocity += acceleration;
    position += velocity;
    

    (velocity wird begrenzt auf 1)

    Eine simulierte Strecke von 8 m Länge wird auf 800 Pixel abgebildet, auf der ich ein rectangle fahren lasse. Mit einem anderen stopwatch-Timer messe ich knapp 16 sec, die das rectangle für die Strecke braucht (~15,75 sec).
    Das ist aber glaube ich falsch, da ja schon nach 3 sec die Plattform 0,9 m/s hat und dabei 1,8 m zurückgelegt hat (hoffentlich ist mein Physik-Verständnis da richtig). Die müsste also schon nach knapp 10 sec die 8 m zurückgelegt haben.

    Was mache ich falsch? Ist vielleicht die zeitliche Auflösung zu niedrig oder meine Methodik falsch?

    Grüsse



  • Hmm.. deine iteration mal debuggen;) und mit nem stift und papier taschenrechenr manuell validieren:)



  • Ich hab mal noch in einem Mathe-Forum nachgefragt. Da hiess es:

    Nach 3,33 s und 1,67 m wird die Höchstgeschwindigkeit erreicht.
    Dann noch 6,33 m in 6,33 s mit konstanter Geschwindigkeit.
    In der Summe also 9,67 s

    Die 3,33 s kann ich nachvollziehen, warum das dann nur 1,67 m sind muss ich mir auch nochmal überlegen.



  • Timer sind ungenau. Sie taugen, um Ereignisse wiederholt einzuleiten, aber Du brauchst noch etwas anderes, um die tatsächlich dazwischen vergangene Zeit zu messen. Ideal dafür wäre eine System.Diagnostics.Stopwatch.

    Die Berechnungen führst Du dann auf Grundlage der gemessenen vergangenen Zeit durch:
    v = v_0 + a * t
    p = p_0 + v * t + a/2 * t²

    velocity += acceleration * time;
    position += velocity * time + acceleration * 0.5 * time * time;
    


  • @luker
    ja, vielen Dank, jetzt sieht das schon viel besser aus 🙂

    Allerdings habe ich immer noch Abweichungen von ~ 3 cm bezogen auf den Punkt an dem Maximal-Geschwindigkeit erreicht wird. Ich poste mal meinen Code, vielleicht ist die Reihenfolge der Befehle ungünstig. Man braucht 3 TextBoxen und ein Canvas mit rectangle (Canvas-Breite = 800 + rectangle-Breite).

    Die Klasse ...

    public class C_Shuttle : INotifyPropertyChanged
    {
        // Private Variablen
        private Vector pos;
        private Vector vel;
        private Vector acc;
    
        // Konstruktor
        public C_Shuttle()
        {
            pos = new Vector(0, 0);
            vel = new Vector(0, 0);
            acc = new Vector(0.3, 0);
        }
    
        // Eigenschaften
        public Vector Pos
        {
            get
            {
                return pos;
            }
            set
            {
                pos = value;
                OnPropertyChanged("Pos");
            }
        }
    
        public Vector Vel
        {
            get
            {
                return vel;
            }
            set
            {
                vel = value;
                if (vel.X > 1)
                {
                    Vel = new Vector(1, 0);
                }
                OnPropertyChanged("Vel");
            }
        }
    
        public Vector Acc
        {
            get
            {
                return acc;
            }
        }
    
        // Property changed Event
        public event PropertyChangedEventHandler PropertyChanged;
    
        // Functions
        private void OnPropertyChanged(String property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
    

    ... und das Programm

    public partial class MainWindow : Window
    {
        Stopwatch MainTimer = new Stopwatch();
        DispatcherTimer RefreshTimer = new DispatcherTimer();
        double t0, t1, dT;
        C_Shuttle Shuttle = new C_Shuttle();
    
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = Shuttle;
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Timer
            RefreshTimer.Interval = TimeSpan.FromSeconds(0.02);
            RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick);
            RefreshTimer.Start();
            MainTimer.Start();
            t0 = MainTimer.ElapsedMilliseconds;
    
            // Bindings
            Binding PosBinding = new Binding();
            PosBinding.Path = new PropertyPath("Pos.X");
            txtPos.SetBinding(TextBox.TextProperty, PosBinding);
            Binding VelBinding = new Binding();
            VelBinding.Path = new PropertyPath("Vel.X");
            txtVel.SetBinding(TextBox.TextProperty, VelBinding);
        }
    
        private void RefreshTimer_Tick(object sender, EventArgs e)
        {
            t1 = MainTimer.ElapsedMilliseconds;
            dT = (t1 - t0) / 1000;
            t0 = t1;
            if (Shuttle.Vel.X < 1)
                Shuttle.Vel += Shuttle.Acc * dT;
            Shuttle.Pos += Shuttle.Vel * dT + Shuttle.Acc * 0.5 * dT * dT;
    
            // Bildschirm aktualisieren
            Canvas.SetLeft(Rechteck, Shuttle.Pos.X * 100);
            txtTime.Text = MainTimer.Elapsed.ToString();
    
            //if (Shuttle.Pos.X >= 8)
            if (MainTimer.ElapsedMilliseconds >= 3333.3333)
            {
                MainTimer.Stop();
                RefreshTimer.Stop();
            }
    
            CommandManager.InvalidateRequerySuggested();
        }
    }
    

Anmelden zum Antworten