]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIFlightPlanCreate.cxx
PerformanceDB improvements.
[flightgear.git] / src / AIModel / AIFlightPlanCreate.cxx
index c49b4abe8a6c7504e764ec779c22d4c63c5beb7b..47026b60ed71a826d8325e4f789ddad228b89313 100644 (file)
@@ -145,6 +145,7 @@ FGAIWaypoint *    FGAIFlightPlan::createInAir(FGAIAircraft * ac,
     wpt->setGear_down  (false                   );
     wpt->setFlaps_down (false                   );
     wpt->setOn_ground  (false                   );
+    wpt->setCrossat    (aElev                   );
     return wpt;
 }
 
@@ -427,6 +428,22 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
     return true;
 }
 
+static double accelDistance(double v0, double v1, double accel)
+{
+  double t = fabs(v1 - v0) / accel; // time in seconds to change velocity
+  // area under the v/t graph: (t * v0) + (dV / 2t) where (dV = v1 - v0)
+  return t * 0.5 * (v1 + v0); 
+}
+
+// find the horizontal distance to gain the specific altiude, holding
+// a constant pitch angle. Used to compute distance based on standard FD/AP
+// PITCH mode prior to VS or CLIMB engaging. Visually, we want to avoid
+// a dip in the nose angle after rotation, during initial climb-out.
+static double pitchDistance(double pitchAngleDeg, double altGainM)
+{
+  return altGainM / tan(pitchAngleDeg * SG_DEGREES_TO_RADIANS);
+}
+
 /*******************************************************************
  * CreateTakeOff 
  * A note on units: 
@@ -442,27 +459,22 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
                                    FGAirport * apt, double speed,
                                    const string & fltType)
 {
+    const double ACCEL_POINT = 105.0;
+    const double KNOTS_HOUR_TO_MSEC = SG_NM_TO_METER / 3600.0;
+  // climb-out angle in degrees. could move this to the perf-db but this
+  // value is pretty sane
+    const double INITIAL_PITCH_ANGLE = 12.5;
+  
     double accel = ac->getPerformance()->acceleration();
     double vTaxi = ac->getPerformance()->vTaxi();
     double vRotate = ac->getPerformance()->vRotate();
     double vTakeoff = ac->getPerformance()->vTakeoff();
-    //double vClimb = ac->getPerformance()->vClimb();
-
-    double accelMetric = (accel * SG_NM_TO_METER) / 3600;
-    double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
-    double vRotateMetric = (vRotate * SG_NM_TO_METER) / 3600;
-    double vTakeoffMetric = (vTakeoff * SG_NM_TO_METER) / 3600;
-    //double vClimbMetric = (vClimb * SG_NM_TO_METER) / 3600;
-    // Acceleration = dV / dT
-    // Acceleration X dT = dV
-    // dT = dT / Acceleration
-    //d = (Vf^2 - Vo^2) / (2*a)
-    //double accelTime = (vRotate - vTaxi) / accel;
-    //cerr << "Using " << accelTime << " as total acceleration time" << endl;
-    double accelDistance =
-        (vRotateMetric * vRotateMetric -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
+
+    double accelMetric = accel * KNOTS_HOUR_TO_MSEC;
+    double vTaxiMetric = vTaxi * KNOTS_HOUR_TO_MSEC;
+    double vRotateMetric = vRotate * KNOTS_HOUR_TO_MSEC;
+    double vTakeoffMetric = vTakeoff * KNOTS_HOUR_TO_MSEC;
+   
     FGAIWaypoint *wpt;
     // Get the current active runway, based on code from David Luff
     // This should actually be unified and extended to include 
@@ -475,41 +487,36 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
         apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
                                             heading);
     }
+  
     FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
     assert( rwy != NULL );
-
     double airportElev = apt->getElevation();
     
-
-    accelDistance =
-        (vTakeoffMetric * vTakeoffMetric -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    SGGeod accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
+    double d = accelDistance(vTaxiMetric, vRotateMetric, accelMetric) + ACCEL_POINT;
+  
+    SGGeod accelPoint = rwy->pointOnCenterline(d);
     wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
     pushBackWaypoint(wpt);
 
-    accelDistance =
-        ((vTakeoffMetric * 1.1) * (vTakeoffMetric * 1.1) -
-         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
-    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
-    wpt =
-        createOnGround(ac, "rotate", accelPoint, airportElev + 1000,
-                       vTakeoff * 1.1);
+    double vRef = vTakeoffMetric + 20; // climb-out at v2 + 20kts
+    double gearUpDist = d + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
+    accelPoint = rwy->pointOnCenterline(gearUpDist);
+    
+    wpt = cloneWithPos(ac, wpt, "gear-up", accelPoint);
+    wpt->setSpeed(vRef);
+    wpt->setCrossat(airportElev + 400);
     wpt->setOn_ground(false);
+    wpt->setGear_down(false);
     pushBackWaypoint(wpt);
-
-    wpt = cloneWithPos(ac, wpt, "3000 ft", rwy->end());
-    wpt->setAltitude(airportElev + 3000);
+  
+    double climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2000 * SG_FEET_TO_METER);
+    accelPoint = rwy->pointOnCenterline(climbOut);
+    wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vRef);
     pushBackWaypoint(wpt);
 
-    // Finally, add two more waypoints, so that aircraft will remain under
-    // Tower control until they have reached the 3000 ft climb point
-    SGGeod pt = rwy->pointOnCenterline(5000 + rwy->lengthM() * 0.5);
-    wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
-    wpt->setAltitude(airportElev + 5000);
-    pushBackWaypoint(wpt);
+  // as soon as we pass 2000', hand off to departure so the next acft can line up
+  // ideally the next aircraft would be able to line-up + hold but that's tricky
+  // with the current design.
     return true;
 }