Jump to content
Sign in to follow this  
icarusuk

Calculating air resistance

Recommended Posts

LoL thats some funky graph doodles, done in MSPaint?  Hehehe.

My full script (thats over 4 pages long so itsnt posed here) can accurately aim at a moving target or group.  It adjusts for launcher / target height (not with the pathetic select 2 rubbish, but using ASLheight).  And it works really well.  If only for this drag thing it would be finished.

Id rather not drop bombs straight, with my script you can see and hear them coming, it looks quite stunning indeed smile.gif  Esspecially with smoke munitions leaving an arc of green smoke in the sky smile.gif

Incidently, the script can be altered through parsing a variable that alters the time of flight. A longer time gives a high arc, which I small time gives a much shallower arc.

Will working out the time of flight and adjusting work?

Share this post


Link to post
Share on other sites

OFP's weather-wind - remember the "rubbing" argument in the drop function, for example - may also influence the motion of the sim-types used for shells / rockets. I haven't done any experiments, so I'm simply mentioning it as it occurs. It could be one factor responsible for the "inconsistencies" mentioned.

It is measurable though (at least, I'm sure a reasonably accurate estimation is possible) via script.

Prospero

Share this post


Link to post
Share on other sites

Ahh yes, rubbing. Makes some nifty smoke effects smile.gif

I sent Suma a PM asking if its possible to let us in on the proper model that they used, Im not expecting a reply, but at least I tried.

Share this post


Link to post
Share on other sites

I mentioned a "display script" for the framework flight-model code I posted earlier in this thread. So, for the sake of completeness, here's an example of one which takes care of the NED to ENU conversion without having to resort back to Euler angles. I use it to display objects made out of lots of separate spherical objects - driven by the flight-model script.

Also note that a trigger called "base" needs to be created (one way or another) for this script to work as intended. The "mysphere" object is just a custom sphere created using O2.

----------

s1 = "mysphere" camcreate [0, 0, 0]

s2 = "mysphere" camcreate [0, 0, 0]

s3 = "mysphere" camcreate [0, 0, 0]

s4 = "mysphere" camcreate [0, 0, 0]

s5 = "mysphere" camcreate [0, 0, 0]

s6 = "mysphere" camcreate [0, 0, 0]

s7 = "mysphere" camcreate [0, 0, 0]

s8 = "mysphere" camcreate [0, 0, 0]

s9 = "mysphere" camcreate [0, 0, 0]

s10 = "mysphere" camcreate [0, 0, 0]

s11 = "mysphere" camcreate [0, 0, 0]

; Vectors in ENU.

_v1 = [0, 0, 0]

_v2 = [0, 1, 0]

_v3 = [1, 0, 0]

_v4 = [0, -1, 0]

_v5 = [-1, 0, 0]

_v6 = [0, 0, 1]

_v7 = [0, 0, -1]

_v8 = [0.325, 1, 0]

_v9 = [-0.325, 1, 0]

_v10 = [0, 1, 0.325]

_v11 = [0, -3, 0]

_vs = [_v1, _v2, _v3, _v4, _v5, _v6, _v7, _v8, _v9, _v10, _v11]

_nvs = count _vs

_n = 0

#lp1

_ip = Output

; Position in ENU (remember that the z value represents absolute height here).

_x = _ip select 4

_y = _ip select 3

_z = -(_ip select 5)

; The Direction Cosine Matrix. Note that this is the NED DCM. We don't want to have to rebuild it from scratch for ENU. Instead, when we come to apply it to the ENU vectors, we'll perform the necessary conversion as we go.

_m11 = _ip select 9

_m12 = _ip select 10

_m13 = _ip select 11

_m21 = _ip select 12

_m22 = _ip select 13

_m23 = _ip select 14

_m31 = _ip select 15

_m32 = _ip select 16

_m33 = _ip select 17

; Transform the vectors.

_tvs = []

#lp2

_v = _vs select _n

_x1 = _v select 0

_y1 = _v select 1

_z1 = _v select 2

; Apply the inverse (or transpose) of the DCM. Also swap the x and y terms and change the sign of the z term as we go.

_x2 = _y1 * _m11 + _x1 * _m21 - _z1 * _m31

_y2 = _y1 * _m12 + _x1 * _m22 - _z1 * _m32

_z2 = _y1 * _m13 + _x1 * _m23 - _z1 * _m33

base setpos [_y2 + _x, _x2 + _y, 0]

_v = [_y2 + _x, _x2 + _y, -_z2 + _z + (getpos base select 2)]

_tvs = _tvs + [_v]

_n = _n + 1

?(_n < _nvs): goto "lp2"

_n = 0

; The array named tvs now contains all the vectors transformed appropriately for ENU, including an offset to account for the (quite probably differing) height of the ground under each position. So all that remains is to place the objects into OFP world-space in the normal way.

s1 setpos (_tvs select 0)

s2 setpos (_tvs select 1)

s3 setpos (_tvs select 2)

s4 setpos (_tvs select 3)

s5 setpos (_tvs select 4)

s6 setpos (_tvs select 5)

s7 setpos (_tvs select 6)

s8 setpos (_tvs select 7)

s9 setpos (_tvs select 8)

s10 setpos (_tvs select 9)

s11 setpos (_tvs select 10)

; In ENU, remember that a positive yaw is nose left, NOT right. It is effectively minus (compass) heading.

hint format ["yaw %1\npitch %2\nroll %3\n", -deg(_ip select 8), deg(_ip select 7), deg(_ip select 6)]

~0.001

goto "lp1"

----------

Prospero

Share this post


Link to post
Share on other sites

I've been trying to do this the old fashioned way apparently.  Though I do have a small result set I'd like you guys to look at and tell me what you think.

The code used is

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">

;Calculate the necessary x,y,z velocity vectors for firing a projectile

;Quantum

;

; src is the firing unit pos array, tgt is the destination pos array

; rounds is the number to fire,

; elevation angle

; dir is direction of course

; initvel is the horizontal velocity

; initvo refers to the vertical offset where the round is camcreate'd (off the ground)

; ---------------------------------

_src = _this select 0

_tgt = _this select 1

_elevation = _this select 2

_rounds = _this select 3

_roundtype = _this select 4

_velinit = _this select 5

_initvo = _this select 6

; ---------------------------------

; break down the pos arrays

_srcx = _src select 0

_srcy = _src select 1

_tgtx = _tgt select 0

_tgty = _tgt select 1

; some good ol fashion math

_diffx = _tgtx - _srcx

_diffy = _tgty - _srcy

;[west,"HQ"] sidechat format["diffs:%1,%2",_diffx,_diffy]

_xsqrd = _diffx ^ 2

_ysqrd = _diffy ^ 2

_range = sqrt(_xsqrd+_ysqrd)

; determine the angle to target as THETA

; THETA = arctan(x/y) for direction

_preangle = atan(_diffx/_diffy)

; now which quandrant are we in?

?(_diffy < 0):_theta=180+_preangle

?(_diffy >= 0):_theta=360+_preangle

?(_theta > 360):_theta=_theta-360

?(_theta < 0):_theta=_theta+360

[west,"HQ"] sidechat format["dir:%1 range:%2",_theta,_range]

;

; setup the vectors

; Theta determines direction, PHI determines elevation

; The magnitude of the first vector is the requested Velocity

; The base of this triangle represents the hypotenus of the direction vector

; so we calculate the Z (verticle axis) first

;

_velOY = _velinit * sin(_elevation)

_velOX = _velinit * cos(_elevation)

; velOX is now the hypotenus (magnitude) of the direction vector

; so get the x,y components from it

_velx = sin(_theta) * _velOX

_vely = cos(_theta) * _velOX

;

_fullstr = format["Vector info OY:%1 OX:%2 X:%3 Y:%4",_velOY,_velOX,_velx,_vely]

[west,"HQ"] sidechat _fullstr

; so the full vector is [_velx,_vely,_velOY]

_op = _roundtype camcreate[_srcx,_srcy,_initvo]

_op setdir _theta

_op setvelocity[_velx,_vely,_velOY]

[west,"HQ"] sidechat "Artillery round fired"

;

_counter = 0

#loop

_oppos = getpos _op

_px = _oppos select 0

_py = _oppos select 1

_diffx = (_px - _srcx)

_diffy = (_py - _srcy)

_travel = sqrt(_diffx^2 + _diffy^2)

;hint format["travel: %1\ndamage: %2",_travel,damage _op]

~0.1

_counter = _counter + 0.1

_opd = damage _op

?(_op == _op):goto "loop"

[west,"HQ"] sidechat format["final x:%1 y:%2",_px,_py]

~2

_fullstr = format["velinit: %1\ntravel:%2\ntime:%3\ndmg:%4\nelevation:%5",_velinit,_travel,_counter,_opd,_elevation]

hint _fullstr

_op = nil

exit

<span id='postcolor'>

Using this I built a table.

Theta = 45 (tested values are avg's, about 5-6 test shots)

        tested  tested | calculated values are

Vo      range   time    |  Voy    Time     Rng      Rng Error%

-----------------------------------------------------------

30      89       4.1        21.21   4.32    91.83        3

45      185     6.5        31.82   6.49    206.63      10

60      315     8.5        42.42   8.6      367          14

75      473     10.5      53.01   10.82   573          17

90      620     12         63.63   12.98   826          24

105    779      13.5      74.24   15.15   1125        30

120    963      14         84.84   17.3    1469        34

at theta=45 Voy = Vox so Vox is not in the table

You can see in my code I get the proper vectors first for elevation, then using the base I build the x,y vectors.

Looking at the hint/chat output, all the vectors are correct.  It's the error rate that get's flaky.  There is some inherent error in the tested values because I couldn't get good timings with a delay of <0.1.  But these results, even with a 1% error still show a definite reduction in range and time.

When the Tof (time of flight) approaches 18 secs the code still works, but of course the shell has exceeded it's Ttl (time to live) so there is never an impact.

I was hoping to build an elevation chart for some of the add arty pieces out there, like the M101 and the M109.  Looking at their initspeed's it appears it would be useless to do so for such high speeds.  The best range at 200m/s is around 1800m.  Not a great distance.  The M109v2(Heat) fires at 900m/s, even with a calculated elevation of 10degrees the round would fly off the map.  At 45d elevation the round takes well over a minute just to reach it's apex.

With an ~20sec Ttl and this ever elusive (-vt), will using real pieces for artillery work?  Sure you can use the 900m/s initspeed's, but your trajectory is so shallow that it kind of defeats the idea of dropping shells from above, especially to clear buildings..

my 2 cents,

Quantum

Share this post


Link to post
Share on other sites

Quantum, looks good. Don't forget you can use the atan2 function and you don't have to worry about quadrants.

Doolittle

Share this post


Link to post
Share on other sites

Didn't know if the whole arty thing was said and done, but I went ahead and addressed an earlier comment in one of these messages about handling the TTL of 'shell' objects by recreating it downrange.  So here it is (hope it's not too big and forgive me for all the comments, I wrote this for my use but also to teach a friend):

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">

; MidFlightRound  (commented out the wazoo)

; Quantum

; The purpose is to create a projectile somewhere

; along it's trajectory mitigating the TTL of 'shell' objects.

; ***********************************************************************************

; TRAJECTORY MATH AND SCRIPT APPROACH DEFINITIONS

; ***********************************************************************************

; Ideally, this script should be called right after the artillery unit performs the 'FIRE'

; action. That way you get the sound effect of the gun firing and then this script handles

; the round.

; The reason for this script is to address the TTL (time-to-live) issues with ammo types

; inherited from the 'shell' object.  Since an object of type 'shell' has a TTL = 20 secs,

; we need to recreate the shell anytime we know the time will exceed the TTL.

; Using addon artillery pieces is the definitive reason behind this script.

; ALL addons intended to be used as artillery suffer from this TTL restriction.

; Firing a 'shell' object at actual military velocities (such as initspeed=900 m/s) means

; the round would be off the map at an elevation as little as 5 degrees (henceforth just d).

; Such shallow trajectories are very rarely, if ever, used in actually battlefield deployments.

; The idea is to arc the round high enough to make the range required but also to come in

; at such an angle as to miss any obstructions between the artillery piece and the intended

; impact location.  In order to best represent this in OFP's engine we need to precalculate the

; actual trajectory values and determine if the round, at the defined initial velocities

; (the horizontal and vertical components), would exceed the TTL before the round is to impact.

; It's all about the math.  Since we don't need to be concerned with the actual artillery piece,

; we hand in the 'shell' type defined in the addons cpp file and do the math.

; For the enlightenment of the uninitiated I will put down the base math required and my approach.

; These are the standard trajectory formulas from any decent physics book.

; Vo = initspeed = desired muzzle velocity of the round you want to create (velocities in m/s)

; T = time in seconds

; g = gravity  (I presume to be 9.8m/s^2, though I've never read it in the forums)

; V(horizontal h) = Vo * sin(elevation)    V(vertical v) = Vo * cos(elevation)

; Hmax (maximum height reached) = (2 * Vv^2) / 2g

; Tof (Time of flight) = (2 * Vv) / g

; Vt (vertical velocity at time T) = Vv - (g * T)

; [now for the FUN formula, range.  this is gonna take a little space to make it look good]

;                            2 * Vo^2 * sin (2 * elevation)

;       Range (R) =  ---------------------------------

;                                             g

; H (height) = Vv * T - (0.5 * g * T^2)

; D (distance) = Vh * T   (no minus anything because gravity doesnt change horizontal velocity)

; So the order of business is to;

;

; A) Calculate Vy and use it to calculate the Tof

; If Tof>19s then just calculate the position on the trajectory at (Tof - 19s) and place

; the round there, give it the right velocity vectors and let it go.

; THIS is the best and still correct method.

;   If Tof<19 then don't do anything.  The reasoning is, this script is

; intended to be used in conjunction with the actual artillery piece.  If the artillery round

; fired by the actual artillery object has a Tof < 19 then let the artillery round do it's

; thing and don't worry about it. Otherwise, create the damn thing somewhere downrange.

; B) Use Tif (Time in flight) = (Tof - 19s), plug it into the first 2 formulas we need to

