Drag...

Started by
13 comments, last by Erzengeldeslichtes 20 years, 6 months ago
I looked in my physics book, and online. The function I found is: Drag = Coefficient * Area * AirDensity * pow(Velocity, 2) * 0.5; All well and good. Coefficient would take a LOT of processing power to work out at real time, so I''m currently querying the object for it, and the object will use one of the presets or a custom (currently using 1.28, the coefficient for a flat plate). AirDensity is queried from atmosphere objects, so it''s arbitrary. Right now it''s using 1.0, which probably doesn''t exist but oh well. Area is difficult to calculate as well, I have a thread on that in the general programming forum (it''s dropped to the second page though...). I''m currently calculating the area of a box. Now when I calculate the drag, the drag comes out to 111.0 u/s², when the object''s velocity is 0.1 u/s. As far as I can tell the problem is in the area, because the object is 128x68 u. When I looked through the equation, I realized I didn''t know the units for the coefficient, but after calculating the rest of the equation I come out with a units of gu/s² (g being grams). Does the coefficient have a units of 1/g? And how do I fix my backwards flying object? As far as I can tell, as soon as I press forward the object shoots off to the maximum bounds of the universe and crashes the game (read: the float overflowed)
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Advertisement
I implemented drag & lift a few years ago using basically the same principals. But I didn''t try looking up the coefficient or calculating the air density (which is << 1 when using standard units). I instead used

drag = -kAv2

where ''k'' combines all the globally constant terms, i.e.

k = 0.5 * coeffiecent * air density

I then played around with different values of k until they felt right, giving the right degree of braking at high speeds and a reasonable terminal velocity when thrust and drag were equal and cancelled.

As for shooting off to infinity it shouldn''t happen with drag, as at reasonable speeds (below the terminal velocity) drag should only slow you down by amounts less than maximum thrust, and so should rapidly then gradually brake a fast moving object.

Try working out the terminal velocity, i.e. the velocity at which drag and (maximum) thrust are balanced. It should be a reasonable maximum speed; if it isn''t check your calculation and units.

John
John BlackburneProgrammer, The Pitbull Syndicate
quote:Original post by Erzengeldeslichtes
I looked in my physics book, and online. The function I found is:
Drag = Coefficient * Area * AirDensity * pow(Velocity, 2) * 0.5;

All well and good. Coefficient would take a LOT of processing power to work out at real time, so I''m currently querying the object for it, and the object will use one of the presets or a custom (currently using 1.28, the coefficient for a flat plate).
AirDensity is queried from atmosphere objects, so it''s arbitrary. Right now it''s using 1.0, which probably doesn''t exist but oh well.
Area is difficult to calculate as well, I have a thread on that in the general programming forum (it''s dropped to the second page though...). I''m currently calculating the area of a box.

Now when I calculate the drag, the drag comes out to 111.0 u/s², when the object''s velocity is 0.1 u/s. As far as I can tell the problem is in the area, because the object is 128x68 u. When I looked through the equation, I realized I didn''t know the units for the coefficient, but after calculating the rest of the equation I come out with a units of gu/s² (g being grams). Does the coefficient have a units of 1/g? And how do I fix my backwards flying object? As far as I can tell, as soon as I press forward the object shoots off to the maximum bounds of the universe and crashes the game (read: the float overflowed)


Drag is a force, which should be Newtons or pounds. Force is mass times acceleration, which for Newtons means kilogram-meter/s2 and for pounds means slug-foot/s2. Your later unit, gu/s2 is a correct representation for force since it is mass time acceleration. (By the way, what exactly is "u"? A micron?)

That coefficient is unitless, and so your dimensional analysis of the equation, which yielded gu/s2 is correct. Why did you say that when you calculated drag it came out to be 111.0 "u/s2"? Did you think that drag should be an acceleration?

As for your crashing problem.... Make sure that your drag force acts in the opposite direction from your velocity. Otherwise, your creating a thrust (not drag) that causes acceleration (and velocity) to increase, which causes thrust to increase faster, which causes acceleration and velocity to increase faster, ..., overflow very soon. If that isn''t the problem, then I can''t help your crashing problem without more information. How are you integrating your system? Simple Euler integration? Verlet? Do you have any other forces other than the drag? (Spring forces, for example, can cause crashes if you use a naive integration scheme.)

