# Simulated projectile - calculated initial velocity overshoots the target

1. Jul 10, 2011

### xovangam

hi there,

i'm programming a simulation of a projectile that has a known target off in the distance somewhere in my 3D world, i also know the angle at which i will be firing the projectile. i am firing the projectile on flat ground (so the start and end y-coordinates are the same).

i'm using the equation:

d = (v2 / g) * sin(2 * theta)

where:
d = distance to target (known)
g = gravity (known)
theta = angle off the horizontal at which i'm firing the projectile (known)

so i solve for v in order to get an initial velocity with which to fire the projectile.

the velocity that i get out of that causes my simulation to always overshoot the target (i.e. the projectile travels a bit farther than d). each step in the simulation is calculated in each tick like so (pseudo-code):
Code (Text):

Position.X += Velocity.X * TimeStep;
Position.Y += Velocity.Y * TimeStep;
Position.Z += Velocity.Z * TimeStep - 0.5 * Gravity.Z * TimeStep * TimeStep;
Velocity.Z -= Gravity.Z * TimeStep;

now i assume this occurs because my timesteps lead to an approximation of a trajectory curve, which causes the projectile to travel a longer distance than it otherwise would if the timesteps were infinitely small ?

and if that's true, so i'm currently scaling the initial velocity that i calculate down a bit by a factor of around 20 percent or so to compensate for the fact that i overshoot my target. so out of curiosity, is there some method by which i could calculate a more "exact" scale factor that was relative to the size of the timesteps that i'm taking ? such that if i raise/lower the size of my timestep, i wouldn't have to re-guess at a scale factor ?

TIA -x.

2. Jul 10, 2011

### xovangam

actually, using smaller timestep increments doesn't seem to bring me closer to the target..

is d = (v2 / g) * sin(2 * theta) not what i want to be using here ?

3. Jul 10, 2011

### HallsofIvy

Since this is neither abstract algebra nor linear algebra, I am moving it to "General Mathematics".

4. Jul 10, 2011

### pmsrw3

The size of your time step shouldn't matter, since the equations of motion you're using are exact. When I do what you say you're doing, I get no overshoot, even if I make my time step big enough for the entire flight of the projectile.

I suspect you've got the wrong velocities. How are you calculating vx, vy, and vz? Are you accounting for the fact that the total horizontal velocity is $v \cos\theta$?

5. Jul 10, 2011

### robphy

What happens when you remove the term
- 0.5 * Gravity.Z * TimeStep * TimeStep;
?

6. Jul 10, 2011

### xovangam

@pmsrw3: the initial velocity is being calculated as:

Code (Text):
v = sqrt((d * g) / sin (2 * theta))
as i simply solved for v in the initial equation. is that not correct ?

@robphy: sorry, i failed to mention that Z is "up" in my 3D world, so Z is the vertical component, X and Y are horizontal components. does that clarify your question ?

7. Jul 10, 2011

### pmsrw3

Yes, I understand that. But that's not actually velocity, it's speed. Velocity is a vector with x, y, and z components, Velocity.X, Velocity.Y, and Velocity.Z in your code. How are you calculating those?

8. Jul 10, 2011

### xovangam

ah. so i have an initial launch direction that i start with (i.e. theta is known).

well, more specifically, i have a unit vector that i start with. given that Z is up, i do this to calculate theta (pseudo code):

Code (Text):
up_vector = vector(0,0,1);
Theta = acos(1.0 - (launch_direction dot up_vector));
which should give me the "pitch" angle between flat ground and my launch direction, yes?

and then i do:

Code (Text):
v = sqrt((d * g) / sin (2 * theta));
and then i multiply 'launch_direction' by 'v' to get the initial velocity.

9. Jul 10, 2011

### pmsrw3

I'm going to repeat the question. "Velocity is a vector with x, y, and z components, Velocity.X, Velocity.Y, and Velocity.Z in your code. How are you calculating those?"

10. Jul 10, 2011

### pmsrw3

Another question: why "acos(1.0 - (launch_direction dot up_vector))"? Shouldn't it be $\frac{\pi}{2}-\cos^{-1}(\text{launch_direction dot up_vector})$?

11. Jul 10, 2011

### xovangam

i have a target in the world somewhere in front of me. i begin by calculating a displacement vector in the XY plane (Z is up) between the position i am going to fire from and the target:

Code (Text):
fireToTargetXY = (target_pos - fire_pos);
fireToTargetXY.Z = 0.0; // i don't really need to do this because the Z values are equal
the magnitude of this vector is the distance that i need the projectile to travel (d).

Code (Text):
d = magnitude(fireToTargetXY);
i then normalize that vector to give me a direction to the target in the XY plane:

Code (Text):
fireToTargetDirXY = normalize(fireToTargetXY);
basis vectors: X is forward (1,0,0), Y is left/right (0,1,0) and Z is up (0,0,1). so i do:

Code (Text):
launch_dir.X = fireToTargetDirXY dot forward;
launch_dir.Y = sin(acos(launch_dir.X)) * sign(fireToTargetDirXY.Y);
launch_dir.Z = sin(theta); // theta is clamped between 0 and Pi / 2
launch_dir = normalize(launch_dir);
for the Z component i don't actually know theta but instead i am given a raw value between 0 (no pitch) and 1 (straight up) from an outside input source; so that is why i mentioned that i calculate the actual "pitch" angle from the launch_dir vector.

is that more or less along the lines of what you're asking for ?

12. Jul 10, 2011

### pmsrw3

Yes, that helps. It's a whole lot more complicated than it needs to be, but it looks like it will eventually work out right. However, your calculation of theta looks wrong to me. In a previous post you said you calculated it by a weird formula acos(1 - ld.up), which doesn't make any sense to me. In fact, I don't see why you think you have to recalculate theta. You used theta as input to calculate ld in the code you just presented, then you use ld as input to recalculate theta. Why would you do that?

Anyway, I'm convinced that the trouble is not in your simulation, but that there's an error somewhere in that horrendously and unnecessarily complicated calculation you do to get your initial velocity vector. My guess would be that it's in the angle calculation, but it could be almost anywhere.

Last edited: Jul 10, 2011
13. Jul 11, 2011

### xovangam

thanks @pmsrw3. to clarify i don't actually have theta when i calculate the launch direction, as i noted that comes from an external input as a number between 0 (no pitch) and 1 (straight up). so my givens are that and a target pos that is somewhere in front of me in the world.

i will try changing the calculation for theta as you suggest. i agree that looks incorrect.

thanks again! -x.

14. Jul 11, 2011

### xovangam

i suppose i could also just do sin-1(Z) on the input for pitch to get theta now that i think about it..oh well. i agree it's more complex than it should be. in any case i think i'm all good now..

15. Jul 11, 2011

### pmsrw3

But your calculation of LD contains this line of code:

Code (Text):
launch_dir.Z = sin(theta);
So you must have theta when you calculate launch direction! I understand that you aren't given theta directly, but you have to calculate it before you can calculate LD.

Code (Text):
launch_dir.X = fireToTargetDirXY dot forward;
launch_dir.Y = sin(acos(launch_dir.X)) * sign(fireToTargetDirXY.Y);
launch_dir.Z = sin(theta); // theta is clamped between 0 and Pi / 2
Actually, looking at this again, this code is not correct. It is not going to give an LD vector at angle theta from the horizontal, but at a shallower angle. You construct a vector whose horizontal component is 1 and whose vertical component is sin(theta), which is a vector at angle arctan(sin(theta)).

But that's basically theta, isn't it? I mean, all you have to do is multiply it by pi/2.