; solve for;

; D and H (so we know how far away and how high the round should be)

; C) Solve Vh anv Vv (so we know how fast the round should be travelling when it's created)

; Theta and Phi are commonly used as references to angles, I will adhere to this defacto standard.

; Theta will represent the direction angle (x,y) in the horizontal plane.

; Phi will represent the elevation ( adjacent segment [x,y], z) in the vertical plane.

; Theta will determine the [x,y] horizontal location on the map at range D from it's origin.

; position x = (sin(Theta) * D) + (starting point x = from position select 0)

; position y = (cos(Theta) * D) + (starting point y = from position select 1)

; position z = H + (starting point z = vertical offset)

; Phi is used in calculating the initial Vh and Vv, which are then used for the setvelocity vector.

; D) Delay creating the round downrange until Tif has expired. This makes the round arrive at the

; time it would have if the games Ttl were not an issue.  So artillery rounds still take time

; to reach their target and you still have a really good chance of hearing them buzz over your

; head (at least, I hope so. I wrote this intro before coding it as a guideline to myself).

; E) CamCreate[x,y,z] the round at the correct coordinates

; F) SetVelocity[x,y,z] with the right velocity vectors

; G) FINALLY!  let the game engine have it's way with our creation

; H) Shout profanity as you watch your round pummel the target.

