TrickLogo

HomeTutorial Home → A Simple Simulation

A Simple (non-Trick) Simulation

Contents


In this tutorial, we are going to build a cannonball simulation. We will start out with a non-Trick-based simulation. Then we will build a Trick-based simulation. Then we will make incremental improvements to our Trick-based simulation, introducing new concepts as we go.

The commands following % should typed in and executed.


Cannonball Problem Statement

Cannon

Figure 1 Cannonball

Determine the trajectory and time of impact of a cannon ball that is fired with an initial speed and initial angle. Assume a constant acceleration of gravity (\(g\)), and assume no aerodynamic forces.


Modeling the Cannonball

For this particular problem it's possible to write down equations that will give us the position, and velocity of the cannon ball for any time (\(t\)). We can also write an equation that will give us the cannon ball’s time of impact.

The cannonball’s acceleration over time is constant. It's just the acceleration of gravity:

$$ \vec{a}(t) = \vec{g} $$

On Earth, at sea level, \(g\) is approximately 9.81 meters per second squared. In our problem, gravity acts in the negative \(y\) direction, so:

$$ \vec{g} = \begin{bmatrix} 0 \cr -g \end{bmatrix} = \begin{bmatrix} 0 \cr -9.81 \end{bmatrix} \text{ m/s}^2 $$

Since acceleration is the derivative of velocity with respect to time, the velocity \(\vec{v}(t)\) is found by simply anti-differentiating \(\vec{a}(t)\). That is:

$$ \vec{v}(t) = \vec{g}t + \vec{v}_0 $$

where the initial velocity is:

$$ \vec{v}_0 = \begin{bmatrix} \text{speed} \cdot \cos\theta \cr \text{speed} \cdot \sin\theta \end{bmatrix} $$

The position of the cannon ball \(\vec{p}(t)\) is likewise found by anti-differentiating \(\vec{v}(t)\).

$$ \vec{p}(t) = \frac{1}{2}\vec{g}t^2 + \vec{v}_0 t + \vec{p}_0 $$

Once we specify our initial conditions, we can calculate the position and velocity of the cannon ball for any time \(t\).

Impact is when the cannon ball hits the ground, that is when the cannonball’s y-coordinate again reaches 0.

Since the y-component of \(\vec{g}\) is \(-g\):

$$ y(t_{\text{impact}}) = -\frac{1}{2}gt^2 + v_{y_0}t + y_0 = 0 $$

Solving for \(t\) (using the quadratic formula), we get the time of impact:

$$ t_{\text{impact}} = \frac{v_{y_0} + \sqrt{v_{y_0}^2 + 2 g y_0}}{g} $$


Code For a non-Trick Cannonball Simulation

Listing 1 - cannon.c

/* Cannonball without Trick */

#include <math.h>
#include <stdio.h>

int main(void)
{
    /* Initial conditions */
    const double g          = 9.81;       // standard gravity in m/s^2
    const double acc[2]     = {0.0, -g};  // acceleration in m/s^2
    const double init_angle = M_PI / 6.0; // initial angle in radians
    const double init_speed = 50.0;       // initial speed in m/s
    const double time_step  = 0.01;       // time step in seconds

    const double init_pos[2] = {0.0, 0.0}; // initial position in meters
    const double init_vel[2]               // initial velocity in m/s
        = {
            cos(init_angle) * init_speed,
            sin(init_angle) * init_speed,
        };

    /* Initialize simulation state */
    double pos[2]      = {init_pos[0], init_pos[1]}; // current position in meters
    double vel[2]      = {init_vel[0], init_vel[1]}; // current velocity in m/s
    double sim_time    = 0.0;                        // current simulation time in seconds
    double impact_time = 0.0;                        // time of impact in seconds
    int impact         = 0;                          // flag indicating whether an impact has occurred

    printf("time, pos[0], pos[1], vel[0], vel[1]\n");

    /* Run simulation */
    while (!impact) {
        vel[0] = init_vel[0] + acc[0] * sim_time;
        vel[1] = init_vel[1] + acc[1] * sim_time;

        pos[0] = init_pos[0] + (init_vel[0] + 0.5 * acc[0] * sim_time) * sim_time;
        pos[1] = init_pos[1] + (init_vel[1] + 0.5 * acc[1] * sim_time) * sim_time;

        printf("%7.2f, %10.6f, %10.6f, %10.6f, %10.6f\n", sim_time, pos[0], pos[1], vel[0], vel[1]);

        if (pos[1] < 0.0) { // check for impact
            impact_time
                = (-init_vel[1] - sqrt(init_vel[1] * init_vel[1] - 2.0 * acc[1] * init_pos[1]))
                / acc[1];

            pos[0] = init_pos[0] + (init_vel[0] + 0.5 * acc[0] * impact_time) * impact_time;
            pos[1] = 0.0;

            impact = 1;
        }

        sim_time += time_step;
    }

    /* Shutdown simulation */
    printf("Impact time=%f position=%f\n", impact_time, pos[0]);

    return 0;
}

If we compile and run the program in listing 1:

% cc cannon.c -o cannon
% ./cannon

we will see trajectory data, followed by:

Impact time=5.096840 position=220.699644

Voila! A cannonball simulation. So why do we need Trick!?


Limitations of the Simulation

For simple physics models like our cannonball, maybe we don't need Trick, but many real-world problems aren't nearly as simple.

In the next section, we'll see how a Trick simulation goes together, and how it helps us to easily integrate user-supplied simulation models with commonly needed simulation capabilites.


Next Page