calculate the descend profiles based on the arrival constraints
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
import sys
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
@@ -62,50 +63,106 @@ class Inbound:
|
|||||||
return timedelta(seconds = 0)
|
return timedelta(seconds = 0)
|
||||||
|
|
||||||
# calculate remaining trackmiles
|
# calculate remaining trackmiles
|
||||||
remainingDistanceNM = self.Report.distanceToIAF
|
trackmiles = self.Report.distanceToIAF
|
||||||
start = self.PlannedStar.Route[0]
|
start = self.PlannedStar.Route[0]
|
||||||
for i in range(1, len(self.PlannedStar.Route)):
|
turnIndices = [ -1, -1 ]
|
||||||
remainingDistanceNM += start.haversine(self.PlannedStar.Route[i]) * 0.539957
|
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]
|
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
|
# calculate descend profile
|
||||||
flightTimeSeconds = 0
|
|
||||||
currentHeading = Waypoint(latitude = self.Report.position.latitude, longitude = self.Report.position.longitude).bearing(self.PlannedStar.Route[0])
|
currentHeading = Waypoint(latitude = self.Report.position.latitude, longitude = self.Report.position.longitude).bearing(self.PlannedStar.Route[0])
|
||||||
distanceToWaypoint = self.Report.distanceToIAF
|
currentIAS = self.PerformanceData.ias(self.Report.dynamics.altitude, trackmiles)
|
||||||
nextWaypointIndex = 0
|
|
||||||
currentPosition = [ self.Report.dynamics.altitude, self.Report.dynamics.groundSpeed ]
|
currentPosition = [ self.Report.dynamics.altitude, self.Report.dynamics.groundSpeed ]
|
||||||
while 0 < currentPosition[0]:
|
distanceToWaypoint = self.Report.distanceToIAF
|
||||||
lastDistance = remainingDistanceNM
|
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
|
# search next altitude constraint
|
||||||
if (currentPosition[0] / 1000 * 3) > remainingDistanceNM:
|
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]
|
oldGroundspeed = currentPosition[1]
|
||||||
descendRate = (currentPosition[1] / 60) / 3 * 1000 / 6
|
descendRate = (currentPosition[1] / 60) / 3 * 1000 / 6
|
||||||
newAltitude = currentPosition[0] - descendRate
|
newAltitude = currentPosition[0] - descendRate
|
||||||
if 0 > newAltitude:
|
if 0 > newAltitude:
|
||||||
newAltitude = 0
|
newAltitude = 0
|
||||||
|
|
||||||
# get the planned IAS and calculate the new altitude and GS out of the predicted information
|
currentPosition = [ newAltitude, min(weather.calculateGS(newAltitude, currentIAS, currentHeading), currentPosition[1]) ]
|
||||||
# we assume that the aircraft only decelerates
|
distance = (currentPosition[1] + oldGroundspeed) / 2 / 60 / 6
|
||||||
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
|
|
||||||
else:
|
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
|
flightTimeSeconds += 10
|
||||||
if 0 > remainingDistanceNM:
|
if flownDistance >= trackmiles:
|
||||||
break
|
break
|
||||||
|
|
||||||
# check if we follow a new waypoint pair
|
# check if we follow a new waypoint pair
|
||||||
distanceToWaypoint -= abs(lastDistance - remainingDistanceNM)
|
|
||||||
if 0 >= distanceToWaypoint:
|
if 0 >= distanceToWaypoint:
|
||||||
|
lastWaypointIndex = nextWaypointIndex
|
||||||
nextWaypointIndex += 1
|
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):
|
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)
|
return timedelta(seconds = flightTimeSeconds)
|
||||||
|
|||||||
Reference in New Issue
Block a user