LCOV - code coverage report
Current view: top level - AP_Soaring - SpeedToFly.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 22 22 100.0 %
Date: 2026-09-09 11:02:08 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /* SpeedToFly class by Samuel Tabor, 2021.
       2             : 
       3             : Calculates the optimal speed to fly given drag polar, expected climb rate in next thermal and
       4             : horizontal and vertical air movement between thermals.
       5             : */
       6             : #include "SpeedToFly.h"
       7             : 
       8       34129 : void SpeedToFly::update(float Wx, float Wz, float Wexp, float CLmin, float CLmax)
       9             : {
      10             :     // The solution to the speed-to-fly problem does not have a closed form solution. A Newton
      11             :     // method with some additional checks will converge to an acceptable level within 3-4 iterations.
      12             :     // However, to keep the computation constant per function call we just do a single iteration using
      13             :     // the previous approximation as a starting point.
      14             :     // This gives good accuracy as the inputs don't change rapidly. It would also be possible to store 
      15             :     // the inputs and converge the solution over 3-4 function calls, but this real-time iteration
      16             :     // approach gives better accuracy in tests as well as simpler code.
      17             : 
      18       34129 :     Wz *= -1.0f; // Sink defined positive.
      19             : 
      20       34129 :     float sqrtfk   = sqrtf(_polarParams.K);
      21       34129 :     float minSink = (sqrtfk/sqrtf(CLmax)*(_polarParams.CD0 + _polarParams.B*CLmax*CLmax))/CLmax;
      22             : 
      23       34129 :     if (!is_positive(minSink+Wz+Wexp)) {
      24             :         // Special case. If lift is greater than min sink speed, fly at min sink
      25             :         // speed.
      26        1280 :         _CL_estimate = CLmax;
      27        1280 :         return;
      28             :     }
      29             : 
      30       32849 :     float CD0 = _polarParams.CD0;
      31       32849 :     float B   = _polarParams.B;
      32       32849 :     float Wxp =  Wx/sqrtfk;
      33       32849 :     float WZ  = (Wz + Wexp)/sqrtfk;
      34             : 
      35             :     // Guess starting location.
      36       32849 :     float CL  = _CL_estimate>0 ? _CL_estimate : 0.5f*(CLmax+CLmin);
      37             : 
      38       32849 :     float t0 = powf(CL,1.5f);
      39       32849 :     float t1 = CD0 + B*CL*CL + t0*WZ;
      40       32849 :     float t2 = 1.5f*sqrtf(CL)*WZ + 2.0f*B*CL;
      41             :     
      42       32849 :     float Jd  = (1.5f*sqrtf(CL)*Wxp + 1.0f)/t1 - (t2*(CL + t0*Wxp))/(t1*t1);
      43             :     
      44       32849 :     float Jdd = 2.0f*t2*t2*(CL + t0*Wxp)/powf(t1,3) - (2.0f*t2*(1.5f*sqrtf(CL)*Wxp + 1.0f))/(t1*t1) - ((2.0f*B + 0.75f*WZ/sqrtf(CL))*(CL + t0*Wxp))/(t1*t1) + 0.75f*Wxp/(sqrtf(CL)*t1);
      45             : 
      46             :     // Check we're heading to a maximum, not a minimum!!
      47       32849 :     if (is_positive(Jdd)) {
      48             :         // Alternate mode, go uphill.
      49          85 :         CL = CL + 0.1 * (Jd>0.0f ? 1.0f : -1.0f);
      50             :     } else {
      51             :         // Newton should work.
      52       32764 :         CL = CL - Jd/Jdd;
      53             :     }
      54             : 
      55       32849 :     _CL_estimate = CL;
      56       32849 :     _CL_estimate = constrain_float(_CL_estimate, CLmin, CLmax);
      57             : }

Generated by: LCOV version 1.14