Question

I'm having some problems with a physics project I'm trying to make. Its basically a Free Fall simulator. I set the gravitational acceleration and the height and the program should simulate the fall. The problem is that it's getting the time wrong, don't know why. I'm using the Stopwatch class for measuring the time.

Here's the code:

FrmMain.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.Diagnostics;

namespace Physics
{
    public partial class FrmMain : Form
    {
        public Settings config = new Settings();

        public float displacement = 0f;

        public Stopwatch timer = new Stopwatch();
        public float timeElapsed; //in Seconds

        public Thread thread;

        public FrmMain()
        {
            InitializeComponent();

            //New thread (Drawing)
            thread = new Thread(new ThreadStart(Drawing));
            thread.IsBackground = true;
            thread.Start();

            this.KeyDown +=new KeyEventHandler(FrmMain_KeyDown);
        }

        private void Drawing()
        {
            try
            {
                while (true)
                {
                    if (config.objectPos.Y < config.sizeBitmap.Height)
                        timer.Start();
                    else
                        timer.Stop();
                    Bitmap screen = new Bitmap(this.pboxScreen.Width,
                                               this.pboxScreen.Height);
                    SendScreen(screen);
                }
            }
            catch (ThreadAbortException tae)
            {
                Console.WriteLine(tae.Message);
            }
        }

        private void SendScreen(Bitmap Screen)
        {
            if (pboxScreen.InvokeRequired)
            {
                pboxScreen.Invoke(new MethodInvoker(delegate()
                {
                    this.SendScreen(Screen);
                }));
            }
            else
            {   //Converting Milliseconds to Seconds
                timeElapsed = timer.ElapsedMilliseconds / 1000f;
                //Check if object isn't in the ground
                if (config.objectPos.Y < config.sizeBitmap.Height)
                 {
                    displacement -= config.objectPos.Y;
                    config.objectPos.Y = config.objectPos.Y + 0.5f * 
                                         config.acceleration * 
                                         timeElapsed * timeElapsed;
                    displacement += config.objectPos.Y;
                }

                Graphics g = Graphics.FromImage(Screen);
                g.Clear(Color.White);

                //New rectangle
                Rectangle rec = new Rectangle((int)config.objectPos.X, 
                                               (int)config.objectPos.Y, 5, 5);
                g.FillRectangle((new Pen(Color.DarkRed)).Brush, rec);
                g.DrawRectangle(new Pen(Color.Red, 2.0f), rec);

                g.Dispose();

                //Update txtbox (textbox)
                txtboxX.Text = config.objectPos.X.ToString();
                txtboxY.Text = config.objectPos.Y.ToString();
                txtboxTempo.Text = timeElapsed.ToString();
                txtboxD.Text = displacement.ToString();

                pboxScreen.Image = Screen;
            }
        }

        void FrmMain_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Space:
                    if (config.objectPos.Y >= config.sizeBitmap.Height)
                    {
                        config.objectPos.Y -= 100;
                        timer.Reset();
                    }
                    break;
            }
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread.IsAlive) thread.Abort();
        }
    }
}

Settings.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Physics
{
    public class Settings
    {
        public Size sizeBitmap; //bitmap resolution
        public PointF objectPos; //Initial Position
        public float acceleration;

        public Settings()
        {
            sizeBitmap.Width = 560;
            sizeBitmap.Height = 420;
            objectPos.X = 560f / 2f;
            objectPos.Y = 420f / 2f;
            acceleration = 9.8f;
        }

    }
}

There's another problem, depending on height the object doesn't fall without interruption, it stay in the same position for a few, but noticeable, milliseconds. I think this is a threading problem, 'cause it's been a while I don't use it, so I might be missing something.

I'm measuring the height in meters, so the objectPos.Y = 420f / 2f represent a height of 210 meters. For this height, the object should take around 6.5 seconds to hit the ground, in my program it's taking less than 1 second, so I assumed that there's a time measuring problem.

I'm calculating the height with the uniform gravitational field without air resistance expression :