(By the way, in aerodynamics, the area used for drag calculations is typically a fixed area, not a projected area. For a box it would just be, for example, the area of the largest size of the box. It is the coefficient that varies with the projection, but it''ll be easier for you just to hold that fixed too and treat the box as though it were a sphere.)



Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
you are right, it is a force, and so should have mass in it. I was thinking of it as an acceleration, hence my confusion in that respect.

As for what "u" is, it''s a unit, which I haven''t defined how much of a meter it is yet, it is simply the distance between 0 and 1 in my coordinate system.

The thing is, I want drag to be less on the smallest side of the box than the largest, so that if the object were controllable, and you wanted maximum drag, you would put the largest side in the direction it is moving, and if you wanted minimum you''d put the smallest area in the direction it''s moving.

I''ve pushed the air density down a large amount and it doesn''t immidiatly crash like it did before. Instead it crashes at a random time that I haven''t isolated yet. I have made certain that it is in the opposite direction--when it''s not crashing, it''s functioning properly. The only other force acting on it is when it is being pushed, which is just a straight force on the base of the object.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
quote:Original post by Erzengeldeslichtes
As for what "u" is, it''s a unit, which I haven''t defined how much of a meter it is yet, it is simply the distance between 0 and 1 in my coordinate system.


Fair enough!

quote:Original post by Erzengeldeslichtes
The thing is, I want drag to be less on the smallest side of the box than the largest, so that if the object were controllable, and you wanted maximum drag, you would put the largest side in the direction it is moving, and if you wanted minimum you''d put the smallest area in the direction it''s moving.


I''m not sure I follow. Are you calculating two drag forces, one for each side? Or are you just calculating one drag and using the appropriate area depending on which side is facing the direction its moving? Remember, no matter what, the *total* drag force, which might be the sum of the front and back drag forces if you are currently calculating two, must always---for every time frame---point AWAY from the direction of motion. Since you only have one other force, I still come to the conclusion that your net drag may be acting in the same direction as the motion, which would definitely cause the overflow. Put an error check in there. Calculate the dot product of the net drag force with the forward velocity. If the dot product is positive, then your net drag force is in the wrong direction.

Looking back at the equation for drag, it is still technically the coefficient that you''d want to vary. The effect is the same as adjusting the area, but since the cost to changing the coefficient is identical to the cost of changing the area, why not do the right thing and just change the coefficient?

quote:Original post by Erzengeldeslichtes
I''ve pushed the air density down a large amount and it doesn''t immidiatly crash like it did before. Instead it crashes at a random time that I haven''t isolated yet. I have made certain that it is in the opposite direction--when it''s not crashing, it''s functioning properly. The only other force acting on it is when it is being pushed, which is just a straight force on the base of the object.


OK, so you''ve checked the drag force direction. And the other force is a constant, right? Or at least the other force has nothing to do with velocity or springs? It this is all correct (I admit I still think the most likely cause is drag in the wrong direction) then you must have an error in your time integration. Care to post a code snippet?

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Actually now I haven't had it crash in a long while, I don't know what was going on and it's hard to isolate now that it seems to have vanished--I did make some changes to my time integration when it went away, so that might be it (I changed my function from an "apply velocity in direction" to a "apply force in direction" as it should have been)
I'm only calculating 1 drag, which is a "flat plate" of the profile of the box. So if you have a the small part of the box toward the angle of movement, you have a small profile. The object gets a bigger profile as it rotates to point the larger section toward the angle of movement, causing more drag. I don't know how I would calculate the coefficient to take into account the changing sides--All websites I've seen say that the coefficient is determined experimentally or with too much processing power to be in a game.

