calculate the descend profiles based on the arrival constraints
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import pytz
|
||||
import sys
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
@@ -62,50 +63,106 @@ class Inbound:
|
||||
return timedelta(seconds = 0)
|
||||
|
||||
# calculate remaining trackmiles
|
||||
remainingDistanceNM = self.Report.distanceToIAF
|
||||
trackmiles = self.Report.distanceToIAF
|
||||
start = self.PlannedStar.Route[0]
|
||||
for i in range(1, len(self.PlannedStar.Route)):
|
||||
remainingDistanceNM += start.haversine(self.PlannedStar.Route[i]) * 0.539957
|
||||
turnIndices = [ -1, -1 ]
|
||||
constraints = []
|
||||
for i in range(0, len(self.PlannedStar.Route)):
|
||||
# identified the base turn
|
||||
if True == self.PlannedStar.Route[i].BaseTurn:
|
||||
turnIndices[0] = i
|
||||
# identified the final turn
|
||||
elif -1 != turnIndices[0] and True == self.PlannedStar.Route[i].FinalTurn:
|
||||
turnIndices[1] = i
|
||||
# skip waypoints until the final turn point is found
|
||||
elif -1 != turnIndices[0] and -1 == turnIndices[1]:
|
||||
continue
|
||||
|
||||
trackmiles += start.haversine(self.PlannedStar.Route[i]) * 0.539957
|
||||
|
||||
# check if a new constraint is defined
|
||||
altitude = -1
|
||||
speed = -1
|
||||
if None != self.PlannedStar.Route[i].Altitude:
|
||||
altitude = self.PlannedStar.Route[i].Altitude
|
||||
if None != self.PlannedStar.Route[i].Speed:
|
||||
speed = self.PlannedStar.Route[i].Speed
|
||||
if -1 != altitude or -1 != speed:
|
||||
constraints.append([ trackmiles, altitude, speed ])
|
||||
|
||||
start = self.PlannedStar.Route[i]
|
||||
|
||||
# add the remaining distance from the last waypoint to the runway threshold
|
||||
trackmiles += start.haversine(self.PlannedRunway.Runway.Start)
|
||||
|
||||
if turnIndices[0] > turnIndices[1] or (-1 == turnIndices[1] and -1 != turnIndices[0]):
|
||||
sys.stderr.write('Invalid constraint definition found for ' + self.PlannedStar.Name)
|
||||
sys.exit(-1)
|
||||
|
||||
# calculate descend profile
|
||||
flightTimeSeconds = 0
|
||||
currentHeading = Waypoint(latitude = self.Report.position.latitude, longitude = self.Report.position.longitude).bearing(self.PlannedStar.Route[0])
|
||||
distanceToWaypoint = self.Report.distanceToIAF
|
||||
nextWaypointIndex = 0
|
||||
currentIAS = self.PerformanceData.ias(self.Report.dynamics.altitude, trackmiles)
|
||||
currentPosition = [ self.Report.dynamics.altitude, self.Report.dynamics.groundSpeed ]
|
||||
while 0 < currentPosition[0]:
|
||||
lastDistance = remainingDistanceNM
|
||||
distanceToWaypoint = self.Report.distanceToIAF
|
||||
flightTimeSeconds = 0
|
||||
nextWaypointIndex = 0
|
||||
flownDistance = 0.0
|
||||
|
||||
# TODO integrate speed and altitude constraints
|
||||
while True:
|
||||
# check if a constraint cleanup is needed and if a speed-update is needed
|
||||
if 0 != len(constraints) and flownDistance >= constraints[0][0]:
|
||||
if -1 != constraints[0][2]:
|
||||
currentIAS = min(constraints[0][2], self.PerformanceData.ias(self.Report.dynamics.altitude, trackmiles - flownDistance))
|
||||
currentPosition[1] = min(weather.calculateGS(currentPosition[0], currentIAS, currentHeading), currentPosition[1])
|
||||
constraints.pop(0)
|
||||
|
||||
# calculate the next position after 10 seconds
|
||||
if (currentPosition[0] / 1000 * 3) > remainingDistanceNM:
|
||||
# search next altitude constraint
|
||||
altitudeDistance = 0
|
||||
nextAltitude = 0
|
||||
for constraint in constraints:
|
||||
if -1 != constraint[1]:
|
||||
altitudeDistance = constraint[0]
|
||||
nextAltitude = constraint[1]
|
||||
break
|
||||
|
||||
# check if update of altitude and speed is needed on 3° glide
|
||||
if currentPosition[0] > nextAltitude and ((currentPosition[0] - nextAltitude) / 1000 * 3) > (altitudeDistance - flownDistance):
|
||||
oldGroundspeed = currentPosition[1]
|
||||
descendRate = (currentPosition[1] / 60) / 3 * 1000 / 6
|
||||
newAltitude = currentPosition[0] - descendRate
|
||||
if 0 > newAltitude:
|
||||
newAltitude = 0
|
||||
|
||||
# get the planned IAS and calculate the new altitude and GS out of the predicted information
|
||||
# we assume that the aircraft only decelerates
|
||||
ias = self.PerformanceData.ias(newAltitude, remainingDistanceNM)
|
||||
currentPosition = [ newAltitude, min(weather.calculateGS(newAltitude, int(ias), currentHeading), currentPosition[1]) ]
|
||||
|
||||
# use the average between last and current speed to estimate the remaining distance
|
||||
remainingDistanceNM -= (currentPosition[1] + oldGroundspeed) / 2 / 60 / 6
|
||||
currentPosition = [ newAltitude, min(weather.calculateGS(newAltitude, currentIAS, currentHeading), currentPosition[1]) ]
|
||||
distance = (currentPosition[1] + oldGroundspeed) / 2 / 60 / 6
|
||||
else:
|
||||
remainingDistanceNM -= currentPosition[1] / 60 / 6
|
||||
distance = currentPosition[1] / 60 / 6
|
||||
|
||||
# update the statistics
|
||||
distanceToWaypoint -= distance
|
||||
flownDistance += distance
|
||||
newIAS = min(currentIAS, self.PerformanceData.ias(currentPosition[0], trackmiles - flownDistance))
|
||||
if newIAS < currentIAS:
|
||||
currentPosition[1] = min(weather.calculateGS(currentPosition[0], newIAS, currentHeading), currentPosition[1])
|
||||
currentIAS = newIAS
|
||||
|
||||
flightTimeSeconds += 10
|
||||
if 0 > remainingDistanceNM:
|
||||
if flownDistance >= trackmiles:
|
||||
break
|
||||
|
||||
# check if we follow a new waypoint pair
|
||||
distanceToWaypoint -= abs(lastDistance - remainingDistanceNM)
|
||||
if 0 >= distanceToWaypoint:
|
||||
lastWaypointIndex = nextWaypointIndex
|
||||
nextWaypointIndex += 1
|
||||
|
||||
# check if a skip from base to final turn waypoints is needed
|
||||
if -1 != turnIndices[0] and nextWaypointIndex > turnIndices[0] and nextWaypointIndex < turnIndices[1]:
|
||||
nextWaypointIndex = turnIndices[1]
|
||||
|
||||
# update the statistics
|
||||
if nextWaypointIndex < len(self.PlannedStar.Route):
|
||||
currentHeading = self.PlannedStar.Route[nextWaypointIndex - 1].bearing(self.PlannedStar.Route[nextWaypointIndex])
|
||||
distanceToWaypoint = self.PlannedStar.Route[lastWaypointIndex].haversine(self.PlannedStar.Route[nextWaypointIndex]) * 0.539957
|
||||
currentHeading = self.PlannedStar.Route[lastWaypointIndex].bearing(self.PlannedStar.Route[nextWaypointIndex])
|
||||
currentPosition[1] = min(weather.calculateGS(newAltitude, currentIAS, currentHeading), currentPosition[1])
|
||||
|
||||
return timedelta(seconds = flightTimeSeconds)
|
||||
|
||||
Reference in New Issue
Block a user