1

现在在我的程序中已经到了这样的地步,我有 5 个摆动的钟摆,它们都被滑块值一次修改。这些值被绘制到 from 并通过类摆。要更改值,请运行更新按钮,它们是使用有效设置的默认选项。这些值也通过一些简单的标签显示在屏幕上。零按钮将所有值(长度除外)设置为零。

现在我的下一个任务是让钟摆“真实地”碰撞并重新创建牛顿摇篮式效果。我研究了粒子的弹性碰撞解决方案,例如这里是一个很好的例子:Ball to Ball Collision - Detection and Handling

我也在这里查看了它背后的原始物理,但我的大脑无法掌握事物的原始物理方面。

所以我想知道是否有人可以帮助我弄清楚碰撞的理论。
我目前的想法是当坐标遇到速度时,将简单地改变极性,例如在相反的钟摆中 +10 到 -10。我在这里正确吗?

这是我的钟摆课程:

class Pendulum 
{
    //all public static so they are actually global (can be used between classes and not just global to this class).
    public static int length = 10;//length of arm /** can't be less than 0 or will break.
    public static double angle = 0; //pendulums arm angle
    public static double aAcc = 0.00; //Angle acceleration
    public static double aVel = 0.00; //anglular velocity
    public static double damping = 0.000; //friction //friction
    public static double gravity = 0.0; //make gravity a constant

    int originX = 0;
    int originY = 0; //allways 0
    int bobX; // = frmWidth / 2;
    int bobY; // = (int)length; Drawn in pendulm as don't really need to be global. Are currently for flexibilty.

    Timer timer; //global for flexibility

    public Pendulum(int frmWidth, int frmHeight)
    {
        timer = new Timer() { Interval = 30 };

        timer.Tick += delegate(object sender, EventArgs e)
        {
            //-----------------drawing variables------------------------------//
            originX = frmWidth / 2;
            originY = 0;
            //to be relative to origin we go:
            bobX = originX + (int)(Math.Sin(angle) * length);
            bobY = originY + (int)(Math.Cos(angle) * length);

            //gravity
            aAcc = (-1 * gravity / length) * Math.Sin(angle); //calculate acceleration
            aVel += aAcc;//increment velcocity
            angle += aVel;//incrment angle

            aVel *= damping;//friction action, pendulum eventually 0's
        };

        timer.Start();
    }

    public void DrawPendulum(Graphics g) 
    {
            g.DrawLine(Pens.Black, originX, originY, bobX, bobY);
            g.FillEllipse(Brushes.Red, bobX - 8, bobY, 20, 20); //-8 to make it look more central!
    }
}

这是表单代码:

public partial class frmPendulum : Form
{
    private Timer timer;
    private Pendulum p1 = null;
    private Pendulum p2 = null;
    private Pendulum p3 = null;
    private Pendulum p4 = null;
    private Pendulum p5 = null;


    public frmPendulum()
    {
        InitializeComponent();
        this.Shown += new EventHandler(frmPendulum_Shown);
        this.Paint += new PaintEventHandler(frmPendulum_Paint);
    }

    void frmPendulum_Shown(object sender, EventArgs e)
    {
        p1 = new Pendulum(this.ClientRectangle.Width, this.ClientRectangle.Height);
        p2 = new Pendulum(this.ClientRectangle.Width + 40, this.ClientRectangle.Height);
        p3 = new Pendulum(this.ClientRectangle.Width - 40, this.ClientRectangle.Height);
        p4 = new Pendulum(this.ClientRectangle.Width - 80, this.ClientRectangle.Height);
        p5 = new Pendulum(this.ClientRectangle.Width + 80, this.ClientRectangle.Height);

        timer = new Timer() { Interval = 100 };
        timer.Tick += delegate(object s2, EventArgs e2)
        {
                this.Refresh();
                Value.Text = string.Format("Length: " + Pendulum.length + "{0}Angle: " + Pendulum.angle + "{0}Acc: " + Pendulum.aAcc + "{0}Vel: " + Pendulum.aVel + "{0}Damping: " + Pendulum.damping + "{0}Gravity: " + Pendulum.gravity, Environment.NewLine);
                value2.Text = string.Format("Length: " + tbrLength.Value + "{0}Angle: " + ((double)tbrAngle.Value) / 100.0 + "{0}Vel: " + ((double)tbrAVel.Value) / 100.0 + "{0}Damping: " + ((double)tbrDamp.Value) / 100.0 + "{0}Gravity: " + ((double)tbrGrav.Value) / 100.0, Environment.NewLine);
        };
        timer.Start();
    }

    void frmPendulum_Paint(object sender, PaintEventArgs e)
    {
        switch (tbrNoOfPend.Value)
        {
            case 1:
                if (p1 != null) //if used because the Paint() event could occur BEFORE "p1"etc. has been instantiated.
                {
                    p1.DrawPendulum(e.Graphics);
                }
                break;
            case 2:
                if (p2 != null)
                {
                    p2.DrawPendulum(e.Graphics);
                }
                goto case 1;
            case 3:
                if (p3 != null)
                {
                    p3.DrawPendulum(e.Graphics);
                }
                goto case 2;
            case 4:
                if (p4 != null)
                {
                    p4.DrawPendulum(e.Graphics);
                }
                goto case 3;
            case 5:
                if (p5 != null)
                {
                    p5.DrawPendulum(e.Graphics);
                }
                goto case 4;
            default:
                break;
        }
    }



    private void btnDefault_Click(object sender, EventArgs e)
    {
        //sets values to a good calibration by default.
        Pendulum.length = 50;
        Pendulum.angle = Math.PI / 2; //pendulums arm angle
        Pendulum.aAcc = 0.00; //Angle acceleration
        Pendulum.aVel = 0.00; //anglular velocity
        Pendulum.damping = 0.995; //friction //friction
        Pendulum.gravity = 0.4; //make gravity a constant

        UpdateSliders();

    }

