calculate the descend profiles based on the arrival constraints

This commit is contained in:
Sven Czarnian
2021-10-13 18:13:00 +02:00
parent cea52736bf
commit 3313a8d463

View File

@@ -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)