kxd661 / ardupilot-mega

Automatically exported from code.google.com/p/ardupilot-mega
0 stars 0 forks source link

energy_error calculated incorrectly #124

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
This is an interesting problem and it took a while for me to see what I think 
is the right answer.  If a 2kg plane accelerates from 10 m/s to 20 m/s, does it 
expend 100 J of energy (neglecting air resistance) or 300 J of energy?  The 
code is written as if it expends 100 J of energy (energy_error ~ (20 m/s - 10 
m/s)^2), but I think the right answer is 300 J.  If I'm right, energy_error 
should be calculated as

energy_error = constant * ((airspeed_cruise * airspeed cruise) - (airspeed * 
airspeed)) + (float)altitude_error * 0.098f;

Here's why I think this is the right way to calculate it:
A counterexample would be a train with a car on it; if a 2000kg car accelerates 
from 0 m/s to 10 m/s, it expends 100,000 J regardless of [inertial] reference 
frame.  But, if the car were on a long flatbed train moving at 10 m/s when it 
did this, a stationary observer would say that the car gained 300,000 J because 
it changed speed from 10 m/s to 20 m/s.  The observer is actually correct that 
the car has now gained 300,000 J relative to the observer, and it is also true 
that the car only expended 100,000 J to do it.  The trick is that the train 
supplied the other 200,000 J by not slowing down when the car accelerated.  So, 
if UAVs were like cars on trains, it would be correct to calculate energy error 
on airspeed_error^2.

But, UAVs aren't like cars on trains; they are like cars on roads.  To gain 
more airspeed, they have to push against absolutely stationary air, not air 
that is stationary relative to them.  If the car was driving on a road and had 
to apply an accelerating force when it was already moving 10 m/s, it would take 
the full 300,000 J to accelerate it from 10 m/s to 20 m/s, not the 100,000 J it 
would take if the car was accelerating from 0 to 10 m/s inside a box and the 
box maintained its 10 m/s speed.  Likewise, if a 2 kg plane is already moving 
10 m/s, it will take 300 J to accelerate it to 20 m/s because the plane has to 
push against air that it's already moving through quickly.  It would only take 
100 J to accelerate the plane to 20 m/s from 10 m/s if the plane were inside an 
airtight box that maintained its speed at 10 m/s during the acceleration.

Original issue reported on code.google.com by bjpcalt...@gmail.com on 20 Sep 2010 at 9:34

GoogleCodeExporter commented 8 years ago
Thanks for the issue report. 

Not sure I follow your explanation 100% but I believe this is a known issue in 
the code.  It is basically due to us using an approximation that the change in 
the square root of a sum is approximated by the change in the sum of the square 
roots (first order taylor approximation).

While true that our calculation is sloppy, it does save a lot of a square root 
operation, which is why it was implemented that way.  And in actual practice 
for altitude hold one term significantly dominates the other (the airspeed if 
my top of the head memory is correct).

I will prioritize this as a low priority and leave it open.

Original comment by dewei...@gmail.com on 25 Sep 2010 at 4:33

GoogleCodeExporter commented 8 years ago

Original comment by DrZip...@gmail.com on 25 Sep 2010 at 6:07

GoogleCodeExporter commented 8 years ago
I'm not sure how the current implementation saves a lot of square root 
operation; my suggested correction involves just one more multiplication, one 
more subtraction and no square roots.

My sign is wrong above, so here's the full, actual equation ready to be pasted 
into the code:
energy_error = 0.00005 * (airspeed_cruise*airspeed_cruise - airspeed*airspeed) 
- (float)altitude_error * 0.098f;

This isn't a small error; consider the difference in energy_error between the 
current equation and my equation with no altitude error:
For airspeed_cruise = 2000 cm/s and airspeed = 1900 cm/s, airspeed_error = -100 
cm/s
energy_error_current = 0.00005 * 100 * 100 = 0.5
energy_error_suggested = 0.00005 * (2000*2000 - 1900*1900) = 19.5
For airspeed_cruise = 1000 cm/s and airspeed = 900 cm/s, airspeed_error = -100 
cm/s
energy_error_current = 0.00005 * 100 * 100 = 0.5
energy_error_suggested = 0.00005 * (1000*1000 - 900*900) = 9.5

So, practically speaking, the current code will provide the same throttle input 
to accelerate from 9 m/s to 10 m/s as it would to accelerate from 19 m/s to 20 
m/s when it actually should be providing a little more than twice the throttle 
input at the higher speed.  This will make for either very jerky slow-speed 
throttle control, or sluggish throttle control at high speeds depending on how 
the gains are set.

Original comment by bjpcalt...@gmail.com on 25 Sep 2010 at 6:56

GoogleCodeExporter commented 8 years ago
Please ignore my previous entry.  I was in a hurry and thinking of the earlier 
implementation (ArduPilot 2.6) where we used pressure units for airspeed, and 
required more computation to move between variable units.

You are correct.  More energy is required to accelerate from 10 to 20 than from 
0 to 10.  

From first principals
(1)  E = F*d,   Energy = Force * distance
(2)  F = m*a,   Force = mass * acceleration
(3)  v = a*t,   Velocity (change in) = acceleration * time
(4)  d = v0*t + a*t*t
For the easy to analyze case of constant acceleration and force (and of course 
mass) it is evident that an acceleration from 0 to 10 will take the same time 
as an acceleration from 10 to 20, but the distance covered will be 
significantly greater in the latter case, and from equation 1 the energy 
required greater.

I will put this on the to do list with a higher priority.  I'm trying to not 
spend the day at the computer today ;)

Original comment by dewei...@gmail.com on 25 Sep 2010 at 10:41

GoogleCodeExporter commented 8 years ago
R944

Original comment by dewei...@gmail.com on 27 Sep 2010 at 5:02