def __init__(self, runway, aircraft, arrivalAirport, descentGlideSlopeDegrees=3.0): ''' arrival Airport provides the field elevation above sea level in meters ''' self.className = self.__class__.__name__ Graph.__init__(self) assert isinstance(descentGlideSlopeDegrees, float) self.descentGlideSlopeDegrees = descentGlideSlopeDegrees # sanity check assert isinstance(arrivalAirport, Airport) self.arrivalAirport = arrivalAirport ''' sanity check RunWay ''' assert isinstance(runway, RunWay) self.runway = runway assert isinstance(aircraft, BadaAircraft) self.aircraft = aircraft fieldElevationAboveSeaLevelMeters = arrivalAirport.getFieldElevationAboveSeaLevelMeters( ) print(self.className + ': airport field Elevation Above Sea Level= {0:.2f} meters'. format(fieldElevationAboveSeaLevelMeters)) strName = arrivalAirport.getName( ) + '-' + 'RunWay' + '-' + self.runway.getName() self.runWayEndPoint = WayPoint( Name=strName, LatitudeDegrees=runway.getLatitudeDegrees(), LongitudeDegrees=runway.getLongitudeDegrees(), AltitudeMeanSeaLevelMeters=fieldElevationAboveSeaLevelMeters) ''' touch down is provided from BADA Ground Movement Landing Length ''' landingDistanceMeters = self.aircraft.groundMovement.getLandingLengthMeters( ) #print self.className + ': {0} aircraft landing length: {1:.2F} meters'.format(self.aircraft.ICAOcode, landingDistanceMeters) runWayOrientationDegrees = self.runway.getTrueHeadingDegrees() ''' if orientation is 270 degrees from runway end point then ... touch down bearing is 360-270=90 bearing from end point ''' self.runWayTouchDownPoint = self.runWayEndPoint.getWayPointAtDistanceBearing( Name='runway-touch-down', DistanceMeters=landingDistanceMeters, BearingDegrees=runWayOrientationDegrees) ''' elevation of touch down point = field elevation''' self.runWayTouchDownPoint.setAltitudeMeanSeaLevelMeters( fieldElevationAboveSeaLevelMeters) strMsg = "{0} - distance from RunWay - TouchDown to RunWay - End= {1:.2f} meters".format( self.className, self.runWayTouchDownPoint.getDistanceMetersTo(self.runWayEndPoint)) print(strMsg) self.bearingDegrees = self.runWayTouchDownPoint.getBearingDegreesTo( self.runWayEndPoint) print(self.className + ": bearing from touch-down to runway end= {0:.2f} degrees". format(self.bearingDegrees))
def read(self): assert len(self.FilePath) > 0 self.book = open_workbook(self.FilePath) ''' assert there is only one sheet ''' sheet = self.book.sheet_by_name('WayPoints') for row in range(sheet.nrows): rowValues = sheet.row_values(row, start_colx=0, end_colx=sheet.ncols) # Print the values of the row formatted to 10 characters wide if row == 0: self.ColumnNames = {} index = 0 for column in rowValues: if column not in fieldNames: print( self.className + ': ERROR - expected way-points column name= {0} not in field names' .format(column)) return False else: self.ColumnNames[column] = index index += 1 else: WayPointName = str(rowValues[0]).strip().upper() if not (WayPointName in self.WayPointsDict.keys()): wayPointDict = {} for column in self.ColumnNames: if column == 'Latitude' or column == 'Longitude': ''' replace degree character ''' strLatLong = ( rowValues[self.ColumnNames[column]]).strip() if '°' in strLatLong: strLatLong = (strLatLong).replace('°', '-') #strLatLong = strLatLong.encode('ascii', 'ignore') strLatLong = str(strLatLong).strip().replace( "'", '-').replace(' ', '').replace('"', '') #print 'lat-long= '+ strLatLong wayPointDict[ column] = convertDegreeMinuteSecondToDecimal( strLatLong) else: wayPointDict[column] = str( rowValues[self.ColumnNames[column]]).strip() ''' create a way point ''' wayPoint = WayPoint(wayPointDict['WayPoint'], wayPointDict['Latitude'], wayPointDict['Longitude']) self.WayPointsDict[WayPointName] = wayPoint else: print( "duplicates found in Way Points database - way Point= {0}" .format(WayPointName)) return True
def test_waypoint(self): print("=========== WayPoint start =========== " + time.strftime("%c")) London = WayPoint('London-Heathrow', 51.5, 0.0) Orly = WayPoint('Orly', 48.726254, 2.365247) print("distance from London to Orly= ", London.getDistanceMetersTo(Orly), " meters") print("bearing from London to Orly= ", London.getBearingDegreesTo(Orly), " degrees") # Zurich = WayPoint('Zurich-Kloten', 47.458215, 8.555424) Marseille = WayPoint('Marseille-Marignane', 43.438431, 5.214382) Zurich = WayPoint('Zurich-Kloten', 47.458215, 8.555424) print("=========== WayPoint resume =========== " + time.strftime("%c")) print("distance from Marseille to Zurich= ", Marseille.getDistanceMetersTo(Zurich), " meters") print("bearing from Zurich to Marseille = ", Zurich.getBearingDegreesTo(Marseille), " degrees") distanceMeters = 321584.699454 bearingDegrees = Zurich.getBearingDegreesTo(Marseille) # bearingDegrees = Marseille.getBearingDegreesTo(Zurich) Zurich.dump() Marseille.dump() TopOfDescent = Zurich.getWayPointAtDistanceBearing('TopOfDescent', distanceMeters, bearingDegrees) TopOfDescent.dump() print("=========== WayPoint resume =========== " + time.strftime("%c")) London.dump() Orly.dump() bearingDegrees = Orly.getBearingDegreesTo(London) print("bearing from London to Orly= ", London.getBearingDegreesTo(Orly), " degrees") TopOfDescent = Orly.getWayPointAtDistanceBearing('TopOfDescent', distanceMeters, bearingDegrees) TopOfDescent.dump()
def computeTouchDownWayPoint(self): ''' get landing length in meters ''' landingLengthMeters = self.aircraft.getLandingLengthMeters() ''' run-way orientation ''' runwayTrueHeadingDegrees = self.runway.getTrueHeadingDegrees() ''' run-way end point ''' strRunWayEndPointName = self.airport.getName() + '-' + 'Rwy'+'-'+self.runway.getName() runWayEndPoint = WayPoint (Name = strRunWayEndPointName, LatitudeDegrees = self.runway.getLatitudeDegrees(), LongitudeDegrees = self.runway.getLongitudeDegrees(), AltitudeMeanSeaLevelMeters =self.airport.getFieldElevationAboveSeaLevelMeters()) strTouchDownWayPointName = self.airport.getName() + '-' + 'Rwy'+'-' + self.runway.getName() + '-' + 'touch-down' touchDownWayPoint = runWayEndPoint.getWayPointAtDistanceBearing(Name = strTouchDownWayPointName, DistanceMeters = landingLengthMeters, BearingDegrees = runwayTrueHeadingDegrees) touchDownWayPoint.setAltitudeMeanSeaLevelMeters(self.airport.getFieldElevationAboveSeaLevelMeters()) return touchDownWayPoint
def read(self): workbook = xlrd.open_workbook(self.FilePath) worksheet = workbook.sheet_by_index(0) self.rows = [] for i, row in enumerate(range(worksheet.nrows)): r = [] for j, col in enumerate(range(worksheet.ncols)): r.append(worksheet.cell_value(i, j)) if (i == 0): self.headers = r else: self.rows.append(r) self.geoPoints.append(WayPoint(r[1], r[2], r[3])) print("{0} - read {1} rows".format(self.className, len(self.rows))) print(self.headers) # Print column headings print(self.rows[0]) # Print first data row sample return (len(self.rows) > 0)
def test_DescentGlideSlope(self): atmosphere = Atmosphere() earth = Earth() print '==================== three degrees Descent Slope Start ==================== ' + time.strftime( "%c") acBd = BadaAircraftDatabase() aircraftICAOcode = 'A320' if acBd.read(): if (acBd.aircraftExists(aircraftICAOcode) and acBd.aircraftPerformanceFileExists(aircraftICAOcode)): print '==================== aircraft found ==================== ' + time.strftime( "%c") aircraft = BadaAircraft( ICAOcode=aircraftICAOcode, aircraftFullName=acBd.getAircraftFullName( aircraftICAOcode), badaPerformanceFilePath=acBd.getAircraftPerformanceFile( aircraftICAOcode), atmosphere=atmosphere, earth=earth) aircraft.dump() assert not (aircraft is None) print '==================== runways database ==================== ' + time.strftime( "%c") runWaysDatabase = RunWayDataBase() assert runWaysDatabase.read() runway = runWaysDatabase.getFilteredRunWays(airportICAOcode='LFML', runwayName='') print runway print "=========== arrival airport =========== " + time.strftime("%c") airportsDB = AirportsDatabase() assert (airportsDB.read()) MarseilleMarignane = airportsDB.getAirportFromICAOCode('LFML') print MarseilleMarignane print "=========== descent glide slope =========== " + time.strftime( "%c") threeDegreesGlideSlope = DescentGlideSlope( runway=runway, aircraft=aircraft, arrivalAirport=MarseilleMarignane) initialWayPoint = WayPoint(Name='startOfDescentGlideSlope', ) print "=========== DescentGlideSlope build the glide slope =========== " + time.strftime( "%c") # threeDegreesGlideSlope.buildGlideSlope(deltaTimeSeconds = 0.1, # elapsedTimeSeconds = 0.0, # initialWayPoint = None, # flownDistanceMeters = 0.0, # distanceStillToFlyMeters = 100000.0, # distanceToLastFixMeters = 100000.0) threeDegreesGlideSlope.buildSimulatedGlideSlope( descentGlideSlopeSizeNautics=5.0) print "=========== DescentGlideSlope =========== " + time.strftime( "%c") for node in threeDegreesGlideSlope.getVertices(): print node print "=========== DescentGlideSlope length =========== " + time.strftime( "%c") print "get number of vertices= {0}".format( threeDegreesGlideSlope.getNumberOfVertices()) print "get number of edges= {0}".format( threeDegreesGlideSlope.getNumberOfEdges()) print 'Glide Slope overall length= {0} meters'.format( threeDegreesGlideSlope.computeLengthMeters()) threeDegreesGlideSlope.createKmlOutputFile() threeDegreesGlideSlope.createXlsxOutputFile() print '==================== three degrees Descent Slope End ==================== ' + time.strftime( "%c")
def computeGreatCircle(self, deltaTimeSeconds, elapsedTimeSeconds, distanceStillToFlyMeters, distanceToLastFixMeters): ''' internally modified ''' initialDeltaTimeSeconds = deltaTimeSeconds ''' build the great circle ''' distance_radians = 2 * math.asin(math.sqrt(math.pow((math.sin((self.ptlat1_radians-self.ptlat2_radians)/2)),2) + math.cos(self.ptlat1_radians) * math.cos(self.ptlat2_radians)*math.pow((math.sin((self.ptlon1_radians-self.ptlon2_radians)/2)),2))) ''' 6371.009 represents the mean radius of the earth''' ''' shortest path distance''' distanceMeters = EarthMeanRadiusMeters * distance_radians #print self.className + ': computeGreatCircle shortest path distance= ' + str(distanceMeters) + ' meters' ''' init the loop index ''' index = 0 elapsedTimeSeconds = elapsedTimeSeconds #print self.className + ': initial True Air Speed= ' + str(trueAirSpeedMetersSecond) + ' meters/second' overflownDistanceMeters = 0.0 ''' loop over the over-flown distance ''' endOfSimulation = False while ( (endOfSimulation == False) and (overflownDistanceMeters < distanceMeters)): ''' initialization of the loop ''' if index == 0: print ( self.className + ': initial way-point= {0}'.format(self.initialWayPoint) ) intermediateWayPoint = self.initialWayPoint if self.aircraft.isCruiseSpeedReached(): ''' speed up the computation => step = 10 seconds ''' deltaTimeSeconds = 10.0 else: deltaTimeSeconds = initialDeltaTimeSeconds ''' fly => increase in true air speed ''' endOfSimulation, deltaDistanceMeters , altitudeMeanSeaLevelMeters = self.aircraft.fly( elapsedTimeSeconds = elapsedTimeSeconds, deltaTimeSeconds = deltaTimeSeconds, distanceStillToFlyMeters = distanceStillToFlyMeters, currentPosition = intermediateWayPoint, distanceToLastFixMeters = distanceToLastFixMeters) #print self.className + ': True AirSpeed= ' + str(trueAirSpeedMetersSecond) + ' meters/second' ''' cumulated over-flown distance ''' overflownDistanceMeters += deltaDistanceMeters distanceStillToFlyMeters -= deltaDistanceMeters distanceToLastFixMeters -= deltaDistanceMeters fprime = overflownDistanceMeters / distanceMeters #print self.className + ': altitude= ' + str(altitudeMeanSeaLevelMeters) + ' meters' ''' fprime is expressed as a fraction along the route from point 1 to point 2 ''' A = math.sin((1-fprime)*distance_radians) / math.sin(distance_radians) B = math.sin(fprime*distance_radians) / math.sin(distance_radians) x = A * math.cos(self.ptlat1_radians) * math.cos(self.ptlon1_radians) + B * math.cos(self.ptlat2_radians) * math.cos(self.ptlon2_radians) y = A * math.cos(self.ptlat1_radians) * math.sin(self.ptlon1_radians) + B * math.cos(self.ptlat2_radians) * math.sin(self.ptlon2_radians) z = A * math.sin(self.ptlat1_radians) + B * math.sin(self.ptlat2_radians) newLatitudeRadians = math.atan2(z, math.sqrt(math.pow(x,2)+math.pow(y,2))) newLongitudeRadians = math.atan2(y,x) newlat_degrees = math.degrees(newLatitudeRadians) newlon_degrees = math.degrees(newLongitudeRadians) #name = 'gc-pt-{0}-{1:.2f}-Nm'.format(index, overflownDistanceMeters*Meter2NauticalMiles) name = '' ''' new way point is built with an altitude ''' newWayPoint = WayPoint(Name = name, LatitudeDegrees = newlat_degrees, LongitudeDegrees = newlon_degrees, AltitudeMeanSeaLevelMeters = altitudeMeanSeaLevelMeters) ''' update new point ''' elapsedTimeSeconds += deltaTimeSeconds newWayPoint.setElapsedTimeSeconds(elapsedTimeSeconds) ''' build the route ''' self.addVertex(newWayPoint) ''' set new intermediate way-point ''' intermediateWayPoint = newWayPoint ''' increment index needed when adding vertex ''' index += 1 ''' rename the final way point ''' intermediateWayPoint.setName(self.finalWayPoint.getName()) # minutes, seconds = divmod(elapsedTimeSeconds, 60) # strMsg = ': passing way-point: {0} ... altitude= {1:.2f} feet ... distance= {2:.2f} nautics ... elapsed time= {3:.2f} sec ... elapsed time= {4} min {5} sec'.format( # self.finalWayPoint.getName(), # altitudeMeanSeaLevelMeters * Meter2Feet, # self.computeLengthMeters()* Meter2NauticalMiles, # elapsedTimeSeconds, int(minutes), int(seconds)) # print self.className + strMsg print ( self.className + ': final way-point= {0}'.format(intermediateWayPoint) ) return endOfSimulation
def buildDepartureGroundRun(self, deltaTimeSeconds, elapsedTimeSeconds, distanceStillToFlyMeters, distanceToLastFixMeters): ''' build the departure ground run ''' ''' elapsedTimeSeconds in seconds ''' elapsedTimeSeconds = elapsedTimeSeconds ''' run-way end point ''' strRunWayEndPointName = self.airport.getName() + '-' + 'Rwy'+'-'+self.runway.getName() runWayEndPoint = WayPoint (Name=strRunWayEndPointName, LatitudeDegrees=self.runway.getLatitudeDegrees(), LongitudeDegrees=self.runway.getLongitudeDegrees(), AltitudeMeanSeaLevelMeters=self.airport.getFieldElevationAboveSeaLevelMeters()) ''' run-way true heading ''' runwayTrueHeadingDegrees = self.runway.getTrueHeadingDegrees() ''' call base class Graph to build Climb Ramp core of the route ''' index = 0 self.addVertex(runWayEndPoint) index += 1 ''' departure ground run => initial speed is null ''' trueAirSpeedMetersSecond = 0.1 ''' ground run leg distance ''' totalLegDistanceMeters = 0.0 self.aircraft.initStateVector( elapsedTimeSeconds, trueAirSpeedMetersSecond, self.airport.getFieldElevationAboveSeaLevelMeters()) ''' Usually, the lift-off speed is designated to be 1.2 * Vstall at a given weight, an aircraft will rotate and climb, stall or fly at an approach to landing at approx the same CAS. regardless of the elevation (height above sea level) , even though the true airspeed and ground-speed may differ significantly. These V speeds are normally published as IAS rather than CAS so they can be read directly from the airspeed indicator. ''' VStallSpeedCASKnots = self.aircraft.computeStallSpeedCasKnots() print self.className + ': V stall Calibrated AirSpeed= {0:.2f} knots'.format(VStallSpeedCASKnots) ''' loop until Stall CAS reached ''' endOfSimulation = False while ((endOfSimulation == False) and ( tas2cas(tas = trueAirSpeedMetersSecond , altitude = self.airport.getFieldElevationAboveSeaLevelMeters(), temp='std', speed_units = 'm/s', alt_units = 'm') * MeterPerSecond2Knots ) < (1.2 * VStallSpeedCASKnots)): ''' initial loop index ''' if index == 1: intermediateWayPoint = runWayEndPoint ''' fly => increase in true air speed ''' ''' during ground run => all the energy is used to increase the Kinetic energy => no potential energy increase ''' endOfSimulation, deltaDistanceMeters , altitudeMeters = self.aircraft.fly( elapsedTimeSeconds = elapsedTimeSeconds, deltaTimeSeconds = deltaTimeSeconds, distanceStillToFlyMeters = distanceStillToFlyMeters, currentPosition = intermediateWayPoint, distanceToLastFixMeters = distanceToLastFixMeters) trueAirSpeedMetersSecond = self.aircraft.getCurrentTrueAirSpeedMetersSecond() assert (((self.airport.getFieldElevationAboveSeaLevelMeters() - 10.0) <= altitudeMeters) and ( altitudeMeters <= (self.airport.getFieldElevationAboveSeaLevelMeters() + 10.0))) #print self.className + ': delta distance= ' + str(deltaDistanceMeters) + ' meters' # name of the next point totalLegDistanceMeters += deltaDistanceMeters distanceStillToFlyMeters -= deltaDistanceMeters distanceToLastFixMeters -= deltaDistanceMeters Name = '' if index == 1: Name = 'ground-run-pt-{0}-{1:.2f}-meters'.format(index-1, totalLegDistanceMeters) #bearingDegrees = math.fmod ( runwayTrueHeadingDegrees + 180.0 , 360.0 ) bearingDegrees = runwayTrueHeadingDegrees newIntermediateWayPoint = intermediateWayPoint.getWayPointAtDistanceBearing(Name = Name, DistanceMeters = deltaDistanceMeters, BearingDegrees = bearingDegrees) ''' during the ground run - altitude = airport field elevation ''' newIntermediateWayPoint.setAltitudeMeanSeaLevelMeters(self.airport.getFieldElevationAboveSeaLevelMeters()) ''' update route waypoint ''' elapsedTimeSeconds += deltaTimeSeconds newIntermediateWayPoint.setElapsedTimeSeconds(elapsedTimeSeconds) ''' insert in the route ''' self.addVertex(newIntermediateWayPoint) ''' copy the intermediate way-point ''' intermediateWayPoint = newIntermediateWayPoint ''' increment the index ''' index += 1 ''' rename last point as take-off ''' intermediateWayPoint.setName(Name = 'Take-Off-{0:.2f}-meters'.format(totalLegDistanceMeters))