h(t)=h0+0.5*g*t²

where: h(t) is the height with respect to time, h0 the initial altitude, g acceleration due to gravity and t the time elapsed

Any help is much appreciated. Thanks.

Était-ce utile?

La solution

I believe your issue may be in the line

        config.objectPos.Y = config.objectPos.Y + 0.5f * 
                             config.acceleration * 
                             timeElapsed * timeElapsed;

The YPosition at time t = t-sub-k (config.objectPos.Y) is the height at time t-sub-k. if t is total elapsed time, then this is equal to the Initial Y-Position (The Height at Time t = 0) + 1/2 gt^2, NOT the last Y-Position.

What you are doing is taking the last Y-Position (the height as of the previous calculation, and adding the drop in altitude during the elapsed time from time t=0 to t= t-sub-k. So it's no wonder that it is falling too fast.

Add an Initial Y-Position read-only property to your settings construct, and DO not Update or modify it.

Modify your code to use it as follows:

        config.objectPos.Y = config.InitialY + 0.5f * 
                             config.acceleration * 
                             timeElapsed * timeElapsed;

Autres conseils

I think your formula is wrong. h0 should be the initial velocity (which in your case is 0 m/s) and it should be multiplied with time.

This is the correct one from This is the for

So having said that, Vi*t is always 0 since your initial velocity is 0. What's left is 0.5 * 9.8 * timeElapsed * timeElapsed.

            config.objectPos.Y = 0 //initial velocity
                + 0.5f * config.acceleration * timeElapsed * timeElapsed;

Also objectPost.Y should always start from 0 meters since it's starting from the top and it's going to fall.

You can refer to this Console app code. Run it and see the time elapsed compared and compare it to the results in

It should be 1.32 seconds.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Physics_16783733
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass c = new MyClass();
        }
    }

    public class MyClass
    {
        public Settings config = new Settings();

        public Stopwatch timer = new Stopwatch();
        public float timeElapsed; //in Seconds

        public Thread thread;

        static ManualResetEvent control;

        public MyClass()
        {
            control = new ManualResetEvent(false);
            //New thread (Drawing)
            thread = new Thread(new ThreadStart(Drawing));
            thread.IsBackground = true;
            thread.Start();

            control.WaitOne();
        }

        public void Drawing()
        {
            try
            {
                while (true)
                {
                    if (config.objectPos.Y < config.sizeBitmap.Height)
                    {
                        timer.Start();
                    }
                    else
                    {
                        timer.Stop();
                        control.Set();
                    }
                    //Bitmap screen = new Bitmap(this.pboxScreen.Width, this.pboxScreen.Height);
                    SendScreen();
                }
            }
            catch (ThreadAbortException tae)
            {
                Console.WriteLine(tae.Message);
            }
        }

        private void SendScreen()
        {
            timeElapsed = timer.ElapsedMilliseconds / 1000f; //Converting Milliseconds to Seconds

            if (config.objectPos.Y < config.sizeBitmap.Height) //Check if object isn't in the ground
            {
                //formula used is in http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm
                config.objectPos.Y = 0 //initial velocity
                    + 0.5f * config.acceleration * timeElapsed * timeElapsed;
            }

            //Update txtbox (textbox)
            Console.WriteLine("Object position Y: " + config.objectPos.Y.ToString());
            Console.WriteLine("Time elapsed     : " + timeElapsed.ToString()); //using the data from http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm, time elapsed should be 1.32 seconds
        }
    }

    public class Settings
    {
        //I used data from http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm
        //where the given is:

        //vi = 0.0 m/s
        //d = -8.52 m
        //a = - 9.8 m/s2

        public Size sizeBitmap; //height of the place where the object will start free falling
        public PointF objectPos; //Initial Position
        public float acceleration;

        public Settings()
        {
            sizeBitmap.Height = 8.52;
            objectPos.Y = 0;
            acceleration = 9.8f;
        }

    }

    public struct PointF
    {
        public float Y { get; set; }
    }

    public struct Size
    {
        public double Height { get; set; }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top