# Thread: Some Basics in Simulation App - Ball Bouncing

1. ## Some Basics in Simulation App - Ball Bouncing

Some things I have said about a simulation app in a previous post, I hope to clarify here.

This app comes from the specialist idea suggested in this post
Specialized Learning vs General Learning

This app is about simulating a rubber ball in free fall. The ball hits the ground and bounces back up into the air, and so on.

The app was written a Windows 8 App in C#
(Unfortunately, that is the only C# compiler I have access to at this time. I will try to port it to a Windows Form program whenever I get the chance)

The objective of the app is to simulate a rubber ball bouncing as long as possible, while keeping each bounce as identical as possible.

When you vary the sliders, sometimes a "floating point" variable goes to the high (or low) end with respect to the other floating point variables and this increases the error in floating point math.

eg
Code:
`1000000000000000 + .0000125 = 1000000000000000.000000087`
whereas adding in a more even range

Code:
`10000000 + 1.25 = 10000001.25`
If the first step is done 1 million times then more error would be introduced and then accumulates

These are just illustrative examples, not to be taken for exactness.

In a simulation, you want to increase accuracy. You can play with the sliders in the app and see how the accuracy of the bouncing ball is affected.

Another aspect of sim accuracy is doing an integration. Example, integrate x with respect to t, where in the code implementation, you would calculate dx using dt, then adjust x by adding dt, and then repeat. The accuracy of the integral increases as dt gets small, but sometimes when dt is sufficiently small, the sim would be accurate enough, and you can leave it at that. If you get too small with the floating point addition, you can have the problem described above.

The equations used in the sim are:
Code:
```      dx = u dt + 1/2 dv dt

v = u + dv

dv = a dt

v = u + a dt```
These are straight physics equation for distance x, acceleration a, and velocity v, where u is the initial velocity.
Last edited by crosswire; Apr 3, 2018 at 07:45 PM.  Reply With Quote

2. ## MainPage.xaml

MainPage.xaml

Code:
```<Page
x:Class="Classical_Ball_Fall.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Classical_Ball_Fall"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Canvas HorizontalAlignment="Left" Height="500" Margin="106,79,0,0" VerticalAlignment="Top" Width="600" Background="DarkBlue" Name="Canvas01">
<Rectangle Fill="#FFF4F4F5" Height="1" Canvas.Left="250" Stroke="Yellow" Canvas.Top="99" Width="100"/>
<Ellipse Fill="#FFF4F4F5" Height="50" Canvas.Left="275" Stroke="Black" Canvas.Top="100" Width="50" Name="Ellipse01"/>
<Rectangle Fill="#FFF4F4F5" Height="12" Canvas.Left="100" Stroke="Black" Canvas.Top="450" Width="400"/>
</Canvas>
<Button Content="Start" HorizontalAlignment="Left" Margin="710,150,0,0" VerticalAlignment="Top" Click="ButtonStart_Click" Name="buttonStart"/>
<Button Content="Reset" HorizontalAlignment="Left" Margin="710,220,0,0" VerticalAlignment="Top" Click="ButtonReset_Click" Name="buttonReset"/>
<Button Content="Close" HorizontalAlignment="Left" Margin="710,290,0,0" VerticalAlignment="Top" Click="ButtonClose_Click" Name="buttonClose"/>
<Slider HorizontalAlignment="Left" Margin="713,380,0,0" VerticalAlignment="Top" Width="200" Name="Slider01" ValueChanged="Slider01_ValueChanged"/>
<Slider HorizontalAlignment="Left" Margin="713,460,0,0" VerticalAlignment="Top" Width="200" Name="Slider02" ValueChanged="Slider02_ValueChanged"/>
<Slider HorizontalAlignment="Left" Margin="713,540,0,0" VerticalAlignment="Top" Width="200" Name="Slider03" ValueChanged="Slider03_ValueChanged"/>
<TextBlock HorizontalAlignment="Left" Height="48" Margin="713,350,0,0" TextWrapping="Wrap" Text="N Simulation calculation bewteen display frames. Higher is more accurate but uses more CPU power so it must be balanced. Also watch out for extreme conditions on very hi-end settings" VerticalAlignment="Top" Width="325"/>
<TextBlock HorizontalAlignment="Left" Height="48" Margin="713,430,0,0" TextWrapping="Wrap" Text="
A scale for the distance being dispayed but it can also be viewed as a scale for the time" VerticalAlignment="Top" Width="325"/>
<TextBlock HorizontalAlignment="Left" Height="48" Margin="713,510,0,0" TextWrapping="Wrap" Text="

Ball's Elasticity (Large is good but not too large)" VerticalAlignment="Top" Width="325"/>
</Grid>
</Page>```
Last edited by crosswire; Apr 3, 2018 at 06:56 PM. Reason: upload success  Reply With Quote

3. ## MainPage.xaml.cs

MainPage.xaml.cs

Code:
```using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Popups;

namespace Classical_Ball_Fall
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>

public class BallPhys
{
public static int nSimPerFrameDT;
public static double nPixelsPerMeter;
public static double elasticity;//big is good

public const double mass = 28.0;

//public static crosssectionalarea = 1.0; //for wind resistance - not implemented
//public static double radius = 1.0f;
//public static double height = 100.0f;

/// <summary>
/// Distance ball is squashed
/// </summary>
public static double compression = 0.0;
/// <summary>
/// Apparent Acceleration Due To Gravity
/// </summary>
public static double g = 9.98;
/// <summary>
/// Initial Velocity
/// </summary>
public static double u = 0;
/// <summary>
/// Final Velocity
/// </summary>
public static double v = 0;
/// <summary>
/// Incremental Time Interval
/// </summary>
public static int DT = 10; //10 milliseconds for each frame render

public static double get_dx(bool bBallInContact)
{

double c = (elasticity * compression) / mass;
/*
Net Accelearation  on ball
--------------------------

dx = u dt + 1/2 dv dt

v = u + dv

dv = a dt

v = u + a dt

*/

//Initialize u with initial v
u = v;

double dt = ((double)DT) / (1000.0 * nSimPerFrameDT); //convert from frame time to sim time. DT to dt. DT is time between displayed frames and dt is time in each sim. dt in seconds
double dv = (g - c) * dt;
double dx = (u * dt) + (0.5 * dv * dt);

//Initialize final v;
v = u + dv;

return dx;
}

public static void reset()
{
u = 0;
v = 0;

//height = 100.0;
}
}

public sealed partial class MainPage : Page
{

private DispatcherTimer timer = new DispatcherTimer();

public MainPage()
{
this.InitializeComponent();

//Initlize Timer
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, BallPhys.DT); //DT is frame time in milliseconds

//Allow user to change parameters of the sim
//range 800 - 8000
Slider01.Minimum = 350;
Slider01.Maximum = 8000;
Slider01.Value = 3800;//(double)(BallPhys.nSimPerFrameDT);
//range 80 - 3000
Slider02.Minimum = 80;
Slider02.Maximum = 3000;
Slider02.Value = 800.0;//(double)(BallPhys.nPixelsPerMeter);
//range 20000 - 2000000
Slider03.Minimum = 20000;
Slider03.Maximum = 2000000;
Slider03.Value = 240000.0;//(double)(BallPhys.elasticity);//big is good

}

/// <summary>
/// Update state using N sim increments for each tick. Physics is simulated
/// Display Frame
/// </summary>
void timer_Tick(object sender, object e)
{

//Do n  simulations per each frame
int nSim = 0;

while (nSim < BallPhys.nSimPerFrameDT)
{

//Distance from canvas top Canvas.Top="122"
//Canvas.Top="450"
//Ball heiht = Ellipse Height="50"

BallPhys.compression = (50.0 - Ellipse01.Height) / BallPhys.nPixelsPerMeter;

//Fall the ball
//Move ball by dx
double DX = BallPhys.get_dx(true) * BallPhys.nPixelsPerMeter;

Canvas.SetTop(Ellipse01, Canvas.GetTop(Ellipse01) + DX);

//Is ball in contact
if ((Canvas.GetTop(Ellipse01) + Ellipse01.Height) >= (450))
{
//Compress ball
if ((Ellipse01.Height - ((Canvas.GetTop(Ellipse01) + Ellipse01.Height) - (450))) > 0)
{
Ellipse01.Height -= (Canvas.GetTop(Ellipse01) + Ellipse01.Height) - (450);
}
Ellipse01.Fill = new SolidColorBrush(Colors.DarkSlateGray);

//   timer.Stop();
// return;
}
else
{
//If ball is compressed
if (Ellipse01.Height < 50.0)
{
Ellipse01.Height = 450.0 - Canvas.GetTop(Ellipse01);
}

Ellipse01.Fill = new SolidColorBrush(Colors.White);
}

nSim++;
}
}

private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
if (timer.IsEnabled)
{
//Stop timer
timer.Stop();
buttonStart.Content = "Start";
}
else
{
//Start timer
timer.Start();
buttonStart.Content = "Pause";
}
}

private void ButtonReset_Click(object sender, RoutedEventArgs e)
{
//Re-init timer / Stop timer
if (timer.IsEnabled)
{
//Stop timer
timer.Stop();
buttonStart.Content = "Start";
}

//Re-init positions
Canvas.SetTop(Ellipse01, 100);
Ellipse01.Height = 50;
BallPhys.reset();

}

async private void ButtonClose_Click(object sender, RoutedEventArgs e)
{

MessageDialog msgDialog = new MessageDialog("Are you sure?", "Exit?");

UICommand butOK = new UICommand("Yes", null, "YES");
//butOK.Invoked = butOKClick;

UICommand butNo = new UICommand("No", null, "NO");
//butNo.Invoked = butNoClick;

//Show message
IUICommand op = await msgDialog.ShowAsync();

//This below is oddly written so that it could be uploaded. Dont know why it was parsed and reject before
if (op.Id.ToString().CompareTo("yes".ToUpper()) == 0)
{
if (timer.IsEnabled)
{
//Stop timer
timer.Stop();
}
App.Current.Exit();
}
}

private void Slider01_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
// public static int nSimPerFrameDT = 3800;

BallPhys.nSimPerFrameDT = (int)(Slider01.Value);

ButtonReset_Click(null, null);
ButtonStart_Click(null, null);
}

private void Slider02_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
//public static double nPixelsPerMeter = 800;

BallPhys.nPixelsPerMeter = (double)(Slider02.Value);

ButtonReset_Click(null, null);
ButtonStart_Click(null, null);
}

private void Slider03_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
//public static double elasticity = 240000.0;//big is good

BallPhys.elasticity = (double)(Slider03.Value);

ButtonReset_Click(null, null);
ButtonStart_Click(null, null);
}
}

}```
Last edited by crosswire; Apr 3, 2018 at 06:56 PM. Reason: upload success  Reply With Quote

4. ## MainPage.xaml.cs (continued)

Reserved for any future related uploads....
Last edited by crosswire; Apr 3, 2018 at 07:51 PM.  Reply With Quote

5. ## MainPage.xaml.cs (continued)

Reserved for any future related uploads....
Last edited by crosswire; Apr 3, 2018 at 07:50 PM.  Reply With Quote

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•