; ***********************************************************************************

;  CODE STARTS HERE

; ***********************************************************************************

; frompos the x,y,z position where the round is created

; topos the x,y,z position where we want the round to land

; initvel the muzzle velocity of the round,  This should equal the addons intended initspeed

; so the downrange velocity vectors are correct.  When the round is created I give it

; the setvelocity vector based off of initvel, as it should be.

; elevation the muzzle elevation at source. (this is really fudge-factored, because the round is

; created near the artillery piece, not necessarily at the end of the muzzle)

; vertoffset the vertical offset where the round is created.

; round the type of object to create (something derived from 'shell' would be nice)

; timeoff the amount of time prior to impact you want to create the new round.  If 0, then the

; round is created at the impact point. Remember not to set this higher than 20, because

; at 20+ seconds prior to impact the round will exceed the Ttl live and not impact!

; The other thing is, you probably want to be closer to 18 seconds to impact, that will

; give you a 2 second buffer in case the engine happens to count fast :)

_frompos = _this select 0

_topos = _this select 1

_initvel = _this select 2

_Phi = _this select 3

_VertOffset = _this select 4

_round = _this select 5

_TimeOff = _this select 6

; Get the initial velocity vectors and see if Tof > 19s.

; Theta determines direction, PHI determines elevation

; The magnitude of the first vector is the requested Velocity