If you want a code snip for better understanding of what I'm doing, here's the section where drag is actually applied:
//A large calculation goes above this that gives me the area of the profile of the object.//Note: Momentum has an x, y, and z value, the y is the rotation along the y axis, x is along the x axis, and z is the speed. (You don't really need the z axis for a velocity)		float AtmosphericDrag = 0.0000005;//Usually determined by the existance of atmosphere objects, but for my test app I just set it to this.		float Coefficient = 1.28f;//coefficient of a flat plate.		float Force = Coefficient * Area * AtmosphericDrag * (float)pow(Momentum.z, 2);		VECTOR InverseDirection(0,0,0);		InverseDirection.y = Momentum.y-180;		InverseDirection.x = -Momentum.x;		m_ObjectArray[i]->ApplyForceInDirection(InverseDirection, Force); //This function ignores the z component of a VECTOR.


[edited by - Erzengeldeslichtes on October 9, 2003 1:51:02 PM]

[edited by - Erzengeldeslichtes on October 9, 2003 1:56:45 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Okay, a few comments.

First, nomenclature. By AtmosphericDrag do you really mean atmospheric density? You should!

Second, I would strongly recommend that you use a separate variable to encode the speed, rather than code it in momentum.z This is highly confusing to anyone other than yourself. And a year from now if you haven''t looked at the code you will be confused too. Just a suggestion to make the code more readable and maintainable.

Now, on to the meat of your problem. I suspect there may be a problem with your inverse direction. I said this before, but your code snippet convinces me further that there may still be something wrong here. Several aspects of your code are confusing to me, e.g., I see a few ways where you could be doing things entirely right or entirely wrong. But I don''t have enough information to determine this. So, I have another question that may shed more light on the matter.

Are you using cylindrical coordinates to represent velocity?

I think you might be, but if you are I am very confused about what you are trying to do with Momentum.x. For cylindrical coordinates, if Momentum.y is the rotation of the y axis then Momentum.x would be the radius, which is identical to the speed and should never be negated.

If you are using cylindrical coordinates, then I also recommend changing your vector class to reflect this. It is not at all intuitive what you are doing when you use var.x and var.y to represent cylindrical coordinate values. You should have something like var.angle and var.radius. (And in the case of cylindrical coordinates the radius will always be your speed and will always be positive. A reversal of direction need only touch the angle, e.g., the -180 that you''re doing.)

Please provide more code. Show me the ApplyForce* function so I can see what you are doing with that inverse direction.

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Oh, I also wanted to comment on variable drag coefficient.

While it is true in general that it is computationally expensive, if not impossible, to calculate it using physics, there are simpler ways.

For simple airplane wing physics, you can use a simple parabolic function to calculate a drag coefficient depending on angle of attack relative to the wind. As long as the angle isn''t too large the parabolic function is quite accurate at predicting variable drag. You can search the forum archives for "drag" and you will find threads from maybe a couple of years ago with details on this subject.

For a sphere, the drag coefficient is roughly 1.0 for a large range of flow conditions. But even outside of this uniform region you can use lookup tables to calculate a widely varying drag coefficient based on Reynold''s Number. Reynold''s Number is easy to calculate and is based on a constant length (say, diameter or length of side), velocity, and air density. Here is a link to a table showing how a sphere''s drag coefficient varies with Reynold''s Number:

http://www.physics.ubc.ca/~waltham/scione/C_D.pdf

For a box, there may be similar diagrams that can be digitized and put into a lookup table. (Though I haven''t seen one for a box.)

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Yes, I mean AtmosphereDensity rather than AtmosphereDrag, I just wrote it as drag and haven't bothered switching it back.
No, I'm not using cylindrical coordinates. The "radius" is the speed of the velocity. I take that, turn it along the x axis by an angle, then turn it along the y axis by an angle. More along the lines of a sphere, not a cylinder.

As for being unintuitive (or counterintuitive?), that's why I have comments EVERYWHERE I do that. Lots and lots of comments to make sure that I and anyone else using it will know I did that, and why. I did it because I want to use my normal vector structure of .x, .y, and .z for the return value rather than having to say object.GetMomentumDirection() and object.GetMomentumSpeed(), I just use object.GetMomentum();

VECTOR BaseObject::GetCoordMomentum() //Finds the speed at which the object is moving along the axes{	float yComponent = (float)(Speed * sin(DEG_2_RAD(xDirectionAngle)));	float xzSpeed = (float)(Speed * cos(DEG_2_RAD(xDirectionAngle)));	float xComponent = (float)(xzSpeed * sin(DEG_2_RAD(yDirectionAngle)));	float zComponent = (float)(xzSpeed * cos(DEG_2_RAD(yDirectionAngle)));	return VECTOR(xComponent, yComponent, zComponent);}void BaseObject::ApplyForceInDirection(VECTOR Direction, float Magnitude) //Ignores the .z part of Direction, for z is roll and doesn't affect direction. Pitch and Yaw (x and y) do.{ 	float PerSec = m_ParentApp->GetElapsed();	VECTOR components = GetCoordMomentum(); 	float yForce = (float)((Magnitude * PerSec)/m_Mass * sin(DEG_2_RAD(Direction.x)));	float xzMagnitude = (float)((Magnitude * PerSec)/m_Mass * cos(DEG_2_RAD(Direction.x)));	float xForce = (float)(xzMagnitude * sin(DEG_2_RAD(Direction.y)));	float zForce = (float)(xzMagnitude * cos(DEG_2_RAD(Direction.y)));	components.y += yForce;	components.x += xForce;	components.z += zForce;	yDirectionAngle = (float)(RAD_2_DEG(atan(components.x/components.z))) - (components.z<0? 180 : 0);	float xzSpeed = (float)(sqrt(pow(components.x, 2) + pow(components.z, 2)));	xDirectionAngle = (float)(RAD_2_DEG(atan(components.y/xzSpeed)));	Speed = (float)(sqrt(pow(xzSpeed, 2) + pow(components.y, 2)));}


Edit: I've determined that if the AtmosphericDensity variable is any greater than 0.000399989888899899997f it shoots off and crashes. If I bump that 7 to an 8 it shoots off and crashes. If I leave it as 7, it hardly moves (It has a terminal velocity of 1.16 u/s, which doesn't go very fast for a 188 unit long object)