    private void UpdateValues()
    {
        /** The trackbars only use integer values so to increment in decimals certain values have to be divided by 100 so they are correct in the simulation.
         * For example is I want the gravity to be 0.4 my track bars value will have to be 40 / 100 = 0.40 
         * Another example will be angle that will go from -3 to 3 incrementing in decimals we go from -300 to 300 /100 = 3 **/

        Pendulum.length = tbrLength.Value; //length is ok as it is an integer
        Pendulum.angle = ((double)tbrAngle.Value) / 100.0; //both numerator and denominator must be of the same type.
       // acceleration is calculated so isn't sent
        Pendulum.aVel = ((double)tbrAVel.Value) / 100.0; 
        Pendulum.damping = ((double)tbrDamp.Value) / 100.0; 
        Pendulum.gravity = ((double)tbrGrav.Value) / 100.0; 
    }

    private void UpdateSliders()
    {
        tbrLength.Value = Pendulum.length;
        tbrAngle.Value = (int)(Pendulum.angle * 100.0); //pendulums arm angle
        //tbrAAcc.Value = (int) Pendulum.aAcc; //Removed acceleration as it is re-calculated anyway.
        tbrAVel.Value = (int)(Pendulum.aVel* 100.0); //anglular velocity
        tbrDamp.Value = (int)(Pendulum.damping * 100.0); //friction //friction
        tbrGrav.Value = (int)(Pendulum.gravity * 100.0); //make gravity a constant
    }

    private void btnUpdateValues_Click(object sender, EventArgs e)
    {
        UpdateValues();
        //this.Shown += new EventHandler(frmPendulum_Shown);
        //this.Paint += new PaintEventHandler(frmPendulum_Paint);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //zero's everything except length.
        Pendulum.angle = 0; //pendulums arm angle
        Pendulum.aAcc = 0.00; //Angle acceleration
        Pendulum.aVel = 0.00; //anglular velocity
        Pendulum.damping = 0; //friction //friction
        Pendulum.gravity = 0; //make gravity a constant

        UpdateSliders();
    }

}
4

1 回答 1

1

好吧,看起来你可以自己解决代码方面的问题,老实说,我真的不是 ac# 专家,但我会尝试处理这方面的物理方面。

牛顿摇篮最酷的地方在于,无论两个末端之间有多少个球,能量都将守恒或至少大致守恒。在你走得更远之前,你需要决定你希望它有多现实。众所周知,真正的牛顿摇篮不会永远摆动,但确定每次碰撞损失多少能量是一个非常复杂的物理问题。

如果你想确定每次碰撞时损失了多少能量,你将需要很多额外的细节,然后需要通过实际测量钟摆的高度和各种东西来通过实验计算。

从这里开始,我将假设您正在谈论能量和动量都守恒的完美弹性碰撞。

在处理弹性碰撞时,您需要了解以下几点:

M1*V1 = M2*V2 according to momentum; M is mass, V is velocity
E_kinetic = 1/2*m*v^2 
E_potential = mgh where m = mass, g = acceleration due to gravity, and h = height

现在对于一些钟摆理论:

当您将钟摆向后拉时,您会以某个角度 theta 将其向后拉,但该角度仅对确定您在 y 方向上提升钟摆的高度很重要。钟摆的长度非常重要,就像支撑质量的绳子的长度一样。一旦你计算出你将钟摆抬高了多高,使用 theta 计算或只知道 y 位移,你就可以计算出摆锤在摆动底部的速度,在牛顿的摇篮中,摆锤将接触到下一个球。

要使用 theta 计算钟摆的高度,请将钟摆的长度乘以 theta 的余弦,然后从钟摆的长度中减去它。或者在数学中:

l = length of pendulum
theta = angle of the pulled back pendulum relative to the vertical axis
h = height
now actual calculations:
h = l - l*cos(theta)

有了这些h,我们现在可以使用之前的能量公式确定摆在其路径底部的速度。

由于能量在这个系统中是守恒的,当我们把它拉回来时球是静止的,我们知道它在它被拉回来的路径的顶部有它的最大势能,当我们把它拉回来时它没有任何动能,因为当我们握住它时,它的速度为零。

KE = PE
PE = m * g * h
KE = 1/2 * m * v^2
m * g * h = 1/2 * m * v^2
v cancels
g * h = 1/2 * v^2
v = sqrt(2 * g * h)
(g = 9.8 m/s^2 or 32 f/s^2)

既然你有了 v,你就可以弄清楚其他不同质量的钟摆对你的第一个钟摆的撞击会有什么反应。

就程序而言,这很无聊的是,如果您假设弹性碰撞,钟摆中的中间球并不重要。

此外,摇篮另一端的摆锤将摆动到您将第一个摆锤拉到的确切高度。虽然实际上会有一些能量损失。如果您想以某种欺骗的方式计算出多少能量损失,您可以查看牛顿摇篮在停止移动之前会点击多少次。

假设系统以 100 焦耳的能量开始,并且在球停止移动之前需要 100 次碰撞,您知道每次碰撞时您都会损失大约 1 焦耳的能量。系统的起始能量可以使用任一能量公式计算,但您必须记住重新添加质量。

一旦你知道每次碰撞会损失多少能量,你就可以反过来计算这些公式,看看另一边会上升多高。

Calculate the kinetic energy
subtract your calculated loss
plug into the potential energy formula
determine the height from the potential energy formula
于 2013-10-29T04:51:24.030 回答