; The base of this triangle represents the hypotenus of the direction vector

; so we calculate the Z (verticle axis) first

;

; velOY is the vertical velocity

; velOX is the horizontal velocity  (we use these for Vv and Vh as defined above)

_velOY = _initvel * sin(_Phi)

_velOX = _initvel * cos(_Phi)

; check the Tof  (again, I am assuming g=9.8)

_Tof = (2 * _velOY) / 9.8

papabear sidechat format["Time of flight: %1",_Tof]

; If Tof < _TimeOff seconds then exit, we don't need to do anything.

; If you want to test lower Tof's, just comment it out.

;?(_Tof < _TimeOff):exit

; delay just a short bit to give the real artillery round time to clear the area

~0.1

; at this point Tof > _TimeOff seconds, so let's get Tif (= Tof - _TimeOff)

_Tif = _Tof - _TimeOff

; If you set _Tif = 0 here, the round will start at Time=0 in the trajectory, which will

; start the round at the beginning of it's trajectory.  The round will then travel along it's

; normal trajectory and impact as long as the dreaded Ttl is not exceeded.

; You can set this to any time.  It is the time in flight of the round, so Tif=2 means start

; the round where it would be 2 seconds into it's trajectory.  The tricky thing here, is if

; you are using an extremely shallow elevation and/or very low initial velocity, you could be