[edited by - Erzengeldeslichtes on October 11, 2003 4:36:47 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Hey,

Your coordinate system actually is called a spherical coordinate system. It is used commonly in engineering and mathematics.

I looked over your code somewhat carefully. The only thing that is absolutely a coding error is the following line:

yDirectionAngle = (float)(RAD_2_DEG(atan(components.x/components.z))) - (components.z<0? 180 : 0); 


That line does not do what you think it does. You are trying to find an angle that yields the correct sin and cos for x and z. The raw atan function returns a value between -pi/2 and pi/2, or -90 and +90 degrees. Now, angles between - and + 90 can produce sin''s of -1 to 1, thus covering both positive and negative x values. But - to + 90 can only produce positive cosine and thus only covers positive z values. You realized this and so subtracted off 180 degrees when z is negative. And that "- components.z<0 ? 180 : 0" is where your equation for yDirectionAngle goes bad. You see, when you subtract 180 from any angle, not only do you negate cos (which you want to do to get the negative z), you also negate sin (which you do not want to do since you do not want to negate x).

The SOLUTION is to use the atan2 function instead of atan. Atan2 returns an angle in the correct quadrant, e.g., it deals with +/- 180 or +/-90 as necessary. Here is how you will use it:

yDirectionAngle = (RAD_2_DEG(atan2f(components.x, components.z)); 


Note that I''ve used the atan2f version so that you don''t have to cast to a float. (You can use sinf, cosf, atanf, atan2f to directly deal with float values with no casts.)

I think you''ll find that using atan2f works better.

You may have another coding error in there. I''m afraid I ran out of patience looking at the code. As a professional developer working in a company with formal coding quality control practices, I''m going to show you the source-code-peer-reviewer side of my personality! Unfortunately, your use of spherical coordinates mixed with standard Cartesian coordinate data structures makes your code convoluted, confusing. Can you tell me why you decided to represent your vectors this way? Since you seem to be converting back to Cartesian coordinates very, very often, why not just represent your vectors in Cartesian coordinates to begin with? The spherical coords confuse your nomenclature, make your code more complex than it needs to be. In my opinion, its harder to read, probably harder to maintain even with copious comments. Anyway, my 2 cents says you''d be better off converting to Cartesian coords. Please take this comment as constructive criticism! I only want to help you make your code better, .

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net

This topic is closed to new replies.

Advertisement