diff --git a/examples/BADAData.py b/examples/BADAData.py new file mode 100644 index 0000000..4602199 --- /dev/null +++ b/examples/BADAData.py @@ -0,0 +1,40 @@ +""" +Example of BADA parametes retrieval for specific aircraft +""" + +from pyBADA.bada3 import Bada3Aircraft +from pyBADA.bada3 import Parser as Bada3Parser + +badaVersion = "DUMMY" + +# loading all the BADA data into a dataframe +allData = Bada3Parser.parseAll(badaVersion=badaVersion) + +# retrieve specific data from the whole database, including synonyms +params = Bada3Parser.getBADAParameters( + df=allData, + acName=["B737", "A1", "P38", "AT45", "DA42"], + parameters=["VMO", "MMO", "MTOW", "engineType"], +) +print(params) +print("\n") + +params = Bada3Parser.getBADAParameters( + df=allData, + acName=["B737"], + parameters=["VMO", "MMO", "MTOW", "engineType"], +) +print(params) +print("\n") + +params = Bada3Parser.getBADAParameters( + df=allData, acName="DA42", parameters=["VMO", "MMO", "MTOW", "engineType"] +) +print(params) +print("\n") + +params = Bada3Parser.getBADAParameters( + df=allData, acName="DA42", parameters="VMO" +) +print(params) +print("\n") diff --git a/examples/ac_trajectory.py b/examples/ac_trajectory.py new file mode 100644 index 0000000..f2914ed --- /dev/null +++ b/examples/ac_trajectory.py @@ -0,0 +1,953 @@ +""" +Example of BADA3 and BADA4 trajectory using TCL +""" + +from dataclasses import dataclass +import matplotlib.pyplot as plt + +from pyBADA import atmosphere as atm +from pyBADA import conversions as conv +from pyBADA import TCL as TCL +from pyBADA.flightTrajectory import FlightTrajectory as FT + +from pyBADA.bada3 import Bada3Aircraft +from pyBADA.bada4 import Bada4Aircraft +from pyBADA.bada4 import Parser as Bada4Parser +from pyBADA.bada3 import Parser as Bada3Parser + + +@dataclass +class target: + ROCDtarget: float = None + slopetarget: float = None + acctarget: float = None + ESFtarget: float = None + + +# initialization of BADA3/4 +# uncomment for testing different BADA family if available + +badaVersion = "DUMMY" + +# allData = Bada3Parser.parseAll(badaVersion=badaVersion) +allData = Bada4Parser.parseAll(badaVersion=badaVersion) +print(allData) + +# AC = Bada3Aircraft(badaVersion=badaVersion, acName='J2H', allData=allData) +AC = Bada4Aircraft( + badaVersion=badaVersion, acName="Dummy-TWIN", allData=allData +) + + +# create a Flight Trajectory object to store the output from TCL segment calculations +ft = FT() + +# default parameters +speedType = "CAS" # {M, CAS, TAS} +wS = 0 # [kt] wind speed +ba = 0 # [deg] bank angle +DeltaTemp = 0 # [K] delta temperature from ISA + +# Initial conditions +m_init = AC.OEW + 0.7 * (AC.MTOW - AC.OEW) # [kg] initial mass +CAS_init = 170 # [kt] Initial CAS +Hp_RWY = 318.0 # [ft] CDG RWY26R elevation + +# take-off conditions +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(Hp_RWY), DeltaTemp=DeltaTemp +) # atmosphere properties at RWY altitude +[cas_cl1, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(Hp_RWY), + mass=m_init, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) # [m/s] take-off CAS + +Hp_CR = 33000 # [ft] CRUISing level + +# BADA speed schedule +[Vcl1, Vcl2, Mcl] = AC.flightEnvelope.getSpeedSchedule( + phase="Climb" +) # BADA Climb speed schedule +[Vcr1, Vcr2, Mcr] = AC.flightEnvelope.getSpeedSchedule( + phase="Cruise" +) # BADA Cruise speed schedule +[Vdes1, Vdes2, Mdes] = AC.flightEnvelope.getSpeedSchedule( + phase="Descent" +) # BADA Descent speed schedule + + +# ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +# CLIMB to threshold altitude 1500ft at take-off speed +# ------------------------------------------------ +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas_cl1), + Hp_init=Hp_RWY, + Hp_final=1499, + m_init=m_init, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# accelerate according to BADA ARPM for below 3000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(2999), DeltaTemp=DeltaTemp +) +[cas_cl2, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(2999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl2), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 3000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=2999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 4000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(3999), DeltaTemp=DeltaTemp +) +[cas_cl3, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(3999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl3), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 4000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 5000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(4999), DeltaTemp=DeltaTemp +) +[cas_cl4, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(4999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl4), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 5000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=4999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 6000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(5999), DeltaTemp=DeltaTemp +) +[cas_cl5, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(5999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl5), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 6000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=5999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 10000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(9999), DeltaTemp=DeltaTemp +) +[cas_cl6, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(9999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl6), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 10000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=9999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for above 10000ft and below crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(Vcl2), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# CLIMB to crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# calculate the crosover altitude for climb phase +crossoverAltitude = conv.m2ft(atm.crossOver(Vcl2, Mcl)) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=crossoverAltitude, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# climb at M from crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="M", + v=Mcl, + Hp_init=Hp, + Hp_final=Hp_CR, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# if not at CR speed -> adapt the speed first (acc/dec) +# ------------------------------------------------ +# current values +Hp, m_final, M_final = ft.getFinalValue(AC, ["Hp", "mass", "M"]) + +if M_final < Mcr: + control = target(acctarget=0.5) + flightTrajectory = TCL.accDec( + AC=AC, + speedType="M", + v_init=M_final, + v_final=Mcr, + Hp_init=Hp, + control=control, + phase="Cruise", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) + ft.append(AC, flightTrajectory) + +# CRUISE for 200 NM +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedLevel( + AC=AC, + lengthType="distance", + length=200, + speedType="M", + v=Mcr, + Hp_init=Hp, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# CRUISE Step for 300 NM +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedLevel( + AC=AC, + lengthType="distance", + length=200, + step_length=50, + maxRFL=36000, + speedType="M", + v=Mcr, + Hp_init=Hp, + m_init=m_final, + stepClimb=True, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# acc/dec to DESCENT speed during the descend +# ------------------------------------------------ +# current values +Hp, m_final, M_final = ft.getFinalValue(AC, ["Hp", "mass", "M"]) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="M", + v_init=M_final, + v_final=Mdes, + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# descend to crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +# calculate the crosover altitude for descend phase +crossoverAltitude = conv.m2ft(atm.crossOver(Vdes2, Mdes)) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="M", + v=Mdes, + Hp_init=Hp, + Hp_final=crossoverAltitude, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# descend to FL100 +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(Vdes2), + Hp_init=Hp, + Hp_final=10000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# decelerate according to BADA ARPM for below FL100 +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(9999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(9999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# descend to 6000ft +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas), + Hp_init=Hp, + Hp_final=6000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# decelerate according to BADA ARPM for below 6000 +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(5999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(5999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# descend to 5000ft +# ------------------------------------------------ +# current values +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas), + Hp_init=Hp, + Hp_final=5000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3700, + slopetarget=-3.0, + config="AP", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) + +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(2999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(2999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="AP", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +if Hp > 2000: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=2000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) + ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(1999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(1999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +if Hp > 1500: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=1500, + slopetarget=-3.0, + config="LD", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) + ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(1499), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(1499), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +if Hp > 1000: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=1000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) + ft.append(AC, flightTrajectory) + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config=None, + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + ) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final = ft.getFinalValue(AC, ["Hp", "mass", "CAS"]) + +flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=Hp_RWY, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +# print and plot final trajectory +df = ft.getFT(AC=AC) +print(df) + +# Plotting the graph Hp=f(dist) +plt.figure(1, figsize=(8, 6)) +plt.plot(df["dist"], df["Hp"], linestyle="-", color="b") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("Pressure Altitude [ft]") +plt.title("Pressure Altitude as a Function of Distance") + +# Plot for Calibrated Airspeed (CAS) +plt.figure(2, figsize=(8, 6)) +plt.plot(df["dist"], df["CAS"], linestyle="-", color="r") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("CAS [kt]") +plt.title("Calibrated Airspeed (CAS) as a Function of Distance") + +# Display the plot +plt.show() + +# save the output to a CSV/XLSX file +# ------------------------------------------------ +# ft.save2csv(os.path.join(grandParentDir, "flightTrajectory_export"), separator=",") +# ft.save2xlsx(os.path.join(grandParentDir, "flightTrajectory_export")) diff --git a/examples/ac_trajectory_GPS.py b/examples/ac_trajectory_GPS.py new file mode 100644 index 0000000..1835ba7 --- /dev/null +++ b/examples/ac_trajectory_GPS.py @@ -0,0 +1,1302 @@ +""" +Example of BADA3 and BADA4 trajectory including geodesic calculations using TCL +""" + +from dataclasses import dataclass +import matplotlib.pyplot as plt +import os + +from pyBADA import atmosphere as atm +from pyBADA import conversions as conv +from pyBADA import TCL as TCL +from pyBADA.flightTrajectory import FlightTrajectory as FT +from pyBADA.magnetic import Grid + +from pyBADA.bada3 import Bada3Aircraft +from pyBADA.bada4 import Bada4Aircraft +from pyBADA.bada4 import Parser as Bada4Parser +from pyBADA.bada3 import Parser as Bada3Parser + + +@dataclass +class target: + ROCDtarget: float = None + slopetarget: float = None + acctarget: float = None + ESFtarget: float = None + + +badaVersion = "DUMMY" + +# allData = Bada3Parser.parseAll(badaVersion=badaVersion) +allData = Bada4Parser.parseAll(badaVersion=badaVersion) +print(allData) + +# AC = Bada3Aircraft(badaVersion=badaVersion, acName='J2H', allData=allData) +AC = Bada4Aircraft( + badaVersion=badaVersion, acName="Dummy-TWIN", allData=allData +) + +# get magnetic declination data +magneticDeclinationGrid = Grid() + +# create a Flight Trajectory object to store the output from TCL segment calculations +ft = FT() + +# default parameters +speedType = "CAS" # {M, CAS, TAS} +wS = 0 # [kt] wind speed +ba = 0 # [deg] bank angle +DeltaTemp = 0 # [K] delta temperature from ISA + +# Initial conditions +m_init = AC.OEW + 0.7 * (AC.MTOW - AC.OEW) # [kg] initial mass +CAS_init = 170 # [kt] Initial CAS +Hp_RWY = 318.0 # [ft] CDG RWY26R elevation +Lat_init = 48.9982052030771 # CDG RWY26R coordinates +Lon_init = 2.5995367285775965 # CDG RWY26R coordinates + +# take-off conditions +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(Hp_RWY), DeltaTemp=DeltaTemp +) # atmosphere properties at RWY altitude +[cas_cl1, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(Hp_RWY), + mass=m_init, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) # [m/s] take-off CAS + + +Hp_CR = 33000 # [ft] CRUISing level + +# BADA speed schedule +[Vcl1, Vcl2, Mcl] = AC.flightEnvelope.getSpeedSchedule( + phase="Climb" +) # BADA Climb speed schedule +[Vcr1, Vcr2, Mcr] = AC.flightEnvelope.getSpeedSchedule( + phase="Cruise" +) # BADA Cruise speed schedule +[Vdes1, Vdes2, Mdes] = AC.flightEnvelope.getSpeedSchedule( + phase="Descent" +) # BADA Descent speed schedule + +# ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +# CLIMB to threshold altitude 1500ft at take-off speed +# ------------------------------------------------ +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas_cl1), + Hp_init=Hp_RWY, + Hp_final=1499, + m_init=m_init, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=Lat_init, + Lon=Lon_init, + initialHeading={"magnetic": None, "true": 50, "constantHeading": False}, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# accelerate according to BADA ARPM for below 3000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(2999), DeltaTemp=DeltaTemp +) +[cas_cl2, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(2999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl2), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 3000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=2999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 4000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(3999), DeltaTemp=DeltaTemp +) +[cas_cl3, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(3999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl3), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 4000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 5000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(4999), DeltaTemp=DeltaTemp +) +[cas_cl4, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(4999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl4), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 5000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=4999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 6000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(5999), DeltaTemp=DeltaTemp +) +[cas_cl5, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(5999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl5), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 6000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=5999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for below 10000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(9999), DeltaTemp=DeltaTemp +) +[cas_cl6, speedUpdated] = AC.ARPM.climbSpeed( + h=conv.ft2m(9999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas_cl6), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CLIMB to threshold altitude 10000ft +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=9999, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# accelerate according to BADA ARPM for above 10000ft and below crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(Vcl2), + Hp_init=Hp, + control=None, + phase="Climb", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# CLIMB to crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# calculate the crosover altitude for climb phase +crossoverAltitude = conv.m2ft(atm.crossOver(Vcl2, Mcl)) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=crossoverAltitude, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# climb at M from crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="M", + v=Mcl, + Hp_init=Hp, + Hp_final=Hp_CR, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# if not at CR speed -> adapt the speed first (acc/dec) +# ------------------------------------------------ +# current values +Hp, m_final, M_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "M", "LAT", "LON", "HDGTrue"] +) + +if M_final < Mcr: + control = target(acctarget=0.5) + flightTrajectory = TCL.accDec( + AC=AC, + speedType="M", + v_init=M_final, + v_final=Mcr, + Hp_init=Hp, + control=control, + phase="Cruise", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) + ft.append(AC, flightTrajectory) + +# CRUISE for 200 NM +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedLevel( + AC=AC, + lengthType="distance", + length=200, + speedType="M", + v=Mcr, + Hp_init=Hp, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# CRUISE Step for 300 NM +# ------------------------------------------------ +# current values +# Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( +# AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +# ) + +# flightTrajectory = TCL.constantSpeedLevel( +# AC=AC, +# lengthType="distance", +# length=200, +# step_length=50, +# maxRFL=36000, +# speedType="M", +# v=Mcr, +# Hp_init=Hp, +# m_init=m_final, +# stepClimb=True, +# wS=wS, +# bankAngle=ba, +# DeltaTemp=DeltaTemp, +# Lat=LAT_final, +# Lon=LON_final, +# initialHeading={"magnetic":None, "true":HDGTrue, "constantHeading":False}, +# magneticDeclinationGrid=magneticDeclinationGrid +# ) +# ft.append(AC, flightTrajectory) + +# acc/dec to DESCENT speed during the descend +# ------------------------------------------------ +# current values +Hp, m_final, M_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "M", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="M", + v_init=M_final, + v_final=Mdes, + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# descend to crossover altitude +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +# calculate the crosover altitude for descend phase +crossoverAltitude = conv.m2ft(atm.crossOver(Vdes2, Mdes)) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="M", + v=Mdes, + Hp_init=Hp, + Hp_final=crossoverAltitude, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# descend to FL100 +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(Vdes2), + Hp_init=Hp, + Hp_final=10000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# decelerate according to BADA ARPM for below FL100 +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(9999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(9999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# descend to 6000ft +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas), + Hp_init=Hp, + Hp_final=6000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# decelerate according to BADA ARPM for below 6000 +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(5999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(5999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + phase="Descent", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# descend to 5000ft +# ------------------------------------------------ +# current values +Hp, m_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedRating( + AC=AC, + speedType="CAS", + v=conv.ms2kt(cas), + Hp_init=Hp, + Hp_final=5000, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3700, + slopetarget=-3.0, + config="AP", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=3000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) + +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(2999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(2999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="AP", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +if Hp > 2000: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=2000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) + ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(1999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(1999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +if Hp > 1500: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=1500, + slopetarget=-3.0, + config="LD", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) + ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(1499), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(1499), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config="LD", + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +if Hp > 1000: + flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=1000, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) + ft.append(AC, flightTrajectory) + +# descend on ILS with 3deg glideslope while decelerating +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +# get BADA target speed from BADA ARPM procedure for the altitude bracket below +[theta, delta, sigma] = atm.atmosphereProperties( + h=conv.ft2m(999), DeltaTemp=DeltaTemp +) +[cas, speedUpdated] = AC.ARPM.descentSpeed( + h=conv.ft2m(999), + mass=m_final, + theta=theta, + delta=delta, + DeltaTemp=DeltaTemp, +) + +control = target(slopetarget=-3.0) +if AC.BADAFamily.BADA3: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config=None, + speedBrakes={"deployed": True, "value": 0.03}, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) +elif AC.BADAFamily.BADA4: + flightTrajectory = TCL.accDec( + AC=AC, + speedType="CAS", + v_init=CAS_final, + v_final=conv.ms2kt(cas), + Hp_init=Hp, + control=control, + phase="Descent", + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, + ) +ft.append(AC, flightTrajectory) + + +# descend on ILS with 3deg glideslope to next altitude threshold +# ------------------------------------------------ +# current values +Hp, m_final, CAS_final, LAT_final, LON_final, HDGTrue = ft.getFinalValue( + AC, ["Hp", "mass", "CAS", "LAT", "LON", "HDGTrue"] +) + +flightTrajectory = TCL.constantSpeedSlope( + AC=AC, + speedType="CAS", + v=CAS_final, + Hp_init=Hp, + Hp_final=Hp_RWY, + slopetarget=-3.0, + config=None, + m_init=m_final, + wS=wS, + bankAngle=ba, + DeltaTemp=DeltaTemp, + Lat=LAT_final, + Lon=LON_final, + initialHeading={ + "magnetic": None, + "true": HDGTrue, + "constantHeading": False, + }, + magneticDeclinationGrid=magneticDeclinationGrid, +) +ft.append(AC, flightTrajectory) + +# print and plot final trajectory +df = ft.getFT(AC=AC) +print(df) + +# Plotting the graph Hp=f(dist) +plt.figure(1, figsize=(8, 6)) +plt.plot(df["dist"], df["Hp"], linestyle="-", color="b") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("Pressure Altitude [ft]") +plt.title("Pressure Altitude as a Function of Distance") + +# Plot for Calibrated Airspeed (CAS) +plt.figure(2, figsize=(8, 6)) +plt.plot(df["dist"], df["CAS"], linestyle="-", color="r") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("CAS [kt]") +plt.title("Calibrated Airspeed (CAS) as a Function of Distance") + +# Display the plot +plt.show() + + +# save the output to a CSV/XLSX file +# ------------------------------------------------ +# ft.save2csv(os.path.join(grandParentDir,"flightTrajectory_export"), separator=',') +# ft.save2xlsx(os.path.join(grandParentDir,"flightTrajectory_export")) +# ft.save2kml(os.path.join(grandParentDir,"flightTrajectory_export")) diff --git a/examples/example_script.py b/examples/example_script.py deleted file mode 100644 index 928d35d..0000000 --- a/examples/example_script.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Simple Plot -=========== - -This script demonstrates how to create a simple plot using matplotlib. - -""" - -import matplotlib.pyplot as plt -import numpy as np - -# Generate data -x = np.linspace(0, 10, 100) -y = np.sin(x) - -# Create plot -plt.plot(x, y) -plt.title("Sine Wave") -plt.xlabel("x") -plt.ylabel("sin(x)") - -# Display plot -plt.show() diff --git a/examples/file_parser.py b/examples/file_parser.py new file mode 100644 index 0000000..34185a7 --- /dev/null +++ b/examples/file_parser.py @@ -0,0 +1,66 @@ +""" +Example of BADA3, BADA4 and BADAH file parser +""" + +from pyBADA.bada3 import Bada3Aircraft +from pyBADA.bada4 import Bada4Aircraft +from pyBADA.badaH import BadaHAircraft +from pyBADA.bada3 import Parser as Bada3Parser +from pyBADA.bada4 import Parser as Bada4Parser +from pyBADA.badaH import Parser as BadaHParser + + +# initialization of BADA3, BADA4 and BADAH +# uncomment for testing different BADA family if available +# BADAH +badaVersion = "DUMMY" +AC = BadaHAircraft(badaVersion=badaVersion, acName="DUMH") + +# BADA4 +# AC = Bada4Aircraft(badaVersion=badaVersion, acName='Dummy-TBP') + +# BADA3 +# AC = Bada3Aircraft(badaVersion=badaVersion, acName='BZJT') + + +# BADA3 or BADA4 +if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4: + ICAO = AC.ICAO + WTC = AC.WTC + VMO = AC.VMO + MMO = AC.MMO + MTOW = AC.MTOW + print( + "BADA Family:", + AC.BADAFamilyName, + "| BADA Version:", + AC.BADAVersion, + "| ICAO:", + ICAO, + "| WTC:", + WTC, + "| VMO =", + VMO, + "| MMO =", + MMO, + "| MTOW =", + MTOW, + ) + +# BADAH +if AC.BADAFamily.BADAH: + ICAO = AC.ICAO + WTC = AC.WTC + MTOW = AC.MTOW + print( + "BADA Family:", + AC.BADAFamilyName, + "| BADA Version:", + AC.BADAVersion, + "| ICAO:", + ICAO, + " |WTC:", + WTC, + "| MTOW =", + MTOW, + ) diff --git a/examples/heli_trajectory.py b/examples/heli_trajectory.py new file mode 100644 index 0000000..4146ea6 --- /dev/null +++ b/examples/heli_trajectory.py @@ -0,0 +1,306 @@ +""" +Example of BADAH trajectory using TCL +""" + +from math import tan, pi +from dataclasses import dataclass +import matplotlib.pyplot as plt + +from pyBADA import atmosphere as atm +from pyBADA import conversions as conv +from pyBADA import constants as const +from pyBADA import TCL as TCL +from pyBADA.flightTrajectory import FlightTrajectory as FT + +from pyBADA.badaH import Parser as BadaHParser +from pyBADA.badaH import BadaHAircraft + + +@dataclass +class target: + ROCDtarget: float = None + slopetarget: float = None + acctarget: float = None + ESFtarget: float = None + + +# initialization of BADAH +badaVersion = "DUMMY" + +allData = BadaHParser.parseAll(badaVersion=badaVersion) +print(allData) + +AC = BadaHAircraft(badaVersion=badaVersion, acName="DUMH") + +# create a Flight Trajectory object to store the output from TCL segment calculations +ft = FT() + +# take-off with const ROCD +speedType = "TAS" # {M, CAS, TAS} +v = 0 # [kt] CAS/TAS speed to follow or [-] MACH speed to follow +Hp_init = 0 # [ft] +Hp_VTOL = 5 # [ft] upper altitude for vertical take-off and landing +m_init = AC.OEW + 0.7 * (AC.MTOW - AC.OEW) # [kg] initial mass +wS = 0 # [kt] wind speed +bankAngle = 0 # [deg] bank angle +DeltaTemp = 0 # [K] delta temperature from ISA +Hp_step = 500 # [ft] altitude step +step_length = 10 # iteration step length for cruise +RFL = 3000 +maxRFL = 3000 + +AVT = 0.3 * const.g # [g] to [m/s^2] +DVT = -0.3 * const.g # [g] to [m/s^2] + +MEC = AC.OPT.getOPTParam("MEC", var_1=0, var_2=m_init, DeltaTemp=DeltaTemp) +LRC = AC.OPT.getOPTParam("LRC", RFL, m_init, DeltaTemp) + +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp_init, + Hp_final=Hp_VTOL, + ROCDtarget=100, + m_init=m_init, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +Hp, m_final = ft.getFinalValue(AC, ["Hp", "mass"]) +control = target(ROCDtarget=500, acctarget=AVT) + +# acc in climb +flightTrajectory = TCL.accDec( + AC=AC, + speedType=speedType, + v_init=v, + v_final=MEC, + Hp_init=Hp, + phase="Climb", + control=control, + maxRating="MTKF", + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# climb const ROCD +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp, + Hp_final=3000, + ROCDtarget=1000, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# acc in cruise +flightTrajectory = TCL.accDec( + AC=AC, + speedType=speedType, + v_init=v, + v_final=LRC, + Hp_init=Hp, + phase="Cruise", + maxRating="MCNT", + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +DEdist = RFL / tan(3 * pi / 180) * 0.3048 / 1852 # [NM] +length = 14.02 # 30 - 3.57 - DEdist + +# cruise const TAS +flightTrajectory = TCL.constantSpeedLevel( + AC=AC, + lengthType="distance", + length=length, + speedType=speedType, + v=v, + Hp_init=Hp, + m_init=m_final, + maxRFL=maxRFL, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + step_length=step_length, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# descent const ROCD +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp, + Hp_final=500, + ROCDtarget=-500, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) +control = target(ROCDtarget=-300, ESFtarget=0.3) + +# dec in descent const ROCD +flightTrajectory = TCL.accDec( + AC=AC, + speedType=speedType, + v_init=v, + v_final=MEC, + Hp_init=Hp, + phase="Descent", + control=control, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# descent const ROCD +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp, + Hp_final=150, + ROCDtarget=-300, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) +control = target(ROCDtarget=-200, ESFtarget=0.3) + +# dec in descent const ROCD +flightTrajectory = TCL.accDec( + AC=AC, + speedType=speedType, + v_init=v, + v_final=30, + Hp_init=Hp, + phase="Descent", + control=control, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# descent const ROCD +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp, + Hp_final=Hp_VTOL, + ROCDtarget=-200, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) +control = target(acctarget=DVT) + +# dec in descent const ROCD +flightTrajectory = TCL.accDec( + AC=AC, + speedType=speedType, + v_init=v, + v_final=0, + Hp_init=Hp, + phase="Cruise", + control=control, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, +) +ft.append(AC, flightTrajectory) + +Hp, m_final, v = ft.getFinalValue(AC, ["Hp", "mass", "TAS"]) + +# descent const ROCD +flightTrajectory = TCL.constantSpeedROCD( + AC=AC, + speedType=speedType, + v=v, + Hp_init=Hp, + Hp_final=0, + ROCDtarget=-100, + m_init=m_final, + wS=wS, + bankAngle=bankAngle, + DeltaTemp=DeltaTemp, + Hp_step=Hp_step, +) +ft.append(AC, flightTrajectory) + +# print and plot final trajectory +df = ft.getFT(AC=AC) +print(df) + +# Plotting the graph Hp=f(dist) +plt.figure(1, figsize=(8, 6)) +plt.plot(df["dist"], df["Hp"], linestyle="-", color="b") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("Pressure Altitude [ft]") +plt.title("Pressure Altitude as a Function of Distance") + +# Plot for True Airspeed (TAS) +plt.figure(2, figsize=(8, 6)) +plt.plot(df["dist"], df["TAS"], linestyle="-", color="r") +plt.grid(True) +plt.xlabel("Distance [NM]") +plt.ylabel("TAS [kt]") +plt.title("True Airspeed (TAS) as a Function of Distance") + +# Display the plot +plt.show() + +# save the output to a CSV/XLSX file +# ------------------------------------------------ +# ft.save2csv(os.path.join(grandParentDir,"flightTrajectory_export"), separator=',') +# ft.save2xlsx(os.path.join(grandParentDir,"flightTrajectory_export")) diff --git a/examples/optimum_speed_altitude.py b/examples/optimum_speed_altitude.py new file mode 100644 index 0000000..2caa573 --- /dev/null +++ b/examples/optimum_speed_altitude.py @@ -0,0 +1,110 @@ +""" +Example of BADA4 and BADAH optimum speed and altitude calculation +""" + +from pyBADA import atmosphere as atm +from pyBADA import conversions as conv + +from pyBADA.bada4 import Bada4Aircraft +from pyBADA.badaH import BadaHAircraft +from pyBADA.bada4 import Parser as Bada4Parser +from pyBADA.badaH import Parser as BadaHParser + +# initialization of BADA3, BADA4 and BADAH +# uncomment for testing different BADA family if available +badaVersion = "DUMMY" +AC = BadaHAircraft(badaVersion=badaVersion, acName="DUMH") +# AC = Bada4Aircraft(badaVersion=badaVersion, acName='DUMMY-TWIN') + +# BADA4 +if AC.BADAFamily.BADA4: + mass = AC.MTOW # [kg] AC weight + h = conv.ft2m(33000) # [m] AC flight altitdue + DeltaTemp = 0 # [K] temperature deviation from ISA + cI = 50 # [kg min^-1] cost index + wS = 0 # [m s^-1] longitudinal wind speed + + [theta, delta, sigma] = atm.atmosphereProperties( + h=h, DeltaTemp=DeltaTemp + ) # atmosphere properties + + # Economic Mach Cruise Speed + econMach = AC.OPT.econMach( + theta=theta, delta=delta, mass=mass, DeltaTemp=DeltaTemp, cI=cI, wS=wS + ) + print("EconMach = ", econMach) + + CCI = AC.OPT.CCI(theta=theta, delta=delta, cI=cI) + CW = AC.OPT.CW(mass=mass, delta=delta) + econMach_precomputed = AC.OPT.getOPTParam("ECON", CW, CCI) + print("EconMach_precomputed = ", econMach_precomputed) + + # Maximum Range Cruise (MRC) Mach speed + MRC = AC.OPT.MRC( + theta=theta, delta=delta, mass=mass, DeltaTemp=DeltaTemp, wS=wS + ) + print("MRC = ", MRC) + + MRC_precomputed = AC.OPT.getOPTParam("MRC", CW) + print("MRC_precomputed = ", MRC_precomputed) + + # Long Range Cruise (LRC) Mach speed + LRC = AC.OPT.LRC( + theta=theta, delta=delta, mass=mass, DeltaTemp=DeltaTemp, wS=wS + ) + print("LRC = ", LRC) + + LRC_precomputed = AC.OPT.getOPTParam("LRC", CW) + print("LRC_precomputed = ", LRC_precomputed) + + # Maximum Endurance Cruise (MEC) Mach speed + MEC = AC.OPT.MEC( + theta=theta, delta=delta, mass=mass, DeltaTemp=DeltaTemp, wS=wS + ) + print("MEC = ", MEC) + + MEC_precomputed = AC.OPT.getOPTParam("MEC", CW) + print("MEC_precomputed = ", MEC_precomputed) + + # optimum flight altitude at given M speed + M = MRC + optAlt = AC.OPT.optAltitude(M=M, mass=mass, DeltaTemp=DeltaTemp) + print("optAlt =", optAlt) + + optAlt_precomputed = AC.OPT.getOPTParam("OPTALT", M, mass) + print("optAlt_precomputed = ", optAlt_precomputed) + + +# BADAH +if AC.BADAFamily.BADAH: + mass = 1600 # [kg] AC weight + Hp = 14000 # [ft] AC flight altitude + h = conv.ft2m(Hp) # [m] AC flight altitude + DeltaTemp = 20 # [K] temperature deviation from ISA + wS = 0 # [m s^-1] longitudinal wind speed + + [theta, delta, sigma] = atm.atmosphereProperties( + h=h, DeltaTemp=DeltaTemp + ) # atmoshpere properties + + # Maximum Range Cruise (MRC) Mach speed + MRC = AC.OPT.MRC(h=h, mass=mass, DeltaTemp=DeltaTemp, wS=wS) + # print("MRC = ", conv.ms2kt(MRC)) + print("MRC = ", (MRC)) + + MRC_precomputed = AC.OPT.getOPTParam("MRC", Hp, mass, DeltaTemp) + print("MRC_precomputed = ", conv.kt2ms(MRC_precomputed)) + + # Long Range Cruise (LRC) Mach speed + LRC = AC.OPT.LRC(h=h, mass=mass, DeltaTemp=DeltaTemp, wS=wS) + print("LRC = ", (LRC)) + + LRC_precomputed = AC.OPT.getOPTParam("LRC", Hp, mass, DeltaTemp) + print("LRC_precomputed = ", conv.kt2ms(LRC_precomputed)) + + # Maximum Endurance Cruise (MEC) Mach speed + MEC = AC.OPT.MEC(h=h, mass=mass, DeltaTemp=DeltaTemp, wS=wS) + print("MEC = ", (MEC)) + + MEC_precomputed = AC.OPT.getOPTParam("MEC", Hp, mass, DeltaTemp) + print("MEC_precomputed = ", conv.kt2ms(MEC_precomputed))