; starting the round AFTER it would have impacted.  Be sure you don't!

; Uncomment the line below to do this, mainly for testing.

;_Tif = 4

; let's figure out the distance the round will have traveled at time Tif and it's altitude (height)

; H (height) = Vv * T - (0.5 * g * T^2)

; D (distance) = Vh * T   (I copied this from above to keep it fresh in your mind)

; For our caculations, _Tif represents time T

_Distance = _velOX * _Tif

_Height = (_velOY * _Tif) - (0.5 * 9.8 * _Tif^2)

; We now know how far it's traveled and how high it should be.  So we need to know how fast it's

; going in the vertical plane.  Is it climbing or falling at Tif?  Well, let's see, that's

; Vt (velocity at time T) = Vv - (g * T)

_velVert = _velOY - (9.8 * _Tif)

; and Vh doesn't change. Well, I don't know what air resistance coefficient OFP uses, so I just

; start the round with the "no air resistance" horizontal velocity, which is the initial

; horizontal velocity

_velHor = _velOx

; With all these vector components we can now construct the pre-creation parameters. Namely

; the actual game [x,y,z] arrays.

; First we need to know the direction the round was fired.  We get that by doing simple trig

; using our source position as the origin and the target position as the [x,y]

; break down the position arrays

_srcx = _frompos select 0

