"""
Basic calculations for the Trajectory Prediction (TP) using BADA
"""
from math import exp
from pyBADA import atmosphere as atm
[docs]
def cruiseFuelConsumption(AC, altitude, M, deltaTemp):
"""
Calculate the cruise fuel consumption for an aircraft during cruise flight using BADA.
:param AC: Aircraft object (instance of Bada3Aircraft, Bada4Aircraft, or BadaHAircraft).
:param altitude: Altitude in meters.
:param M: Mach number at cruising altitude.
:param deltaTemp: Temperature deviation from standard atmosphere.
:type AC: object
:type altitude: float
:type M: float
:type deltaTemp: float
:return: Fuel flow in kg/s.
:rtype: float
"""
[theta, delta, sigma] = atm.atmosphereProperties(
h=altitude, DeltaTemp=deltaTemp
)
TAS = atm.mach2Tas(Mach=M, theta=theta)
config = "CR"
flightPhase = "Cruise"
mass = AC.MREF
if AC.BADAFamily.BADA3:
# compute lift coefficient
CL = AC.CL(tas=TAS, sigma=sigma, mass=mass)
# compute drag coefficient
CD = AC.CD(CL=CL, config=config)
# compute drag force
Drag = AC.D(tas=TAS, sigma=sigma, CD=CD)
# compute thrust force and fuel flow
THR = Drag
fuelFlow = AC.ff(
h=altitude,
v=TAS,
T=THR,
config=config,
flightPhase=flightPhase,
)
elif AC.BADAFamily.BADA4:
# compute lift coefficient
CL = AC.CL(M=M, delta=delta, mass=mass)
# compute drag coefficient
[HLid, LG] = AC.flightEnvelope.getAeroConfig(config=config)
CD = AC.CD(M=M, CL=CL, HLid=HLid, LG=LG)
# compute drag force
Drag = AC.D(M=M, delta=delta, CD=CD)
# compute thrust force and fuel flow
THR = Drag
CT = AC.CT(Thrust=THR, delta=delta)
fuelFlow = AC.ff(
CT=CT, delta=delta, theta=theta, M=M, deltaTemp=deltaTemp
) # [kg/s]
elif AC.BADAFamily.BADAH:
# compute Power required for level flight
Preq = AC.Preq(sigma=sigma, tas=TAS, mass=mass, phi=0)
Peng_i = Preq
# Pav_i = AC.Pav(rating="MCNT", theta=theta, delta=delta) # assume MCNT rating as the limit
# if Pav_i < Preq:
# warnings.warn("Power Available is lower than Power Required",UserWarning)
# compute fuel flow for level flight
CP = AC.CP(Peng=Preq)
fuelFlow = AC.ff(delta=delta, CP=CP) # [kg/s]
return fuelFlow
[docs]
def breguetLeducInitialMass(
AC, distance, GS, cruiseFuelFlow, payload, fuelReserve
):
"""Calculate the estimated initial mass required for the aircraft using
the Breguet Leduc formula.
:param AC: Aircraft object (instance of Bada3Aircraft, Bada4Aircraft, or
BadaHAircraft).
:param distance: Flight distance in meters.
:param GS: Ground speed in m/s (assumed equal to true airspeed under no-
wind conditions).
:param cruiseFuelFlow: Fuel flow rate during cruise in kg/s.
:param payload: Payload percentage (of the maximum payload mass) to be
used.
:param fuelReserve: Fuel reserve time in seconds.
:type AC: object
:type distance: float
:type GS: float
:type cruiseFuelFlow: float
:type payload: float
:type fuelReserve: float
:return: Initial mass in kg.
:rtype: float
"""
fuelReserveMass = fuelReserve * cruiseFuelFlow
if AC.MPL is not None:
maximumPayload = AC.MPL
else:
maximumPayload = AC.MTOW - AC.OEW - AC.MFL
payloadMass = (payload / 100) * maximumPayload
minimumLandingMass = AC.OEW + payloadMass + fuelReserveMass
initialMass = minimumLandingMass * exp(
(cruiseFuelFlow * distance) / (AC.MREF * GS)
)
return initialMass
[docs]
def getInitialMass(
AC,
distance,
altitude,
M,
payload=60,
fuelReserve=3600,
flightPlanInitialMass=None,
deltaTemp=0,
):
"""Calculates the estimated initial aircraft mass assumig cruise phase,
combining flight plan data, aircraft envelope constraints, and an
exponential fuel consumption model inspired by the Breguet Leduc formula.
:param AC: Aircraft object (instance of Bada3Aircraft, Bada4Aircraft,
BadaEAircraft, or BadaHAircraft).
:param distance: Distance to be flown in meters.
:param altitude: Cruising altitude in meters.
:param M: Mach number at cruising altitude.
:param payload: Percentage of the maximum payload mass (default is 60%).
:param fuelReserve: Fuel reserve time in seconds (default is 3600 seconds,
or 1 hour).
:param flightPlanInitialMass: Optional initial mass from a flight plan, in
kg.
:param deltaTemp: Temperature deviation from standard atmosphere.
:type AC: object
:type distance: float
:type altitude: float
:type M: float
:type payload: float, optional
:type fuelReserve: float, optional
:type flightPlanInitialMass: float, optional
:type deltaTemp: float, optional
:return: Estimated initial aircraft mass in kg.
:rtype: float
"""
# set Initial Mass from FPL check
if flightPlanInitialMass is not None:
initialMass = flightPlanInitialMass
else:
# in case of no wind, the ground speed is the same as true airspeed
[theta, delta, sigma] = atm.atmosphereProperties(
h=altitude, DeltaTemp=deltaTemp
)
TAS = atm.mach2Tas(Mach=M, theta=theta)
GS = TAS
if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
if (AC.MMO is not None and AC.MMO >= 1.0) or (
AC.VMO is not None and AC.VMO >= 400
):
# identified as fighter jet
initialMass = AC.MREF
else:
cruiseFuelFlow = cruiseFuelConsumption(
AC=AC, altitude=altitude, M=M, deltaTemp=deltaTemp
)
initialMass = breguetLeducInitialMass(
AC=AC,
distance=distance,
GS=GS,
cruiseFuelFlow=cruiseFuelFlow,
payload=payload,
fuelReserve=fuelReserve,
)
elif AC.BADAFamily.BADAH:
if AC.vne is not None and AC.vne >= 400:
# identified as fighter
initialMass = AC.MREF
else:
cruiseFuelFlow = cruiseFuelConsumption(
AC=AC, altitude=altitude, M=M, deltaTemp=deltaTemp
)
initialMass = breguetLeducInitialMass(
AC=AC,
distance=distance,
GS=GS,
cruiseFuelFlow=cruiseFuelFlow,
payload=payload,
fuelReserve=fuelReserve,
)
# envelope check
initialMass = min(max(initialMass, AC.OEW), AC.MTOW)
return initialMass