_srcy = _frompos select 1

_tgtx = _topos select 0

_tgty = _topos select 1

; some good ol fashion math

_diffx = _tgtx - _srcx

_diffy = _tgty - _srcy

_xsqrd = _diffx ^ 2

_ysqrd = _diffy ^ 2

_RangeToTarget = sqrt(_xsqrd+_ysqrd)

; determine the angle to target as THETA

; THETA = arctan(x/y) for direction

_preangle = atan(_diffx/_diffy)

; now which quandrant are we in?

?(_diffy < 0):_Theta=180+_preangle

?(_diffy >= 0):_Theta=360+_preangle

; correct for negative directions and directions over 360

?(_Theta > 360):_Theta=_Theta-360

?(_Theta < 0):_Theta=360+_Theta

; _Theta is our direction.  So let's figure out where in the game ([x,y,z]) world it would be.

; I realize I keep changing the reference to height with a simple reassignment, but it's for the

; sake of explaining what, why and how.

; The actual X,Y position is simply the direction * magnitude(_Distance)

_preposX = sin(_theta) * _Distance

_preposY = cos(_theta) * _Distance

; To get the starting coordinates, we need to add in the starting location of the arty piece

; the round was "started" from.

_posX = _srcx + _preposX

_posY = _srcy + _preposY

_posZ = _Height + _VertOffset

; the full position vector is [_posX,_posY,_posZ]

; We now know where to place the round.  Let's figure out the velocity vectors.  These vectors will

; tell the round how fast to go and in what direction.

; Since we know the magnitudes of both the horizontal and vertical components, we use a little

; more trig to calculate the x,y,z.

; X and Y are in the horizontal plane, so the vector _velHor tells us the magnitude, which is the

; same as the hypotenus. So to get X and Y......

; Trig hats on = true

_velX = sin(_Theta) * _velHor

_velY = cos(_Theta) * _velHor

; and the Z component is just _velVert.  This is true because the Z axis is not based off the direction

; our projectile is traveling, it merely tells us if it's climbing or falling.

_velZ = _velVert

; the full velocity vector is [_velX,_velY,_velZ]

; Lets wait for Tif before creating the round

~_Tif

; Create the round

_op = _round camcreate[_posX,_posY,_posZ]

; Point it in the direction of travel. (Remeber, there is no PITCH command, we can only tell the round

; it's horizontal orientation)

_op setdir _Theta

; Start it flying

_op setvelocity[_velX,_velY,_velZ]

; Now let the game engine take over, we're done!

exit

<span id='postcolor'>

Works like you expect.  I still have the pressing question of what gravitational constant they use.  Since they do alter the trajectory effectively by a different G value and/or -Vh over time (simulating air resistance).  Guess the BIS guys never gave the final answer to that, at least not in this thread.

Hope it's not beating that dead horse too bad.  Was not my intention.

Share this post


Link to post
Share on other sites

No, you're not beating a dead horse...that's neat what you've done.

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">_shell = "Barrel4" createVehicle [_src select 0, _src select 1, 1]

_shell setVelocity [_vx, _vz, _vy]

"GrenadeHand" createVehicle _src

player sideChat "FIRE"

<span id='postcolor'>

I ended up writing a little script that fires a barrel...then it makes an explosion when the barrel hits the ground.  This way, you don't have to worry about a 20 second limit, the barrel lasts forever until you delete it....and most importantly, drag seems not to effect the barrel nearly as much as shells.  Different objects in the game you use go different distances, like a phone flies further.  I found the barrel to be the one object which was getting the closest to where I wanted the shell to land.  In order to negate the air friction problem, I just made a marker on the map that showed where you wanted to hit, & where the "shell" actually hit...this way the human running the script could do their own calculating to hit stuff.

Doolittle

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×