pyBADA 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. pyBADA/TCL.py +1573 -797
  2. pyBADA/aircraft/BADA4/DUMMY/ACM_BADA4.xsd +3 -1
  3. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.ATF +33 -33
  4. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.xml +3 -1
  5. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTD +30 -30
  6. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTF +14 -14
  7. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTD +30 -30
  8. pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTF +14 -14
  9. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.ATF +143 -143
  10. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.xml +83 -81
  11. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTD +153 -153
  12. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTF +21 -21
  13. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTD +153 -153
  14. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTF +21 -21
  15. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.OPT +36 -0
  16. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.OPT +56 -0
  17. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.OPT +36 -0
  18. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/{OPTALT.dat → OPTALT.OPT} +5 -5
  19. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.ATF +158 -158
  20. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.xml +123 -121
  21. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTD +216 -216
  22. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTF +28 -28
  23. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTD +216 -216
  24. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTF +28 -28
  25. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/ECON.OPT +25 -25
  26. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/LRC.OPT +22 -24
  27. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MEC.OPT +42 -44
  28. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MRC.OPT +22 -24
  29. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/OPTALT.OPT +20 -20
  30. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.ATF +181 -181
  31. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.xml +190 -188
  32. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTD +216 -216
  33. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTF +25 -25
  34. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTD +204 -204
  35. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTF +25 -25
  36. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/ECON.OPT +25 -25
  37. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/LRC.OPT +22 -22
  38. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MEC.OPT +42 -42
  39. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MRC.OPT +22 -22
  40. pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/OPTALT.OPT +20 -20
  41. pyBADA/aircraft.py +180 -145
  42. pyBADA/atmosphere.py +117 -87
  43. pyBADA/bada3.py +1233 -621
  44. pyBADA/bada4.py +1537 -799
  45. pyBADA/badaH.py +1103 -508
  46. pyBADA/configuration.py +82 -24
  47. pyBADA/constants.py +0 -9
  48. pyBADA/conversions.py +0 -10
  49. pyBADA/flightTrajectory.py +154 -151
  50. pyBADA/geodesic.py +278 -179
  51. pyBADA/magnetic.py +54 -16
  52. pyBADA/trajectoryPrediction.py +27 -26
  53. {pybada-0.1.0.dist-info → pybada-0.1.1.dist-info}/METADATA +22 -7
  54. {pybada-0.1.0.dist-info → pybada-0.1.1.dist-info}/RECORD +57 -59
  55. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.dat +0 -38
  56. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.dat +0 -58
  57. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.dat +0 -38
  58. pyBADA/aircraft/BADA4/DUMMY/aircraft_model_default.xml +0 -311
  59. pyBADA/badaE.py +0 -3317
  60. {pybada-0.1.0.dist-info → pybada-0.1.1.dist-info}/WHEEL +0 -0
  61. {pybada-0.1.0.dist-info → pybada-0.1.1.dist-info}/licenses/AUTHORS +0 -0
  62. {pybada-0.1.0.dist-info → pybada-0.1.1.dist-info}/licenses/LICENCE.txt +0 -0
pyBADA/TCL.py CHANGED
@@ -6,15 +6,6 @@ Developped @EUROCONTROL (EIH)
6
6
  2024
7
7
  """
8
8
 
9
- __author__ = "Henrich Glaser-Opitz"
10
- __copyright__ = "Copyright 2024, EUROCONTROL (EIH)"
11
- __license__ = "BADA Eurocontrol"
12
- __version__ = "1.0.0"
13
- __maintainer__ = "Henrich Glaser-Opitz"
14
- __email__ = "henrich.glaser-opitz@eurocontrol.int"
15
- __status__ = "Development"
16
- __docformat__ = "reStructuredText"
17
-
18
9
  import os
19
10
  import numpy as np
20
11
  from pyBADA.geodesic import Vincenty as vincenty
@@ -69,64 +60,97 @@ def constantSpeedLevel(
69
60
  magneticDeclinationGrid=None,
70
61
  **kwargs,
71
62
  ):
72
- """This function computes time and fuel required by an aircraft to fly given distance at constant speed in level flight
73
-
74
- :param AC: aircraft {BADA3/4/H/E}
75
- :param lengthType: what kind of length applies {distance, time}.
76
- :param length: length of a segment to fly - [NM] distance to fly or [s] time to fly
77
- :param step_length: length of a step of a segment - [NM] distance to fly or [s] time to fly
78
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
79
- :param v: what speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
80
- :param Hp_init: initial pressure altitude [ft].
81
- :param m_init: initial aircraft mass [kg].
82
- :param stepClimb: kind of vertical evolution during cruise {constAlt=False, stepClimb=True}.
83
- :param HpStep: altitude step for the stepClimb.
84
- :param DeltaTemp: deviation with respect to ISA [K].
85
- :param maxRFL: maximum cruise altitude [ft].
86
- :param wS: longitudinal wind speed (TAS) [kt].
87
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
88
- :param SOC_init: initial state of charge [%].
89
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
90
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
91
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
92
- :param Lat: Geographical Latitude [deg]
93
- :param Lon: Geographical Longitude [deg]
94
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
95
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
96
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
97
- :param m_iter: number of iterations for integration loop [-]
98
- :param flightPhase: aircraft phase of flight {Climb,Cruise,Descent}
99
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
100
- :type lengthType: string.
101
- :type length: float.
102
- :type step_length: float.
103
- :type speedType: string.
104
- :type v: float.
105
- :type Hp_init: float.
106
- :type m_init: float.
107
- :type stepClimb: boolean.
108
- :type HpStep: float.
109
- :type DeltaTemp: float.
110
- :type maxRFL: float.
111
- :type wS: float.
112
- :type turnMetrics: {float,float,string}.
113
- :type SOC_init: float.
114
- :type config: string.
115
- :type speedBrakes: dict{boolean,float}.
116
- :type ROCD_min: float.
117
- :type Lat: float.
118
- :type Lon: float.
119
- :type initialHeading: {float,float,boolean}.
120
- :type magneticDeclinationGrid: magneticDeclinationGrid.
121
- :type mass_const: boolean.
122
- :type m_iter: integer.
123
- :type flightPhase: string.
124
- :returns:
125
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
126
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
127
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
128
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
129
- :rtype: dict[list[float]}.
63
+ """
64
+ Calculates the time, fuel consumption, and other parameters for a level flight
65
+ segment at a constant speed for a given aircraft in the BADA model. It supports step-climb,
66
+ constant heading (true or magnetic), and turns.
67
+
68
+ The function handles different BADA families (BADA3, BADA4, BADAH, BADAE), and computes various
69
+ parameters such as altitude, speed, fuel consumption, power, heading, and mass based on aircraft
70
+ performance data.
71
+
72
+ :param AC: Aircraft object {BADA3/4/H/E}
73
+ :param lengthType: Specifies if the length of the flight segment is based on 'distance' [NM] or 'time' [s].
74
+ :param length: The length of the flight segment. Distance [NM] or Time [s] depending on lengthType.
75
+ :param speedType: Specifies the type of speed to follow {M, CAS, TAS}.
76
+ :param v: The target speed in [kt] for CAS/TAS or [-] for MACH.
77
+ :param Hp_init: Initial pressure altitude at the start of the flight segment [ft].
78
+ :param m_init: Initial mass of the aircraft [kg].
79
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
80
+ :param maxRFL: Maximum cruise altitude limit [ft]. Default is infinity.
81
+ :param wS: Wind speed component along the longitudinal axis (positive for headwind, negative for tailwind) [kt]. Default is 0.0.
82
+ :param turnMetrics: Dictionary containing turn parameters:
83
+ - rateOfTurn [deg/s]
84
+ - bankAngle [deg]
85
+ - directionOfTurn {LEFT/RIGHT}. Default is no turn (straight flight).
86
+ :param stepClimb: Boolean to enable or disable step climb during the cruise segment. Default is False.
87
+ :param Lat: Geographical latitude of the starting point [deg].
88
+ :param Lon: Geographical longitude of the starting point [deg].
89
+ :param initialHeading: Dictionary defining the initial heading and its type:
90
+ - magnetic: Magnetic heading [deg].
91
+ - true: True heading [deg].
92
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
93
+ :param flightPhase: Defines the phase of flight, e.g., "Cruise", "Climb", "Descent". Default is "Cruise".
94
+ :param magneticDeclinationGrid: Optional magnetic declination grid to correct headings. Default is None.
95
+ :param kwargs: Additional optional parameters:
96
+ - mass_const: Boolean. If True, keeps the aircraft mass constant during the segment. Default is False.
97
+ - SOC_init: Initial battery state of charge for electric aircraft [%]. Default is 100 for BADAE.
98
+ - speedBrakes: Dictionary defining whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
99
+ - ROCD_min: Minimum rate of climb/descent threshold to identify service ceiling [ft/min]. Default varies by aircraft type.
100
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD.
101
+ - HpStep: Altitude step for step climb [ft]. Default is 2000 ft.
102
+ - m_iter: Number of iterations for mass integration. Default is 1 for BADAE, 2 for others.
103
+ - step_length: The step length for each iteration in [NM] or [s], depending on the lengthType. Default is 100 NM for BADA3/4 and 10 NM for BADAH/BADAE.
104
+
105
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
106
+ - Hp: Altitude [ft]
107
+ - TAS: True Air Speed [kt]
108
+ - CAS: Calibrated Air Speed [kt]
109
+ - GS: Ground Speed [kt]
110
+ - M: Mach number [-]
111
+ - ROCD: Rate of Climb/Descent [ft/min]
112
+ - ESF: Energy Share Factor[-]
113
+ - FUEL: Fuel flow [kg/s]
114
+ - FUELCONSUMED: Total fuel consumed [kg]
115
+ - THR: Thrust force [N]
116
+ - DRAG: Drag force [N]
117
+ - time: Elapsed time [s]
118
+ - dist: Distance flown [NM]
119
+ - slope: Trajectory slope [deg]
120
+ - mass: Aircraft mass [kg]
121
+ - config: Aerodynamic configuration
122
+ - LAT: Latitude [deg]
123
+ - LON: Longitude [deg]
124
+ - HDGTrue: True heading [deg]
125
+ - HDGMagnetic: Magnetic heading [deg]
126
+ - BankAngle: Bank angle [deg]
127
+ - ROT: Rate of turn [deg/s]
128
+ - For BADAH:
129
+ - Preq: Required power [W]
130
+ - Peng: Generated power [W]
131
+ - Pav: Available power [W]
132
+ - For BADAE (electric aircraft):
133
+ - Pmec: Mechanical power [W]
134
+ - Pelc: Electrical power [W]
135
+ - Pbat: Power supplied by the battery [W]
136
+ - SOCr: Rate of battery state of charge depletion [%/h]
137
+ - SOC: Battery state of charge [%]
138
+ - Ibat: Battery current [A]
139
+ - Vbat: Battery voltage [V]
140
+ - Vgbat: Ground battery voltage [V]
141
+ - Comment: Comments for each segment
142
+ :rtype: pandas.DataFrame
143
+
144
+ This function works by iteratively calculating the flight trajectory for a given segment of the flight,
145
+ taking into account the specified flight conditions, and updating the aircraft’s state (altitude, speed, fuel, etc.)
146
+ at each step of the iteration. The trajectory is returned as a DataFrame containing all relevant flight parameters.
147
+
148
+ Key considerations:
149
+ - Magnetic declination can be corrected based on the provided grid.
150
+ - Supports handling turns and constant heading navigation.
151
+ - Step climbs are optionally allowed if enabled.
152
+ - Takes into account wind speed and flight phase-specific configurations.
153
+ - Power and fuel consumption are calculated differently for each BADA family (BADAH and BADAE handle power instead of fuel in different ways).
130
154
  """
131
155
 
132
156
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -177,7 +201,9 @@ def constantSpeedLevel(
177
201
 
178
202
  # speed brakes application
179
203
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
180
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
204
+ speedBrakes = kwargs.get(
205
+ "speedBrakes", {"deployed": False, "value": 0.03}
206
+ )
181
207
 
182
208
  # optional parameter - iteration step length based on the type of aircraft
183
209
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -191,9 +217,13 @@ def constantSpeedLevel(
191
217
 
192
218
  # weight iteration constant
193
219
  if AC.BADAFamily.BADAE:
194
- m_iter = kwargs.get("m_iter", 1) # number of iterations for integration loop[-]
220
+ m_iter = kwargs.get(
221
+ "m_iter", 1
222
+ ) # number of iterations for integration loop[-]
195
223
  else:
196
- m_iter = kwargs.get("m_iter", 2) # number of iterations for integration loop[-]
224
+ m_iter = kwargs.get(
225
+ "m_iter", 2
226
+ ) # number of iterations for integration loop[-]
197
227
 
198
228
  # comment line describing type of trajectory calculation
199
229
  if flightPhase != "Cruise":
@@ -317,7 +347,9 @@ def constantSpeedLevel(
317
347
 
318
348
  # atmosphere properties
319
349
  H_m = conv.ft2m(Hp_i) # altitude [m]
320
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
350
+ [theta, delta, sigma] = atm.atmosphereProperties(
351
+ h=H_m, DeltaTemp=DeltaTemp
352
+ )
321
353
  # aircraft speed
322
354
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
323
355
  v=v, speedType=speedType, theta=theta, delta=delta, sigma=sigma
@@ -327,10 +359,14 @@ def constantSpeedLevel(
327
359
  if turnFlight:
328
360
  if turnMetrics["bankAngle"] != 0.0:
329
361
  # bankAngle is defined
330
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
362
+ rateOfTurn = AC.rateOfTurn_bankAngle(
363
+ TAS=TAS_i, bankAngle=bankAngle
364
+ )
331
365
  else:
332
366
  # rateOfTurn is defined
333
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
367
+ bankAngle = AC.bankAngle(
368
+ rateOfTurn=rateOfTurn, v=TAS_i
369
+ ) # [degrees]
334
370
 
335
371
  if lengthType == "distance":
336
372
  # step time is: distance differantial divided by ground speed
@@ -359,7 +395,9 @@ def constantSpeedLevel(
359
395
  # BADAH or BADAE
360
396
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
361
397
  # compute Power required for level flight
362
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
398
+ Preq_i = AC.Preq(
399
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
400
+ )
363
401
  Peng_i = Preq_i
364
402
  if AC.BADAFamily.BADAH:
365
403
  Pav_i = AC.Pav(
@@ -372,7 +410,8 @@ def constantSpeedLevel(
372
410
 
373
411
  if Pav_i < Preq_i:
374
412
  warnings.warn(
375
- "Power Available is lower than Power Required", UserWarning
413
+ "Power Available is lower than Power Required",
414
+ UserWarning,
376
415
  )
377
416
 
378
417
  # BADAH
@@ -390,7 +429,9 @@ def constantSpeedLevel(
390
429
  Pelc_i = Preq_i / AC.eta
391
430
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC_i)
392
431
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC_i)
393
- Vgbat_i = AC.Vocbat(SOC=SOC_i) - AC.R0bat(SOC=SOC_i) * Ibat_i
432
+ Vgbat_i = (
433
+ AC.Vocbat(SOC=SOC_i) - AC.R0bat(SOC=SOC_i) * Ibat_i
434
+ )
394
435
 
395
436
  # BADA4
396
437
  elif AC.BADAFamily.BADA4:
@@ -414,12 +455,16 @@ def constantSpeedLevel(
414
455
  currentConfig=config_i,
415
456
  )
416
457
 
417
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
458
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
459
+ config=config_i
460
+ )
418
461
 
419
462
  # compute lift coefficient
420
463
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
421
464
  # compute drag coefficient
422
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
465
+ CD = AC.CD(
466
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
467
+ )
423
468
  # compute drag force
424
469
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
425
470
  # compute thrust force and fuel flow
@@ -702,7 +747,9 @@ def constantSpeedLevel(
702
747
  # determine atmosphere properties at upper cruise altitude
703
748
  nextHp = min(Hp_i + HpStep, maxRFL)
704
749
  H_m = conv.ft2m(nextHp) # altitude [m]
705
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
750
+ [theta, delta, sigma] = atm.atmosphereProperties(
751
+ h=H_m, DeltaTemp=DeltaTemp
752
+ )
706
753
 
707
754
  # aircraft speed at upper cruise altitude
708
755
  [M_up, CAS_up, TAS_up] = atm.convertSpeed(
@@ -771,19 +818,31 @@ def constantSpeedLevel(
771
818
  currentConfig=config_i,
772
819
  )
773
820
 
774
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
821
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
822
+ config=config_i
823
+ )
775
824
 
776
825
  # compute lift coefficient
777
826
  CL = AC.CL(M=M_up, delta=delta, mass=mass_i, nz=nz)
778
827
  # compute drag coefficient
779
- CD = AC.CD(M=M_up, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
828
+ CD = AC.CD(
829
+ M=M_up,
830
+ CL=CL,
831
+ HLid=HLid_i,
832
+ LG=LG_i,
833
+ speedBrakes=speedBrakes,
834
+ )
780
835
  # compute drag force
781
836
  Drag = AC.D(M=M_up, delta=delta, CD=CD)
782
837
  # compute thrust force and fuel flow
783
838
  THR_up = Drag
784
839
  CT = AC.CT(Thrust=THR_up, delta=delta)
785
840
  FUEL_up = AC.ff(
786
- CT=CT, delta=delta, theta=theta, M=M_up, DeltaTemp=DeltaTemp
841
+ CT=CT,
842
+ delta=delta,
843
+ theta=theta,
844
+ M=M_up,
845
+ DeltaTemp=DeltaTemp,
787
846
  ) # [kg/s]
788
847
 
789
848
  # Compare specific range at current and upper cruise altitudes
@@ -808,7 +867,10 @@ def constantSpeedLevel(
808
867
 
809
868
  flightEvolution = "const" + speedType
810
869
  ESF_i = AC.esf(
811
- h=H_m, flightEvolution=flightEvolution, M=M_up, DeltaTemp=DeltaTemp
870
+ h=H_m,
871
+ flightEvolution=flightEvolution,
872
+ M=M_up,
873
+ DeltaTemp=DeltaTemp,
812
874
  )
813
875
  temp_const = (theta * const.temp_0) / (
814
876
  theta * const.temp_0 - DeltaTemp
@@ -894,7 +956,9 @@ def constantSpeedLevel(
894
956
  ROT.extend(flightTrajectory_CL["ROT"])
895
957
 
896
958
  comment_CL = flightTrajectory_CL["comment"]
897
- Comment.extend([com + "_stepClimb" for com in comment_CL])
959
+ Comment.extend(
960
+ [com + "_stepClimb" for com in comment_CL]
961
+ )
898
962
 
899
963
  # BADA4
900
964
  if AC.BADAFamily.BADA4:
@@ -916,7 +980,9 @@ def constantSpeedLevel(
916
980
  if Lat and Lon and magneticHeading:
917
981
  LAT.extend(flightTrajectory_CL["LAT"])
918
982
  LON.extend(flightTrajectory_CL["LON"])
919
- HDGMagnetic.extend(flightTrajectory_CL["HDGMagnetic"])
983
+ HDGMagnetic.extend(
984
+ flightTrajectory_CL["HDGMagnetic"]
985
+ )
920
986
  HDGTrue.extend(flightTrajectory_CL["HDGTrue"])
921
987
 
922
988
  # Compute cruise fuel at upper altitude
@@ -936,18 +1002,20 @@ def constantSpeedLevel(
936
1002
 
937
1003
  # ensure continuity of configuration change within the segment
938
1004
  if config:
939
- config_i = (
940
- AC.flightEnvelope.checkConfigurationContinuity(
941
- phase=flightPhase,
942
- previousConfig=config[-1],
943
- currentConfig=config_i,
944
- )
1005
+ config_i = AC.flightEnvelope.checkConfigurationContinuity(
1006
+ phase=flightPhase,
1007
+ previousConfig=config[-1],
1008
+ currentConfig=config_i,
945
1009
  )
946
1010
 
947
1011
  # compute lift coefficient
948
- CL = AC.CL(tas=TAS_up, sigma=sigma, mass=mass[-1], nz=nz)
1012
+ CL = AC.CL(
1013
+ tas=TAS_up, sigma=sigma, mass=mass[-1], nz=nz
1014
+ )
949
1015
  # compute drag coefficient
950
- CD = AC.CD(CL=CL, config=config_i, speedBrakes=speedBrakes)
1016
+ CD = AC.CD(
1017
+ CL=CL, config=config_i, speedBrakes=speedBrakes
1018
+ )
951
1019
  # compute drag force
952
1020
  Drag = AC.D(tas=TAS_up, sigma=sigma, CD=CD)
953
1021
  # compute thrust force and fuel flow
@@ -977,12 +1045,10 @@ def constantSpeedLevel(
977
1045
 
978
1046
  # ensure continuity of configuration change within the segment
979
1047
  if config:
980
- config_i = (
981
- AC.flightEnvelope.checkConfigurationContinuity(
982
- phase=flightPhase,
983
- previousConfig=config[-1],
984
- currentConfig=config_i,
985
- )
1048
+ config_i = AC.flightEnvelope.checkConfigurationContinuity(
1049
+ phase=flightPhase,
1050
+ previousConfig=config[-1],
1051
+ currentConfig=config_i,
986
1052
  )
987
1053
 
988
1054
  [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
@@ -990,7 +1056,9 @@ def constantSpeedLevel(
990
1056
  )
991
1057
 
992
1058
  # compute lift coefficient
993
- CL = AC.CL(M=M_up, delta=delta, mass=mass[-1], nz=nz)
1059
+ CL = AC.CL(
1060
+ M=M_up, delta=delta, mass=mass[-1], nz=nz
1061
+ )
994
1062
  # compute drag coefficient
995
1063
  CD = AC.CD(
996
1064
  M=M_up,
@@ -1121,58 +1189,89 @@ def constantSpeedROCD(
1121
1189
  magneticDeclinationGrid=None,
1122
1190
  **kwargs,
1123
1191
  ):
1124
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init to Hp_final at constant speed and constant rate of climb/descent
1125
-
1126
- :param AC: aircraft {BADA3/4/H/E}
1127
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
1128
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
1129
- :param Hp_init: initial pressure altitude [ft].
1130
- :param Hp_final: final pressure altitude [ft].
1131
- :param ROCDtarget: Rate of climb/descent to be followed [ft/min].
1132
- :param m_init: initial aircraft mass [kg].
1133
- :param DeltaTemp: deviation with respect to ISA [K].
1134
- :param wS: longitudinal wind speed (TAS) [kt].
1135
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
1136
- :param Hp_step: length of an altitude step of a segment [ft].
1137
- :param SOC_init: initial state of charge [%].
1138
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
1139
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
1140
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
1141
- :param Lat: Geographical Latitude [deg]
1142
- :param Lon: Geographical Longitude [deg]
1143
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
1144
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
1145
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
1146
- :param m_iter: number of iterations for integration loop [-]
1147
- :param reducedPower: reduction of Power during the climb {True/False}
1148
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
1149
- :type speedType: string.
1150
- :type v: float.
1151
- :type Hp_init: float.
1152
- :type Hp_final: float.
1153
- :type ROCDtarget: float.
1154
- :type m_init: float.
1155
- :type DeltaTemp: float.
1156
- :type wS: float.
1157
- :type turnMetrics: {float,float,string}.
1158
- :type Hp_step: float.
1159
- :type SOC_init: float.
1160
- :type config: string.
1161
- :type speedBrakes: dict{boolean,float}.
1162
- :type ROCD_min: float.
1163
- :type Lat: float.
1164
- :type Lon: float.
1165
- :type initialHeading: {float,float,boolean}.
1166
- :type magneticDeclinationGrid: magneticDeclinationGrid.
1167
- :type mass_const: boolean.
1168
- :type m_iter: integer.
1169
- :type reducedPower: boolean.
1170
- :returns:
1171
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
1172
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
1173
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
1174
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
1175
- :rtype: dict[list[float]}.
1192
+ """
1193
+ Computes the time, fuel consumption, and other parameters required for an aircraft to climb or descend
1194
+ from a given initial altitude (Hp_init) to a final altitude (Hp_final) at a constant speed and rate of climb/descent (ROCD).
1195
+
1196
+ The function handles multiple BADA families (BADA3, BADA4, BADAH, BADAE), computing various parameters
1197
+ such as altitude, speed, fuel consumption, power, heading, and mass based on the aircraft's performance
1198
+ characteristics. The function supports turn performance, optional heading (true or magnetic), and
1199
+ handling mass changes during the flight.
1200
+
1201
+ :param AC: Aircraft object {BADA3/4/H/E}
1202
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
1203
+ :param v: Speed to maintain during the flight - [kt] CAS/TAS or [-] MACH.
1204
+ :param Hp_init: Initial pressure altitude at the start of the segment [ft].
1205
+ :param Hp_final: Final pressure altitude at the end of the segment [ft].
1206
+ :param ROCDtarget: Target rate of climb/descent [ft/min].
1207
+ :param m_init: Initial aircraft mass at the start of the segment [kg].
1208
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
1209
+ :param wS: Wind speed component along the longitudinal axis [kt]. Positive values for headwind, negative for tailwind. Default is 0.0.
1210
+ :param turnMetrics: Dictionary defining turn parameters:
1211
+ - rateOfTurn [deg/s]
1212
+ - bankAngle [deg]
1213
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
1214
+ :param Lat: Geographical latitude of the starting point [deg]. Default is None.
1215
+ :param Lon: Geographical longitude of the starting point [deg]. Default is None.
1216
+ :param initialHeading: Dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
1217
+ - magnetic: Magnetic heading [deg].
1218
+ - true: True heading [deg].
1219
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
1220
+ :param reducedPower: Boolean specifying whether to apply reduced power during the climb. Default is None.
1221
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
1222
+ :param magneticDeclinationGrid: Optional grid of magnetic declinations used to correct headings. Default is None.
1223
+ :param kwargs: Additional optional parameters:
1224
+ - Hp_step: Altitude step size [ft]. Default is 1000 for BADA3/4, 500 for BADAH/BADAE.
1225
+ - SOC_init: Initial state of charge for electric aircraft [%]. Default is 100 for BADAE.
1226
+ - speedBrakes: Dictionary specifying whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
1227
+ - ROCD_min: Minimum ROCD to identify the service ceiling [ft/min]. Default varies by aircraft type.
1228
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD. Default is None.
1229
+ - mass_const: Boolean specifying whether to keep the mass constant during the segment. Default is False.
1230
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
1231
+
1232
+ :returns: A pandas DataFrame containing the flight trajectory, including parameters like:
1233
+ - Hp: Altitude [ft]
1234
+ - TAS: True Air Speed [kt]
1235
+ - CAS: Calibrated Air Speed [kt]
1236
+ - GS: Ground Speed [kt]
1237
+ - M: Mach number [-]
1238
+ - ROCD: Rate of Climb/Descent [ft/min]
1239
+ - ESF: Energy Share Factor [-]
1240
+ - FUEL: Fuel flow [kg/s]
1241
+ - FUELCONSUMED: Total fuel consumed [kg]
1242
+ - THR: Thrust force [N]
1243
+ - DRAG: Drag force [N]
1244
+ - time: Elapsed time [s]
1245
+ - dist: Distance flown [NM]
1246
+ - slope: Trajectory slope [deg]
1247
+ - mass: Aircraft mass [kg]
1248
+ - config: Aerodynamic configuration
1249
+ - LAT: Latitude [deg]
1250
+ - LON: Longitude [deg]
1251
+ - HDGTrue: True heading [deg]
1252
+ - HDGMagnetic: Magnetic heading [deg]
1253
+ - BankAngle: Bank angle [deg]
1254
+ - ROT: Rate of turn [deg/s]
1255
+ - For BADAH:
1256
+ - Preq: Required power [W]
1257
+ - Peng: Generated power [W]
1258
+ - Pav: Available power [W]
1259
+ - For BADAE (electric aircraft):
1260
+ - Pmec: Mechanical power [W]
1261
+ - Pelc: Electrical power [W]
1262
+ - Pbat: Power supplied by the battery [W]
1263
+ - SOCr: Rate of battery state of charge depletion [%/h]
1264
+ - SOC: Battery state of charge [%]
1265
+ - Ibat: Battery current [A]
1266
+ - Vbat: Battery voltage [V]
1267
+ - Vgbat: Ground battery voltage [V]
1268
+ - Comment: Comments for each segment
1269
+ :rtype: pandas.DataFrame
1270
+
1271
+ Notes:
1272
+ - The function iteratively calculates flight parameters for each altitude step, adjusting fuel, power, and mass.
1273
+ - Magnetic heading and true heading can be adjusted using the magnetic declination grid if provided.
1274
+ - The function supports turns, and constant or changing headings based on input parameters.
1176
1275
  """
1177
1276
 
1178
1277
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -1223,7 +1322,9 @@ def constantSpeedROCD(
1223
1322
 
1224
1323
  # speed brakes application
1225
1324
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
1226
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
1325
+ speedBrakes = kwargs.get(
1326
+ "speedBrakes", {"deployed": False, "value": 0.03}
1327
+ )
1227
1328
 
1228
1329
  # optional parameter - iteration step for altitude loop
1229
1330
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -1271,7 +1372,9 @@ def constantSpeedROCD(
1271
1372
  constHeadingStr = ""
1272
1373
 
1273
1374
  # comment line describing type of trajectory calculation
1274
- comment = phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
1375
+ comment = (
1376
+ phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
1377
+ )
1275
1378
 
1276
1379
  if Lat and Lon and (magneticHeading or trueHeading):
1277
1380
  comment = comment + "_" + headingToFly + "_Heading"
@@ -1292,7 +1395,9 @@ def constantSpeedROCD(
1292
1395
  )
1293
1396
 
1294
1397
  # weight iteration constant
1295
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
1398
+ m_iter = kwargs.get(
1399
+ "m_iter", 5
1400
+ ) # number of iterations for integration loop[-]
1296
1401
 
1297
1402
  # convert ROCD to IS units
1298
1403
  ROCDisu = conv.ft2m(ROCDtarget) / 60
@@ -1361,8 +1466,12 @@ def constantSpeedROCD(
1361
1466
 
1362
1467
  # atmosphere properties
1363
1468
  H_m = conv.ft2m(Hp_i) # altitude [m]
1364
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
1365
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
1469
+ [theta, delta, sigma] = atm.atmosphereProperties(
1470
+ h=H_m, DeltaTemp=DeltaTemp
1471
+ )
1472
+ temp_const = (theta * const.temp_0) / (
1473
+ theta * const.temp_0 - DeltaTemp
1474
+ )
1366
1475
 
1367
1476
  # aircraft speed
1368
1477
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -1371,16 +1480,23 @@ def constantSpeedROCD(
1371
1480
 
1372
1481
  # compute Energy Share Factor (ESF)
1373
1482
  ESF_i = AC.esf(
1374
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
1483
+ h=H_m,
1484
+ M=M_i,
1485
+ DeltaTemp=DeltaTemp,
1486
+ flightEvolution=("const" + speedType),
1375
1487
  )
1376
1488
 
1377
1489
  if turnFlight:
1378
1490
  if turnMetrics["bankAngle"] != 0.0:
1379
1491
  # bankAngle is defined
1380
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
1492
+ rateOfTurn = AC.rateOfTurn_bankAngle(
1493
+ TAS=TAS_i, bankAngle=bankAngle
1494
+ )
1381
1495
  else:
1382
1496
  # rateOfTurn is defined
1383
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
1497
+ bankAngle = AC.bankAngle(
1498
+ rateOfTurn=rateOfTurn, v=TAS_i
1499
+ ) # [degrees]
1384
1500
 
1385
1501
  # Load factor
1386
1502
  nz = 1 / cos(radians(bankAngle))
@@ -1394,7 +1510,9 @@ def constantSpeedROCD(
1394
1510
  # BADAH or BADAE
1395
1511
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
1396
1512
  # compute Power required for level flight
1397
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
1513
+ Preq_i = AC.Preq(
1514
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
1515
+ )
1398
1516
  # Compute power required for target ROCD
1399
1517
  Preq_target_i = AC.Peng_target(
1400
1518
  temp=theta * const.temp_0,
@@ -1422,20 +1540,27 @@ def constantSpeedROCD(
1422
1540
  # ensure continuity of configuration change within the segment
1423
1541
  if config:
1424
1542
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
1425
- phase=phase, previousConfig=config[-1], currentConfig=config_i
1543
+ phase=phase,
1544
+ previousConfig=config[-1],
1545
+ currentConfig=config_i,
1426
1546
  )
1427
1547
 
1428
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
1548
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
1549
+ config=config_i
1550
+ )
1429
1551
 
1430
1552
  # compute lift coefficient
1431
1553
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
1432
1554
  # compute drag coefficient
1433
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
1555
+ CD = AC.CD(
1556
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
1557
+ )
1434
1558
  # compute drag force
1435
1559
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
1436
1560
  # compute thrust force
1437
1561
  THR_i = (
1438
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
1562
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
1563
+ + Drag
1439
1564
  ) # [N]
1440
1565
 
1441
1566
  # BADA3
@@ -1468,7 +1593,8 @@ def constantSpeedROCD(
1468
1593
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
1469
1594
  # compute thrust force
1470
1595
  THR_i = (
1471
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
1596
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
1597
+ + Drag
1472
1598
  ) # [N]
1473
1599
 
1474
1600
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -1567,21 +1693,39 @@ def constantSpeedROCD(
1567
1693
  Pelc_i = Preq_target_i / AC.eta
1568
1694
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
1569
1695
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
1570
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
1696
+ Vgbat_i = (
1697
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
1698
+ )
1571
1699
 
1572
1700
  # BADA4
1573
1701
  elif AC.BADAFamily.BADA4:
1574
1702
  THR_min = AC.Thrust(
1575
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1703
+ rating="LIDL",
1704
+ delta=delta,
1705
+ theta=theta,
1706
+ M=M_i,
1707
+ DeltaTemp=DeltaTemp,
1576
1708
  ) # IDLE Thrust
1577
1709
  FUEL_min = AC.ff(
1578
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1710
+ rating="LIDL",
1711
+ delta=delta,
1712
+ theta=theta,
1713
+ M=M_i,
1714
+ DeltaTemp=DeltaTemp,
1579
1715
  ) # IDLE Fuel Flow
1580
1716
  THR_max = AC.Thrust(
1581
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1717
+ rating="MCMB",
1718
+ delta=delta,
1719
+ theta=theta,
1720
+ M=M_i,
1721
+ DeltaTemp=DeltaTemp,
1582
1722
  ) # MCMB Thrust
1583
1723
  FUEL_max = AC.ff(
1584
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1724
+ rating="MCMB",
1725
+ delta=delta,
1726
+ theta=theta,
1727
+ M=M_i,
1728
+ DeltaTemp=DeltaTemp,
1585
1729
  ) # MCMB Fuel Flow
1586
1730
  if THR_i < THR_min:
1587
1731
  THR_i = THR_min
@@ -1612,14 +1756,22 @@ def constantSpeedROCD(
1612
1756
  else:
1613
1757
  CT = AC.CT(Thrust=THR_i, delta=delta)
1614
1758
  FUEL_i = AC.ff(
1615
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1759
+ CT=CT,
1760
+ delta=delta,
1761
+ theta=theta,
1762
+ M=M_i,
1763
+ DeltaTemp=DeltaTemp,
1616
1764
  ) # [kg/s]
1617
1765
  ROCD_i = ROCDtarget
1618
1766
 
1619
1767
  # BADA3
1620
1768
  elif AC.BADAFamily.BADA3:
1621
1769
  THR_min = AC.Thrust(
1622
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
1770
+ rating="LIDL",
1771
+ v=TAS_i,
1772
+ h=H_m,
1773
+ config="CR",
1774
+ DeltaTemp=DeltaTemp,
1623
1775
  ) # IDLE Thrust
1624
1776
  FUEL_min = AC.ff(
1625
1777
  flightPhase="Descent",
@@ -1630,7 +1782,11 @@ def constantSpeedROCD(
1630
1782
  adapted=False,
1631
1783
  ) # IDLE Fuel Flow
1632
1784
  THR_max = AC.Thrust(
1633
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
1785
+ rating="MCMB",
1786
+ v=TAS_i,
1787
+ h=H_m,
1788
+ DeltaTemp=DeltaTemp,
1789
+ config="CR",
1634
1790
  ) # MCMB Thrust
1635
1791
  FUEL_max = AC.ff(
1636
1792
  flightPhase="Climb",
@@ -1779,10 +1935,14 @@ def constantSpeedROCD(
1779
1935
  gamma_i = 90 * np.sign(ROCD_i)
1780
1936
  else:
1781
1937
  if AC.BADAFamily.BADAE:
1782
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
1938
+ gamma_i = degrees(
1939
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
1940
+ )
1783
1941
  else:
1784
1942
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
1785
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
1943
+ gamma_i = degrees(
1944
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
1945
+ )
1786
1946
 
1787
1947
  Slope.append(gamma_i)
1788
1948
 
@@ -1815,7 +1975,9 @@ def constantSpeedROCD(
1815
1975
  if turnFlight:
1816
1976
  step_distance = conv.m2nm(
1817
1977
  turn.distance(
1818
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
1978
+ rateOfTurn=rateOfTurn,
1979
+ TAS=TAS_i,
1980
+ timeOfTurn=step_time,
1819
1981
  )
1820
1982
  ) # arcLength during the turn [NM]
1821
1983
  else:
@@ -2035,58 +2197,84 @@ def constantSpeedROCD_time(
2035
2197
  magneticDeclinationGrid=None,
2036
2198
  **kwargs,
2037
2199
  ):
2038
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init for set amount of time at constant speed and constant rate of climb/descent
2039
-
2040
- :param AC: aircraft {BADA3/4/H/E}
2041
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
2042
- :param length: length of a segment to fly [s]
2043
- :param step_length: length of a step of a segment - [s]
2044
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
2045
- :param Hp_init: initial pressure altitude [ft].
2046
- :param ROCDtarget: Rate of climb/descent to be followed [ft/min].
2047
- :param m_init: initial aircraft mass [kg].
2048
- :param DeltaTemp: deviation with respect to ISA [K].
2049
- :param wS: longitudinal wind speed (TAS) [kt].
2050
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
2051
- :param SOC_init: initial state of charge [%].
2052
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
2053
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
2054
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
2055
- :param Lat: Geographical Latitude [deg]
2056
- :param Lon: Geographical Longitude [deg]
2057
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
2058
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
2059
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
2060
- :param m_iter: number of iterations for integration loop [-]
2061
- :param reducedPower: reduction of Power during the climb {True/False}
2062
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
2063
- :type speedType: string.
2064
- :type length: float.
2065
- :type step_length: float.
2066
- :type v: float.
2067
- :type Hp_init: float.
2068
- :type ROCDtarget: float.
2069
- :type m_init: float.
2070
- :type DeltaTemp: float.
2071
- :type wS: float.
2072
- :type turnMetrics: {float,float,string}.
2073
- :type SOC_init: float.
2074
- :type config: string.
2075
- :type speedBrakes: dict{boolean,float}.
2076
- :type ROCD_min: float.
2077
- :type Lat: float.
2078
- :type Lon: float.
2079
- :type initialHeading: {float,float,boolean}.
2080
- :type magneticDeclinationGrid: magneticDeclinationGrid.
2081
- :type mass_const: boolean.
2082
- :type m_iter: integer.
2083
- :type reducedPower: boolean.
2084
- :returns:
2085
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
2086
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
2087
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
2088
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
2089
- :rtype: dict[list[float]}.
2200
+ """
2201
+ Computes the time, fuel consumption, and performance parameters required for an aircraft to
2202
+ perform a climb or descent based on a set amount of time, while maintaining a constant speed and constant
2203
+ rate of climb/descent (ROCD).
2204
+
2205
+ The function supports various BADA families (BADA3, BADA4, BADAH, BADAE), with different handling for mass changes,
2206
+ aerodynamic configurations, and energy consumption. It calculates parameters such as fuel consumption, power
2207
+ requirements, speed, heading, and altitude changes over the specified duration.
2208
+
2209
+ :param AC: Aircraft object {BADA3/4/H/E}
2210
+ :param length: The length of the segment to fly in time [s].
2211
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
2212
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
2213
+ :param Hp_init: Initial pressure altitude [ft].
2214
+ :param ROCDtarget: Rate of climb or descent [ft/min].
2215
+ :param m_init: Initial aircraft mass at the start of the segment [kg].
2216
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
2217
+ :param wS: Wind speed component along the longitudinal axis [kt]. Default is 0.0.
2218
+ :param turnMetrics: Dictionary defining turn parameters:
2219
+ - rateOfTurn [deg/s]
2220
+ - bankAngle [deg]
2221
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
2222
+ :param Lat: Geographical latitude at the start [deg]. Default is None.
2223
+ :param Lon: Geographical longitude at the start [deg]. Default is None.
2224
+ :param initialHeading: Dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
2225
+ - magnetic: Magnetic heading [deg].
2226
+ - true: True heading [deg].
2227
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
2228
+ :param reducedPower: Boolean specifying whether to apply reduced power during the climb. Default is None.
2229
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
2230
+ :param magneticDeclinationGrid: Optional grid of magnetic declinations used to correct headings. Default is None.
2231
+ :param kwargs: Additional optional parameters:
2232
+ - step_length: Step size in seconds for time iteration. Default is 1 second.
2233
+ - SOC_init: Initial state of charge for electric aircraft [%]. Default is 100 for BADAE.
2234
+ - speedBrakes: Dictionary specifying whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
2235
+ - ROCD_min: Minimum ROCD to identify the service ceiling [ft/min]. Default varies by aircraft type.
2236
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD. Default is None.
2237
+ - mass_const: Boolean specifying whether to keep the mass constant during the segment. Default is False.
2238
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
2239
+
2240
+ :returns: A pandas DataFrame containing the flight trajectory, including parameters like:
2241
+ - Hp: Altitude [ft]
2242
+ - TAS: True Air Speed [kt]
2243
+ - CAS: Calibrated Air Speed [kt]
2244
+ - GS: Ground Speed [kt]
2245
+ - M: Mach number [-]
2246
+ - ROCD: Rate of Climb/Descent [ft/min]
2247
+ - ESF: Energy Share Factor [-]
2248
+ - FUEL: Fuel flow [kg/s]
2249
+ - FUELCONSUMED: Total fuel consumed [kg]
2250
+ - THR: Thrust force [N]
2251
+ - DRAG: Drag force [N]
2252
+ - time: Elapsed time [s]
2253
+ - dist: Distance flown [NM]
2254
+ - slope: Trajectory slope [deg]
2255
+ - mass: Aircraft mass [kg]
2256
+ - config: Aerodynamic configuration
2257
+ - LAT: Latitude [deg]
2258
+ - LON: Longitude [deg]
2259
+ - HDGTrue: True heading [deg]
2260
+ - HDGMagnetic: Magnetic heading [deg]
2261
+ - BankAngle: Bank angle [deg]
2262
+ - ROT: Rate of turn [deg/s]
2263
+ - For BADAH:
2264
+ - Preq: Required power [W]
2265
+ - Peng: Generated power [W]
2266
+ - Pav: Available power [W]
2267
+ - For BADAE (electric aircraft):
2268
+ - Pmec: Mechanical power [W]
2269
+ - Pelc: Electrical power [W]
2270
+ - Pbat: Power supplied by the battery [W]
2271
+ - SOCr: Rate of battery state of charge depletion [%/h]
2272
+ - SOC: Battery state of charge [%]
2273
+ - Ibat: Battery current [A]
2274
+ - Vbat: Battery voltage [V]
2275
+ - Vgbat: Ground battery voltage [V]
2276
+ - Comment: Comments for each segment.
2277
+ :rtype: pandas.DataFrame
2090
2278
  """
2091
2279
 
2092
2280
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -2137,7 +2325,9 @@ def constantSpeedROCD_time(
2137
2325
 
2138
2326
  # speed brakes application
2139
2327
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
2140
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
2328
+ speedBrakes = kwargs.get(
2329
+ "speedBrakes", {"deployed": False, "value": 0.03}
2330
+ )
2141
2331
 
2142
2332
  # step size in [s]
2143
2333
  step_length = kwargs.get("step_length", 1)
@@ -2170,7 +2360,9 @@ def constantSpeedROCD_time(
2170
2360
  constHeadingStr = ""
2171
2361
 
2172
2362
  # comment line describing type of trajectory calculation
2173
- comment = phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
2363
+ comment = (
2364
+ phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
2365
+ )
2174
2366
 
2175
2367
  if Lat and Lon and (magneticHeading or trueHeading):
2176
2368
  comment = comment + "_" + headingToFly + "_Heading"
@@ -2191,7 +2383,9 @@ def constantSpeedROCD_time(
2191
2383
  )
2192
2384
 
2193
2385
  # weight iteration constant
2194
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
2386
+ m_iter = kwargs.get(
2387
+ "m_iter", 5
2388
+ ) # number of iterations for integration loop[-]
2195
2389
 
2196
2390
  # convert ROCD to IS units
2197
2391
  ROCDisu = conv.ft2m(ROCDtarget) / 60
@@ -2269,8 +2463,12 @@ def constantSpeedROCD_time(
2269
2463
  for _ in itertools.repeat(None, m_iter):
2270
2464
  # atmosphere properties
2271
2465
  H_m = conv.ft2m(Hp_i) # altitude [m]
2272
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
2273
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
2466
+ [theta, delta, sigma] = atm.atmosphereProperties(
2467
+ h=H_m, DeltaTemp=DeltaTemp
2468
+ )
2469
+ temp_const = (theta * const.temp_0) / (
2470
+ theta * const.temp_0 - DeltaTemp
2471
+ )
2274
2472
 
2275
2473
  # aircraft speed
2276
2474
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -2279,13 +2477,18 @@ def constantSpeedROCD_time(
2279
2477
 
2280
2478
  # compute Energy Share Factor (ESF)
2281
2479
  ESF_i = AC.esf(
2282
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
2480
+ h=H_m,
2481
+ M=M_i,
2482
+ DeltaTemp=DeltaTemp,
2483
+ flightEvolution=("const" + speedType),
2283
2484
  )
2284
2485
 
2285
2486
  if turnFlight:
2286
2487
  if turnMetrics["bankAngle"] != 0.0:
2287
2488
  # bankAngle is defined
2288
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
2489
+ rateOfTurn = AC.rateOfTurn_bankAngle(
2490
+ TAS=TAS_i, bankAngle=bankAngle
2491
+ )
2289
2492
  else:
2290
2493
  # rateOfTurn is defined
2291
2494
  bankAngle = AC.bankAngle(
@@ -2300,7 +2503,9 @@ def constantSpeedROCD_time(
2300
2503
  # BADAH or BADAE
2301
2504
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
2302
2505
  # compute Power required for level flight
2303
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
2506
+ Preq_i = AC.Preq(
2507
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
2508
+ )
2304
2509
  # Compute power required for target ROCD
2305
2510
  Preq_target_i = AC.Peng_target(
2306
2511
  temp=theta * const.temp_0,
@@ -2328,20 +2533,27 @@ def constantSpeedROCD_time(
2328
2533
  # ensure continuity of configuration change within the segment
2329
2534
  if config:
2330
2535
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
2331
- phase=phase, previousConfig=config[-1], currentConfig=config_i
2536
+ phase=phase,
2537
+ previousConfig=config[-1],
2538
+ currentConfig=config_i,
2332
2539
  )
2333
2540
 
2334
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
2541
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
2542
+ config=config_i
2543
+ )
2335
2544
 
2336
2545
  # compute lift coefficient
2337
2546
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
2338
2547
  # compute drag coefficient
2339
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
2548
+ CD = AC.CD(
2549
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
2550
+ )
2340
2551
  # compute drag force
2341
2552
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
2342
2553
  # compute thrust force
2343
2554
  THR_i = (
2344
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
2555
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
2556
+ + Drag
2345
2557
  ) # [N]
2346
2558
 
2347
2559
  # BADA3
@@ -2374,7 +2586,8 @@ def constantSpeedROCD_time(
2374
2586
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
2375
2587
  # compute thrust force
2376
2588
  THR_i = (
2377
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
2589
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
2590
+ + Drag
2378
2591
  ) # [N]
2379
2592
 
2380
2593
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -2473,21 +2686,39 @@ def constantSpeedROCD_time(
2473
2686
  Pelc_i = Preq_target_i / AC.eta
2474
2687
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
2475
2688
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
2476
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
2689
+ Vgbat_i = (
2690
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
2691
+ )
2477
2692
 
2478
2693
  # BADA4
2479
2694
  elif AC.BADAFamily.BADA4:
2480
2695
  THR_min = AC.Thrust(
2481
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2696
+ rating="LIDL",
2697
+ delta=delta,
2698
+ theta=theta,
2699
+ M=M_i,
2700
+ DeltaTemp=DeltaTemp,
2482
2701
  ) # IDLE Thrust
2483
2702
  FUEL_min = AC.ff(
2484
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2703
+ rating="LIDL",
2704
+ delta=delta,
2705
+ theta=theta,
2706
+ M=M_i,
2707
+ DeltaTemp=DeltaTemp,
2485
2708
  ) # IDLE Fuel Flow
2486
2709
  THR_max = AC.Thrust(
2487
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2710
+ rating="MCMB",
2711
+ delta=delta,
2712
+ theta=theta,
2713
+ M=M_i,
2714
+ DeltaTemp=DeltaTemp,
2488
2715
  ) # MCMB Thrust
2489
2716
  FUEL_max = AC.ff(
2490
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2717
+ rating="MCMB",
2718
+ delta=delta,
2719
+ theta=theta,
2720
+ M=M_i,
2721
+ DeltaTemp=DeltaTemp,
2491
2722
  ) # MCMB Fuel Flow
2492
2723
  if THR_i < THR_min:
2493
2724
  THR_i = THR_min
@@ -2518,14 +2749,22 @@ def constantSpeedROCD_time(
2518
2749
  else:
2519
2750
  CT = AC.CT(Thrust=THR_i, delta=delta)
2520
2751
  FUEL_i = AC.ff(
2521
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2752
+ CT=CT,
2753
+ delta=delta,
2754
+ theta=theta,
2755
+ M=M_i,
2756
+ DeltaTemp=DeltaTemp,
2522
2757
  ) # [kg/s]
2523
2758
  ROCD_i = ROCDtarget
2524
2759
 
2525
2760
  # BADA3
2526
2761
  elif AC.BADAFamily.BADA3:
2527
2762
  THR_min = AC.Thrust(
2528
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
2763
+ rating="LIDL",
2764
+ v=TAS_i,
2765
+ h=H_m,
2766
+ config="CR",
2767
+ DeltaTemp=DeltaTemp,
2529
2768
  ) # IDLE Thrust
2530
2769
  FUEL_min = AC.ff(
2531
2770
  flightPhase="Descent",
@@ -2536,7 +2775,11 @@ def constantSpeedROCD_time(
2536
2775
  adapted=False,
2537
2776
  ) # IDLE Fuel Flow
2538
2777
  THR_max = AC.Thrust(
2539
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
2778
+ rating="MCMB",
2779
+ v=TAS_i,
2780
+ h=H_m,
2781
+ DeltaTemp=DeltaTemp,
2782
+ config="CR",
2540
2783
  ) # MCMB Thrust
2541
2784
  FUEL_max = AC.ff(
2542
2785
  flightPhase="Climb",
@@ -2688,12 +2931,18 @@ def constantSpeedROCD_time(
2688
2931
  [theta, delta, sigma] = atm.atmosphereProperties(
2689
2932
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
2690
2933
  )
2691
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
2934
+ temp_const = (theta * const.temp_0) / (
2935
+ theta * const.temp_0 - DeltaTemp
2936
+ )
2692
2937
  if AC.BADAFamily.BADAE:
2693
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
2938
+ gamma_i = degrees(
2939
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
2940
+ )
2694
2941
  else:
2695
2942
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
2696
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
2943
+ gamma_i = degrees(
2944
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
2945
+ )
2697
2946
 
2698
2947
  # ground speed can be calcualted as TAS projected on the ground minus wind
2699
2948
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -2730,7 +2979,9 @@ def constantSpeedROCD_time(
2730
2979
  if turnFlight:
2731
2980
  step_distance = conv.m2nm(
2732
2981
  turn.distance(
2733
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
2982
+ rateOfTurn=rateOfTurn,
2983
+ TAS=TAS_i,
2984
+ timeOfTurn=step_time,
2734
2985
  )
2735
2986
  ) # arcLength during the turn [NM]
2736
2987
  else:
@@ -2932,58 +3183,83 @@ def constantSpeedSlope(
2932
3183
  magneticDeclinationGrid=None,
2933
3184
  **kwargs,
2934
3185
  ):
2935
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init to Hp_final at constant speed and constant slope
2936
-
2937
- :param AC: aircraft {BADA3/4/H/E}
2938
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
2939
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
2940
- :param Hp_init: initial pressure altitude [ft].
2941
- :param Hp_final: final pressure altitude [ft].
2942
- :param slopetarget: slope to be followed [deg].
2943
- :param m_init: initial aircraft mass [kg].
2944
- :param DeltaTemp: deviation with respect to ISA [K].
2945
- :param wS: longitudinal wind speed (TAS) [kt].
2946
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
2947
- :param Hp_step: length of an altitude step of a segment [ft].
2948
- :param SOC_init: initial state of charge [%].
2949
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
2950
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
2951
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
2952
- :param Lat: Geographical Latitude [deg]
2953
- :param Lon: Geographical Longitude [deg]
2954
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
2955
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
2956
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
2957
- :param m_iter: number of iterations for integration loop [-]
2958
- :param reducedPower: reduction of Power during the climb {True/False}
2959
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
2960
- :type speedType: string.
2961
- :type v: float.
2962
- :type Hp_init: float.
2963
- :type Hp_final: float.
2964
- :type slopetarget: float.
2965
- :type m_init: float.
2966
- :type DeltaTemp: float.
2967
- :type wS: float.
2968
- :type turnMetrics: {float,float,string}.
2969
- :type Hp_step: float.
2970
- :type SOC_init: float.
2971
- :type config: string.
2972
- :type speedBrakes: dict{boolean,float}.
2973
- :type ROCD_min: float.
2974
- :type Lat: float.
2975
- :type Lon: float.
2976
- :type initialHeading: {float,float,boolean}.
2977
- :type magneticDeclinationGrid: magneticDeclinationGrid.
2978
- :type mass_const: boolean.
2979
- :type m_iter: integer.
2980
- :type reducedPower: boolean.
2981
- :returns:
2982
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
2983
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
2984
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
2985
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
2986
- :rtype: dict[list[float]}.
3186
+ """
3187
+ Calculates time, fuel consumption, and other parameters required for an aircraft to perform a climb or descent
3188
+ from an initial altitude (Hp_init) to a final altitude (Hp_final) while maintaining a constant speed and a constant slope.
3189
+
3190
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key flight parameters
3191
+ such as energy consumption, rate of climb/descent (ROCD), fuel burn, mass changes, and power requirements. The function also supports
3192
+ complex flight dynamics including turns, heading changes, and wind influences.
3193
+
3194
+ :param AC: Aircraft object {BADA3/4/H/E}.
3195
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
3196
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
3197
+ :param Hp_init: Initial pressure altitude [ft].
3198
+ :param Hp_final: Final pressure altitude [ft].
3199
+ :param slopetarget: Target slope (trajectory angle) to be maintained during climb/descent [deg].
3200
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
3201
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
3202
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
3203
+ :param turnMetrics: A dictionary defining the turn parameters:
3204
+ - rateOfTurn [deg/s]
3205
+ - bankAngle [deg]
3206
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
3207
+ :param Lat: Initial latitude [deg]. Default is None.
3208
+ :param Lon: Initial longitude [deg]. Default is None.
3209
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
3210
+ - magnetic: Magnetic heading [deg].
3211
+ - true: True heading [deg].
3212
+ - constantHeading: Whether to maintain a constant heading. Default is None.
3213
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
3214
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
3215
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
3216
+ :param kwargs: Additional optional parameters:
3217
+ - Hp_step: Step size in altitude for the iterative calculation [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
3218
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
3219
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
3220
+ - ROCD_min: Minimum rate of climb/descent used to determine service ceiling [ft/min]. Default varies based on aircraft type.
3221
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
3222
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
3223
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
3224
+
3225
+ :returns: A pandas DataFrame containing flight trajectory data with the following columns:
3226
+ - Hp: Pressure altitude [ft]
3227
+ - TAS: True Air Speed [kt]
3228
+ - CAS: Calibrated Air Speed [kt]
3229
+ - GS: Ground Speed [kt]
3230
+ - M: Mach number [-]
3231
+ - ROCD: Rate of climb/descent [ft/min]
3232
+ - ESF: Energy Share Factor [-]
3233
+ - FUEL: Fuel flow [kg/s]
3234
+ - FUELCONSUMED: Total fuel consumed [kg]
3235
+ - THR: Thrust force [N]
3236
+ - DRAG: Drag force [N]
3237
+ - time: Elapsed time [s]
3238
+ - dist: Distance flown [NM]
3239
+ - slope: Flight trajectory slope (angle) [deg]
3240
+ - mass: Aircraft mass [kg]
3241
+ - config: Aerodynamic configuration
3242
+ - LAT: Latitude [deg]
3243
+ - LON: Longitude [deg]
3244
+ - HDGTrue: True heading [deg]
3245
+ - HDGMagnetic: Magnetic heading [deg]
3246
+ - BankAngle: Bank angle during the turn [deg]
3247
+ - ROT: Rate of turn [deg/s]
3248
+ - Comment: Comments describing the flight segment
3249
+ - For BADAH:
3250
+ - Preq: Required power for level flight [W]
3251
+ - Peng: Generated power [W]
3252
+ - Pav: Available power [W]
3253
+ - For BADAE (electric aircraft):
3254
+ - Pmec: Mechanical power [W]
3255
+ - Pelc: Electrical power [W]
3256
+ - Pbat: Battery power [W]
3257
+ - SOCr: Rate of battery state of charge depletion [%/h]
3258
+ - SOC: Battery state of charge [%]
3259
+ - Ibat: Battery current [A]
3260
+ - Vbat: Battery voltage [V]
3261
+ - Vgbat: Ground battery voltage [V]
3262
+ :rtype: pandas.DataFrame
2987
3263
  """
2988
3264
 
2989
3265
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -3034,7 +3310,9 @@ def constantSpeedSlope(
3034
3310
 
3035
3311
  # speed brakes application
3036
3312
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
3037
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
3313
+ speedBrakes = kwargs.get(
3314
+ "speedBrakes", {"deployed": False, "value": 0.03}
3315
+ )
3038
3316
 
3039
3317
  # optional parameter - iteration step for altitude loop
3040
3318
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -3079,7 +3357,9 @@ def constantSpeedSlope(
3079
3357
  constHeadingStr = ""
3080
3358
 
3081
3359
  # comment line describing type of trajectory calculation
3082
- comment = phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
3360
+ comment = (
3361
+ phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
3362
+ )
3083
3363
 
3084
3364
  if Lat and Lon and (magneticHeading or trueHeading):
3085
3365
  comment = comment + "_" + headingToFly + "_Heading"
@@ -3100,7 +3380,9 @@ def constantSpeedSlope(
3100
3380
  )
3101
3381
 
3102
3382
  # weight iteration constant
3103
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
3383
+ m_iter = kwargs.get(
3384
+ "m_iter", 5
3385
+ ) # number of iterations for integration loop[-]
3104
3386
 
3105
3387
  # initialize output parameters
3106
3388
  Hp = []
@@ -3166,8 +3448,12 @@ def constantSpeedSlope(
3166
3448
 
3167
3449
  # atmosphere properties
3168
3450
  H_m = conv.ft2m(Hp_i) # altitude [m]
3169
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
3170
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
3451
+ [theta, delta, sigma] = atm.atmosphereProperties(
3452
+ h=H_m, DeltaTemp=DeltaTemp
3453
+ )
3454
+ temp_const = (theta * const.temp_0) / (
3455
+ theta * const.temp_0 - DeltaTemp
3456
+ )
3171
3457
 
3172
3458
  # aircraft speed
3173
3459
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -3177,17 +3463,24 @@ def constantSpeedSlope(
3177
3463
  if turnFlight:
3178
3464
  if turnMetrics["bankAngle"] != 0.0:
3179
3465
  # bankAngle is defined
3180
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
3466
+ rateOfTurn = AC.rateOfTurn_bankAngle(
3467
+ TAS=TAS_i, bankAngle=bankAngle
3468
+ )
3181
3469
  else:
3182
3470
  # rateOfTurn is defined
3183
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
3471
+ bankAngle = AC.bankAngle(
3472
+ rateOfTurn=rateOfTurn, v=TAS_i
3473
+ ) # [degrees]
3184
3474
 
3185
3475
  # Load factor
3186
3476
  nz = 1 / cos(radians(bankAngle))
3187
3477
 
3188
3478
  # compute Energy Share Factor (ESF)
3189
3479
  ESF_i = AC.esf(
3190
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
3480
+ h=H_m,
3481
+ M=M_i,
3482
+ DeltaTemp=DeltaTemp,
3483
+ flightEvolution=("const" + speedType),
3191
3484
  )
3192
3485
 
3193
3486
  if AC.BADAFamily.BADAE:
@@ -3205,7 +3498,9 @@ def constantSpeedSlope(
3205
3498
  # BADAH or BADAE
3206
3499
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
3207
3500
  # compute Power required for level flight
3208
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
3501
+ Preq_i = AC.Preq(
3502
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
3503
+ )
3209
3504
  # Compute power required for target ROCD
3210
3505
  Preq_target_i = AC.Peng_target(
3211
3506
  temp=theta * const.temp_0,
@@ -3233,20 +3528,27 @@ def constantSpeedSlope(
3233
3528
  # ensure continuity of configuration change within the segment
3234
3529
  if config:
3235
3530
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
3236
- phase=phase, previousConfig=config[-1], currentConfig=config_i
3531
+ phase=phase,
3532
+ previousConfig=config[-1],
3533
+ currentConfig=config_i,
3237
3534
  )
3238
3535
 
3239
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
3536
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
3537
+ config=config_i
3538
+ )
3240
3539
 
3241
3540
  # compute lift coefficient
3242
3541
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
3243
3542
  # compute drag coefficient
3244
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
3543
+ CD = AC.CD(
3544
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
3545
+ )
3245
3546
  # compute drag force
3246
3547
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
3247
3548
  # compute thrust force
3248
3549
  THR_i = (
3249
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
3550
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
3551
+ + Drag
3250
3552
  ) # [N]
3251
3553
 
3252
3554
  # BADA3
@@ -3279,7 +3581,8 @@ def constantSpeedSlope(
3279
3581
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
3280
3582
  # compute thrust force
3281
3583
  THR_i = (
3282
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
3584
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
3585
+ + Drag
3283
3586
  ) # [N]
3284
3587
 
3285
3588
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -3378,21 +3681,39 @@ def constantSpeedSlope(
3378
3681
  Pelc_i = Preq_target_i / AC.eta
3379
3682
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
3380
3683
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
3381
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
3684
+ Vgbat_i = (
3685
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
3686
+ )
3382
3687
 
3383
3688
  # BADA4
3384
3689
  elif AC.BADAFamily.BADA4:
3385
3690
  THR_min = AC.Thrust(
3386
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3691
+ rating="LIDL",
3692
+ delta=delta,
3693
+ theta=theta,
3694
+ M=M_i,
3695
+ DeltaTemp=DeltaTemp,
3387
3696
  ) # IDLE Thrust
3388
3697
  FUEL_min = AC.ff(
3389
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3698
+ rating="LIDL",
3699
+ delta=delta,
3700
+ theta=theta,
3701
+ M=M_i,
3702
+ DeltaTemp=DeltaTemp,
3390
3703
  ) # IDLE Fuel Flow
3391
3704
  THR_max = AC.Thrust(
3392
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3705
+ rating="MCMB",
3706
+ delta=delta,
3707
+ theta=theta,
3708
+ M=M_i,
3709
+ DeltaTemp=DeltaTemp,
3393
3710
  ) # MCMB Thrust
3394
3711
  FUEL_max = AC.ff(
3395
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3712
+ rating="MCMB",
3713
+ delta=delta,
3714
+ theta=theta,
3715
+ M=M_i,
3716
+ DeltaTemp=DeltaTemp,
3396
3717
  ) # MCMB Fuel Flow
3397
3718
 
3398
3719
  if THR_i < THR_min:
@@ -3424,14 +3745,22 @@ def constantSpeedSlope(
3424
3745
  else:
3425
3746
  CT = AC.CT(Thrust=THR_i, delta=delta)
3426
3747
  FUEL_i = AC.ff(
3427
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3748
+ CT=CT,
3749
+ delta=delta,
3750
+ theta=theta,
3751
+ M=M_i,
3752
+ DeltaTemp=DeltaTemp,
3428
3753
  ) # [kg/s]
3429
3754
  ROCD_i = conv.m2ft(ROCDisu) * 60
3430
3755
 
3431
3756
  # BADA3
3432
3757
  elif AC.BADAFamily.BADA3:
3433
3758
  THR_min = AC.Thrust(
3434
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
3759
+ rating="LIDL",
3760
+ v=TAS_i,
3761
+ h=H_m,
3762
+ config="CR",
3763
+ DeltaTemp=DeltaTemp,
3435
3764
  ) # IDLE Thrust
3436
3765
  FUEL_min = AC.ff(
3437
3766
  flightPhase="Descent",
@@ -3442,7 +3771,11 @@ def constantSpeedSlope(
3442
3771
  adapted=False,
3443
3772
  ) # IDLE Fuel Flow
3444
3773
  THR_max = AC.Thrust(
3445
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
3774
+ rating="MCMB",
3775
+ v=TAS_i,
3776
+ h=H_m,
3777
+ DeltaTemp=DeltaTemp,
3778
+ config="CR",
3446
3779
  ) # MCMB Thrust
3447
3780
  FUEL_max = AC.ff(
3448
3781
  flightPhase="Climb",
@@ -3590,10 +3923,14 @@ def constantSpeedSlope(
3590
3923
  gamma_i = 90 * np.sign(ROCD_i)
3591
3924
  else:
3592
3925
  if AC.BADAFamily.BADAE:
3593
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
3926
+ gamma_i = degrees(
3927
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
3928
+ )
3594
3929
  else:
3595
3930
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
3596
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
3931
+ gamma_i = degrees(
3932
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
3933
+ )
3597
3934
 
3598
3935
  # ground speed can be calcualted as TAS projected on the ground minus wind
3599
3936
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -3629,7 +3966,9 @@ def constantSpeedSlope(
3629
3966
  if turnFlight:
3630
3967
  step_distance = conv.m2nm(
3631
3968
  turn.distance(
3632
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
3969
+ rateOfTurn=rateOfTurn,
3970
+ TAS=TAS_i,
3971
+ timeOfTurn=step_time,
3633
3972
  )
3634
3973
  ) # arcLength during the turn [NM]
3635
3974
  else:
@@ -3844,59 +4183,82 @@ def constantSpeedSlope_time(
3844
4183
  magneticDeclinationGrid=None,
3845
4184
  **kwargs,
3846
4185
  ):
3847
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init for set amount of time at constant speed and constant slope
3848
-
3849
- :param AC: aircraft {BADA3/4/H/E}
3850
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
3851
- :param length: length of a segment to fly [s]
3852
- :param step_length: length of a step of a segment - [s]
3853
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
3854
- :param Hp_init: initial pressure altitude [ft].
3855
- :param slopetarget: slope to be followed [deg].
3856
- :param m_init: initial aircraft mass [kg].
3857
- :param DeltaTemp: deviation with respect to ISA [K].
3858
- :param wS: longitudinal wind speed (TAS) [kt].
3859
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
3860
- :param Hp_step: length of an altitude step of a segment [ft].
3861
- :param SOC_init: initial state of charge [%].
3862
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
3863
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
3864
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
3865
- :param Lat: Geographical Latitude [deg]
3866
- :param Lon: Geographical Longitude [deg]
3867
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
3868
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
3869
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
3870
- :param m_iter: number of iterations for integration loop [-]
3871
- :param reducedPower: reduction of Power during the climb {True/False}
3872
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
3873
- :type speedType: string.
3874
- :type length: float.
3875
- :type step_length: float.
3876
- :type v: float.
3877
- :type Hp_init: float.
3878
- :type slopetarget: float.
3879
- :type m_init: float.
3880
- :type DeltaTemp: float.
3881
- :type wS: float.
3882
- :type turnMetrics: {float,float,string}.
3883
- :type Hp_step: float.
3884
- :type SOC_init: float.
3885
- :type config: string.
3886
- :type speedBrakes: dict{boolean,float}.
3887
- :type ROCD_min: float.
3888
- :type Lat: float.
3889
- :type Lon: float.
3890
- :type initialHeading: {float,float,boolean}.
3891
- :type magneticDeclinationGrid: magneticDeclinationGrid.
3892
- :type mass_const: boolean.
3893
- :type m_iter: integer.
3894
- :returns:
3895
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
3896
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
3897
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
3898
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
3899
- :rtype: dict[list[float]}.
4186
+ """
4187
+ Computes the time, fuel, and trajectory parameters required by an aircraft to climb or descend at constant speed and slope over a given duration.
4188
+
4189
+ This function models a trajectory with constant speed (either CAS, TAS, or Mach) and a specified slope (degrees). The aircraft's dynamics are modeled based on BADA family data (BADA3, BADA4, BADAH, BADAE), supporting various aircraft types including electric models. It also accounts for turns, heading changes, and wind effects.
4190
+
4191
+ :param AC: Aircraft object {BADA3, BADA4, BADAH, BADAE}.
4192
+ :param length: Total duration of the segment [s].
4193
+ :param speedType: Speed type to follow during the trajectory {M, CAS, TAS}.
4194
+ :param v: Speed to follow (in knots for CAS/TAS or as a Mach number) [kt] or [-] for Mach.
4195
+ :param Hp_init: Initial pressure altitude [ft].
4196
+ :param slopetarget: Desired slope (trajectory angle) to follow [deg].
4197
+ :param m_init: Initial aircraft mass [kg].
4198
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
4199
+ :param wS: Longitudinal wind speed component (affects ground speed) [kt]. Default is 0.0.
4200
+ :param turnMetrics: A dictionary defining the turn parameters:
4201
+ - rateOfTurn [deg/s]
4202
+ - bankAngle [deg]
4203
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
4204
+ :param Lat: Initial latitude [deg]. Default is None.
4205
+ :param Lon: Initial longitude [deg]. Default is None.
4206
+ :param initialHeading: A dictionary specifying the initial heading (magnetic or true) and whether to fly a constant heading:
4207
+ - magnetic: Magnetic heading [deg].
4208
+ - true: True heading [deg].
4209
+ - constantHeading: Whether to maintain a constant heading [True/False].
4210
+ :param reducedPower: Boolean specifying if reduced power is applied during climb/descent. Default is None.
4211
+ :param directionOfTurn: Direction of turn {LEFT, RIGHT}. Default is None.
4212
+ :param magneticDeclinationGrid: Optional magnetic declination grid for correcting magnetic heading. Default is None.
4213
+ :param kwargs: Additional optional parameters:
4214
+ - step_length: Step length for trajectory calculation [s]. Default is 1 second.
4215
+ - Hp_step: Altitude step size for calculations [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
4216
+ - SOC_init: Initial battery state of charge (for electric aircraft) [%]. Default is 100.
4217
+ - config: Default aerodynamic configuration {TO, IC, CR, AP, LD}. If not provided, configuration is calculated automatically.
4218
+ - speedBrakes: Dictionary specifying if speed brakes are deployed and additional drag coefficient {deployed: False, value: 0.03}.
4219
+ - ROCD_min: Minimum Rate of Climb/Descent to determine service ceiling [ft/min]. Defaults depend on aircraft type and engine.
4220
+ - mass_const: Boolean indicating whether mass remains constant during the flight. Default is False.
4221
+ - m_iter: Number of iterations for mass integration. Default is 5.
4222
+
4223
+ :returns: A pandas DataFrame containing the flight trajectory data with the following columns:
4224
+ - Hp: Pressure altitude [ft]
4225
+ - TAS: True Air Speed [kt]
4226
+ - CAS: Calibrated Air Speed [kt]
4227
+ - GS: Ground Speed [kt]
4228
+ - M: Mach number [-]
4229
+ - ROCD: Rate of Climb/Descent [ft/min]
4230
+ - ESF: Energy Share Factor [-]
4231
+ - FUEL: Fuel flow [kg/s]
4232
+ - FUELCONSUMED: Total fuel consumed [kg]
4233
+ - THR: Thrust force [N]
4234
+ - DRAG: Drag force [N]
4235
+ - time: Elapsed time [s]
4236
+ - dist: Distance flown [NM]
4237
+ - slope: Trajectory slope (angle) [deg]
4238
+ - mass: Aircraft mass [kg]
4239
+ - config: Aerodynamic configuration
4240
+ - LAT: Latitude [deg]
4241
+ - LON: Longitude [deg]
4242
+ - HDGTrue: True heading [deg]
4243
+ - HDGMagnetic: Magnetic heading [deg]
4244
+ - BankAngle: Bank angle during turns [deg]
4245
+ - ROT: Rate of turn [deg/s]
4246
+ - Comment: Descriptive comments about the trajectory segment.
4247
+ - For BADAH:
4248
+ - Preq: Power required for level flight [W]
4249
+ - Peng: Generated power [W]
4250
+ - Pav: Available power [W]
4251
+ - For BADAE (electric aircraft):
4252
+ - Pmec: Mechanical power [W]
4253
+ - Pelc: Electrical power [W]
4254
+ - Pbat: Battery power [W]
4255
+ - SOCr: Battery state of charge rate of depletion [%/h]
4256
+ - SOC: Battery state of charge [%]
4257
+ - Ibat: Battery current [A]
4258
+ - Vbat: Battery voltage [V]
4259
+ - Vgbat: Ground battery voltage [V]
4260
+
4261
+ :rtype: pandas.DataFrame
3900
4262
  """
3901
4263
 
3902
4264
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -3947,7 +4309,9 @@ def constantSpeedSlope_time(
3947
4309
 
3948
4310
  # speed brakes application
3949
4311
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
3950
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
4312
+ speedBrakes = kwargs.get(
4313
+ "speedBrakes", {"deployed": False, "value": 0.03}
4314
+ )
3951
4315
 
3952
4316
  # step size in [s]
3953
4317
  step_length = kwargs.get("step_length", 1)
@@ -3980,7 +4344,9 @@ def constantSpeedSlope_time(
3980
4344
  constHeadingStr = ""
3981
4345
 
3982
4346
  # comment line describing type of trajectory calculation
3983
- comment = phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
4347
+ comment = (
4348
+ phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
4349
+ )
3984
4350
 
3985
4351
  if Lat and Lon and (magneticHeading or trueHeading):
3986
4352
  comment = comment + "_" + headingToFly + "_Heading"
@@ -4001,7 +4367,9 @@ def constantSpeedSlope_time(
4001
4367
  )
4002
4368
 
4003
4369
  # weight iteration constant
4004
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
4370
+ m_iter = kwargs.get(
4371
+ "m_iter", 5
4372
+ ) # number of iterations for integration loop[-]
4005
4373
 
4006
4374
  # initialize output parameters
4007
4375
  Hp = [Hp_init]
@@ -4075,8 +4443,12 @@ def constantSpeedSlope_time(
4075
4443
  for _ in itertools.repeat(None, m_iter):
4076
4444
  # atmosphere properties
4077
4445
  H_m = conv.ft2m(Hp_i) # altitude [m]
4078
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
4079
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
4446
+ [theta, delta, sigma] = atm.atmosphereProperties(
4447
+ h=H_m, DeltaTemp=DeltaTemp
4448
+ )
4449
+ temp_const = (theta * const.temp_0) / (
4450
+ theta * const.temp_0 - DeltaTemp
4451
+ )
4080
4452
 
4081
4453
  # aircraft speed
4082
4454
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -4086,7 +4458,9 @@ def constantSpeedSlope_time(
4086
4458
  if turnFlight:
4087
4459
  if turnMetrics["bankAngle"] != 0.0:
4088
4460
  # bankAngle is defined
4089
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
4461
+ rateOfTurn = AC.rateOfTurn_bankAngle(
4462
+ TAS=TAS_i, bankAngle=bankAngle
4463
+ )
4090
4464
  else:
4091
4465
  # rateOfTurn is defined
4092
4466
  bankAngle = AC.bankAngle(
@@ -4098,7 +4472,10 @@ def constantSpeedSlope_time(
4098
4472
 
4099
4473
  # compute Energy Share Factor (ESF)
4100
4474
  ESF_i = AC.esf(
4101
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
4475
+ h=H_m,
4476
+ M=M_i,
4477
+ DeltaTemp=DeltaTemp,
4478
+ flightEvolution=("const" + speedType),
4102
4479
  )
4103
4480
 
4104
4481
  step_time = length_loop - time[-1]
@@ -4106,14 +4483,20 @@ def constantSpeedSlope_time(
4106
4483
  # Compute required ROCD
4107
4484
  if AC.BADAFamily.BADAE:
4108
4485
  # special case for BADAE, in future it may apply also for BADAH
4109
- ROCDisu = tan(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4486
+ ROCDisu = (
4487
+ tan(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4488
+ )
4110
4489
  else:
4111
- ROCDisu = sin(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4490
+ ROCDisu = (
4491
+ sin(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4492
+ )
4112
4493
 
4113
4494
  # BADAH or BADAE
4114
4495
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
4115
4496
  # compute Power required for level flight
4116
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
4497
+ Preq_i = AC.Preq(
4498
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
4499
+ )
4117
4500
  # Compute power required for target ROCD
4118
4501
  Preq_target_i = AC.Peng_target(
4119
4502
  temp=theta * const.temp_0,
@@ -4141,20 +4524,27 @@ def constantSpeedSlope_time(
4141
4524
  # ensure continuity of configuration change within the segment
4142
4525
  if config:
4143
4526
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
4144
- phase=phase, previousConfig=config[-1], currentConfig=config_i
4527
+ phase=phase,
4528
+ previousConfig=config[-1],
4529
+ currentConfig=config_i,
4145
4530
  )
4146
4531
 
4147
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
4532
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
4533
+ config=config_i
4534
+ )
4148
4535
 
4149
4536
  # compute lift coefficient
4150
4537
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
4151
4538
  # compute drag coefficient
4152
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
4539
+ CD = AC.CD(
4540
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
4541
+ )
4153
4542
  # compute drag force
4154
4543
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
4155
4544
  # compute thrust force
4156
4545
  THR_i = (
4157
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
4546
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
4547
+ + Drag
4158
4548
  ) # [N]
4159
4549
 
4160
4550
  # BADA3
@@ -4187,7 +4577,8 @@ def constantSpeedSlope_time(
4187
4577
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
4188
4578
  # compute thrust force
4189
4579
  THR_i = (
4190
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
4580
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
4581
+ + Drag
4191
4582
  ) # [N]
4192
4583
 
4193
4584
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -4286,21 +4677,39 @@ def constantSpeedSlope_time(
4286
4677
  Pelc_i = Preq_target_i / AC.eta
4287
4678
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
4288
4679
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
4289
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
4680
+ Vgbat_i = (
4681
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
4682
+ )
4290
4683
 
4291
4684
  # BADA4
4292
4685
  elif AC.BADAFamily.BADA4:
4293
4686
  THR_min = AC.Thrust(
4294
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4687
+ rating="LIDL",
4688
+ delta=delta,
4689
+ theta=theta,
4690
+ M=M_i,
4691
+ DeltaTemp=DeltaTemp,
4295
4692
  ) # IDLE Thrust
4296
4693
  FUEL_min = AC.ff(
4297
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4694
+ rating="LIDL",
4695
+ delta=delta,
4696
+ theta=theta,
4697
+ M=M_i,
4698
+ DeltaTemp=DeltaTemp,
4298
4699
  ) # IDLE Fuel Flow
4299
4700
  THR_max = AC.Thrust(
4300
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4701
+ rating="MCMB",
4702
+ delta=delta,
4703
+ theta=theta,
4704
+ M=M_i,
4705
+ DeltaTemp=DeltaTemp,
4301
4706
  ) # MCMB Thrust
4302
4707
  FUEL_max = AC.ff(
4303
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4708
+ rating="MCMB",
4709
+ delta=delta,
4710
+ theta=theta,
4711
+ M=M_i,
4712
+ DeltaTemp=DeltaTemp,
4304
4713
  ) # MCMB Fuel Flow
4305
4714
 
4306
4715
  if THR_i < THR_min:
@@ -4332,14 +4741,22 @@ def constantSpeedSlope_time(
4332
4741
  else:
4333
4742
  CT = AC.CT(Thrust=THR_i, delta=delta)
4334
4743
  FUEL_i = AC.ff(
4335
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4744
+ CT=CT,
4745
+ delta=delta,
4746
+ theta=theta,
4747
+ M=M_i,
4748
+ DeltaTemp=DeltaTemp,
4336
4749
  ) # [kg/s]
4337
4750
  ROCD_i = conv.m2ft(ROCDisu) * 60
4338
4751
 
4339
4752
  # BADA3
4340
4753
  elif AC.BADAFamily.BADA3:
4341
4754
  THR_min = AC.Thrust(
4342
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
4755
+ rating="LIDL",
4756
+ v=TAS_i,
4757
+ h=H_m,
4758
+ config="CR",
4759
+ DeltaTemp=DeltaTemp,
4343
4760
  ) # IDLE Thrust
4344
4761
  FUEL_min = AC.ff(
4345
4762
  flightPhase="Descent",
@@ -4350,7 +4767,11 @@ def constantSpeedSlope_time(
4350
4767
  adapted=False,
4351
4768
  ) # IDLE Fuel Flow
4352
4769
  THR_max = AC.Thrust(
4353
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
4770
+ rating="MCMB",
4771
+ v=TAS_i,
4772
+ h=H_m,
4773
+ DeltaTemp=DeltaTemp,
4774
+ config="CR",
4354
4775
  ) # MCMB Thrust
4355
4776
  FUEL_max = AC.ff(
4356
4777
  flightPhase="Climb",
@@ -4502,12 +4923,18 @@ def constantSpeedSlope_time(
4502
4923
  [theta, delta, sigma] = atm.atmosphereProperties(
4503
4924
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
4504
4925
  )
4505
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
4926
+ temp_const = (theta * const.temp_0) / (
4927
+ theta * const.temp_0 - DeltaTemp
4928
+ )
4506
4929
  if AC.BADAFamily.BADAE:
4507
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
4930
+ gamma_i = degrees(
4931
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
4932
+ )
4508
4933
  else:
4509
4934
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
4510
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
4935
+ gamma_i = degrees(
4936
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
4937
+ )
4511
4938
 
4512
4939
  # ground speed can be calcualted as TAS projected on the ground minus wind
4513
4940
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -4544,7 +4971,9 @@ def constantSpeedSlope_time(
4544
4971
  if turnFlight:
4545
4972
  step_distance = conv.m2nm(
4546
4973
  turn.distance(
4547
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
4974
+ rateOfTurn=rateOfTurn,
4975
+ TAS=TAS_i,
4976
+ timeOfTurn=step_time,
4548
4977
  )
4549
4978
  ) # arcLength during the turn [NM]
4550
4979
  else:
@@ -4747,58 +5176,83 @@ def constantSpeedRating(
4747
5176
  initRating=None,
4748
5177
  **kwargs,
4749
5178
  ):
4750
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init to Hp_final at constant speed and constant engine rating
4751
-
4752
- :param AC: aircraft {BADA3/4/H/E}
4753
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
4754
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
4755
- :param Hp_init: initial pressure altitude [ft].
4756
- :param Hp_final: final pressure altitude [ft].
4757
- :param m_init: initial aircraft mass [kg].
4758
- :param DeltaTemp: deviation with respect to ISA [K].
4759
- :param wS: longitudinal wind speed (TAS) [kt].
4760
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
4761
- :param Hp_step: length of an altitude step of a segment [ft].
4762
- :param SOC_init: initial state of charge [%].
4763
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
4764
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
4765
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
4766
- :param Lat: Geographical Latitude [deg]
4767
- :param Lon: Geographical Longitude [deg]
4768
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
4769
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
4770
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
4771
- :param m_iter: number of iterations for integration loop [-]
4772
- :param reducedPower: reduction of Power during the climb {True/False}
4773
- :param initRating: default rating settings
4774
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
4775
- :type speedType: string.
4776
- :type v: float.
4777
- :type Hp_init: float.
4778
- :type Hp_final: float.
4779
- :type m_init: float.
4780
- :type DeltaTemp: float.
4781
- :type wS: float.
4782
- :type turnMetrics: {float,float,string}.
4783
- :type Hp_step: float.
4784
- :type SOC_init: float.
4785
- :type config: string.
4786
- :type speedBrakes: dict{boolean,float}.
4787
- :type ROCD_min: float.
4788
- :type Lat: float.
4789
- :type Lon: float.
4790
- :type initialHeading: {float,float,boolean}.
4791
- :type magneticDeclinationGrid: magneticDeclinationGrid.
4792
- :type mass_const: boolean.
4793
- :type m_iter: integer.
4794
- :type reducedPower: boolean.
4795
- :type initRating: string.
4796
- :returns:
4797
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
4798
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
4799
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
4800
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
4801
- :rtype: dict[list[float]}.
5179
+ """
5180
+ Calculates time, fuel consumption, and other parameters required for an aircraft to perform a climb or descent
5181
+ from an initial altitude (Hp_init) to a final altitude (Hp_final) while maintaining a constant speed and engine rating.
5182
+
5183
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key flight parameters
5184
+ such as fuel burn, rate of climb/descent (ROCD), thrust, drag, and energy requirements. The function also supports
5185
+ complex flight dynamics including turns, heading changes, and wind influences.
5186
+
5187
+ :param AC: Aircraft object {BADA3/4/H/E}.
5188
+ :param speedType: Type of speed to maintain during the flight {M (Mach), CAS, TAS}.
5189
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
5190
+ :param Hp_init: Initial pressure altitude [ft].
5191
+ :param Hp_final: Final pressure altitude [ft].
5192
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
5193
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
5194
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
5195
+ :param turnMetrics: A dictionary defining the turn parameters:
5196
+ - rateOfTurn [deg/s]
5197
+ - bankAngle [deg]
5198
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
5199
+ :param Lat: Initial latitude [deg]. Default is None.
5200
+ :param Lon: Initial longitude [deg]. Default is None.
5201
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
5202
+ - magnetic: Magnetic heading [deg].
5203
+ - true: True heading [deg].
5204
+ - constantHeading: Whether to maintain a constant heading. Default is None.
5205
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
5206
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
5207
+ :param expedite: Boolean flag to expedite climb/descent. Default is False.
5208
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
5209
+ :param kwargs: Additional optional parameters:
5210
+ - Hp_step: Step size in altitude for the iterative calculation [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
5211
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
5212
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
5213
+ - ROCD_min: Minimum rate of climb/descent used to determine service ceiling [ft/min]. Default varies based on aircraft type.
5214
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
5215
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
5216
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
5217
+
5218
+ :returns: A pandas DataFrame containing flight trajectory data with the following columns:
5219
+ - Hp: Pressure altitude [ft]
5220
+ - TAS: True Air Speed [kt]
5221
+ - CAS: Calibrated Air Speed [kt]
5222
+ - GS: Ground Speed [kt]
5223
+ - M: Mach number [-]
5224
+ - ROCD: Rate of climb/descent [ft/min]
5225
+ - ESF: Energy Share Factor [-]
5226
+ - FUEL: Fuel flow [kg/s]
5227
+ - FUELCONSUMED: Total fuel consumed [kg]
5228
+ - THR: Thrust force [N]
5229
+ - DRAG: Drag force [N]
5230
+ - time: Elapsed time [s]
5231
+ - dist: Distance flown [NM]
5232
+ - slope: Flight trajectory slope (angle) [deg]
5233
+ - mass: Aircraft mass [kg]
5234
+ - config: Aerodynamic configuration
5235
+ - LAT: Latitude [deg]
5236
+ - LON: Longitude [deg]
5237
+ - HDGTrue: True heading [deg]
5238
+ - HDGMagnetic: Magnetic heading [deg]
5239
+ - BankAngle: Bank angle during the turn [deg]
5240
+ - ROT: Rate of turn [deg/s]
5241
+ - Comment: Comments describing the flight segment
5242
+ - For BADAH:
5243
+ - Preq: Required power for level flight [W]
5244
+ - Peng: Generated power [W]
5245
+ - Pav: Available power [W]
5246
+ - For BADAE (electric aircraft):
5247
+ - Pmec: Mechanical power [W]
5248
+ - Pelc: Electrical power [W]
5249
+ - Pbat: Battery power [W]
5250
+ - SOCr: Rate of battery state of charge depletion [%/h]
5251
+ - SOC: Battery state of charge [%]
5252
+ - Ibat: Battery current [A]
5253
+ - Vbat: Battery voltage [V]
5254
+ - Vgbat: Ground battery voltage [V]
5255
+ :rtype: pandas.DataFrame
4802
5256
  """
4803
5257
 
4804
5258
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -4849,7 +5303,9 @@ def constantSpeedRating(
4849
5303
 
4850
5304
  # speed brakes application
4851
5305
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
4852
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
5306
+ speedBrakes = kwargs.get(
5307
+ "speedBrakes", {"deployed": False, "value": 0.03}
5308
+ )
4853
5309
 
4854
5310
  # optional parameter - iteration step for altitude loop
4855
5311
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -4908,7 +5364,13 @@ def constantSpeedRating(
4908
5364
 
4909
5365
  # comment line describing type of trajectory calculation
4910
5366
  comment = (
4911
- phase + turnComment + "_const_" + speedType + "_" + rating + constHeadingStr
5367
+ phase
5368
+ + turnComment
5369
+ + "_const_"
5370
+ + speedType
5371
+ + "_"
5372
+ + rating
5373
+ + constHeadingStr
4912
5374
  )
4913
5375
 
4914
5376
  if Lat and Lon and (magneticHeading or trueHeading):
@@ -4933,7 +5395,9 @@ def constantSpeedRating(
4933
5395
  )
4934
5396
 
4935
5397
  # weight iteration constant
4936
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
5398
+ m_iter = kwargs.get(
5399
+ "m_iter", 5
5400
+ ) # number of iterations for integration loop[-]
4937
5401
 
4938
5402
  # The thrust_fuel method for BADA 3 models applies the cruise fuel correction
4939
5403
  # whenever the thrust is adapted, instead of only in cruise: this correction
@@ -5004,8 +5468,12 @@ def constantSpeedRating(
5004
5468
  ## atmosphere, speeds, thrust. fuel flow, ESF
5005
5469
  # atmosphere properties
5006
5470
  H_m = conv.ft2m(Hp_i) # altitude [m]
5007
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
5008
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
5471
+ [theta, delta, sigma] = atm.atmosphereProperties(
5472
+ h=H_m, DeltaTemp=DeltaTemp
5473
+ )
5474
+ temp_const = (theta * const.temp_0) / (
5475
+ theta * const.temp_0 - DeltaTemp
5476
+ )
5009
5477
 
5010
5478
  # aircraft speed
5011
5479
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -5015,17 +5483,24 @@ def constantSpeedRating(
5015
5483
  if turnFlight:
5016
5484
  if turnMetrics["bankAngle"] != 0.0:
5017
5485
  # bankAngle is defined
5018
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
5486
+ rateOfTurn = AC.rateOfTurn_bankAngle(
5487
+ TAS=TAS_i, bankAngle=bankAngle
5488
+ )
5019
5489
  else:
5020
5490
  # rateOfTurn is defined
5021
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
5491
+ bankAngle = AC.bankAngle(
5492
+ rateOfTurn=rateOfTurn, v=TAS_i
5493
+ ) # [degrees]
5022
5494
 
5023
5495
  # Load factor
5024
5496
  nz = 1 / cos(radians(bankAngle))
5025
5497
 
5026
5498
  # compute Energy Share Factor (ESF)
5027
5499
  ESF_i = AC.esf(
5028
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
5500
+ h=H_m,
5501
+ M=M_i,
5502
+ DeltaTemp=DeltaTemp,
5503
+ flightEvolution=("const" + speedType),
5029
5504
  )
5030
5505
 
5031
5506
  mass_i = mass[-1]
@@ -5034,7 +5509,9 @@ def constantSpeedRating(
5034
5509
  if AC.BADAFamily.BADAH:
5035
5510
  # compute available power
5036
5511
  if rating == "UNKNOWN":
5037
- Preq_target_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
5512
+ Preq_target_i = (
5513
+ 0.1 * AC.P0
5514
+ ) # No minimum power model: assume 10% torque
5038
5515
  else:
5039
5516
  Preq_target_i = AC.Pav(rating=rating, theta=theta, delta=delta)
5040
5517
 
@@ -5048,7 +5525,9 @@ def constantSpeedRating(
5048
5525
  elif AC.BADAFamily.BADAE:
5049
5526
  # compute available power
5050
5527
  if rating == "UNKNOWN":
5051
- Preq_target_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
5528
+ Preq_target_i = (
5529
+ 0.1 * AC.P0
5530
+ ) # No minimum power model: assume 10% torque
5052
5531
  else:
5053
5532
  Preq_target_i = AC.Pav(rating=rating, SOC=SOC[-1])
5054
5533
 
@@ -5067,10 +5546,16 @@ def constantSpeedRating(
5067
5546
  elif AC.BADAFamily.BADA4:
5068
5547
  # compute thrust force and fuel flow
5069
5548
  THR_i = AC.Thrust(
5070
- rating=rating, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
5549
+ rating=rating,
5550
+ delta=delta,
5551
+ theta=theta,
5552
+ M=M_i,
5553
+ DeltaTemp=DeltaTemp,
5071
5554
  ) # [N]
5072
5555
  CT = AC.CT(Thrust=THR_i, delta=delta)
5073
- FUEL_i = AC.ff(CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp)
5556
+ FUEL_i = AC.ff(
5557
+ CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
5558
+ )
5074
5559
 
5075
5560
  # BADA3
5076
5561
  elif AC.BADAFamily.BADA3:
@@ -5089,12 +5574,18 @@ def constantSpeedRating(
5089
5574
  # ensure continuity of configuration change within the segment
5090
5575
  if config:
5091
5576
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5092
- phase=phase, previousConfig=config[-1], currentConfig=config_i
5577
+ phase=phase,
5578
+ previousConfig=config[-1],
5579
+ currentConfig=config_i,
5093
5580
  )
5094
5581
 
5095
5582
  # compute thrust force and fuel flow
5096
5583
  THR_i = AC.Thrust(
5097
- rating=rating, v=TAS_i, h=H_m, config=config_i, DeltaTemp=DeltaTemp
5584
+ rating=rating,
5585
+ v=TAS_i,
5586
+ h=H_m,
5587
+ config=config_i,
5588
+ DeltaTemp=DeltaTemp,
5098
5589
  )
5099
5590
  FUEL_i = AC.ff(
5100
5591
  flightPhase=phase,
@@ -5122,7 +5613,9 @@ def constantSpeedRating(
5122
5613
  # BADAH or BADAE
5123
5614
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
5124
5615
  # compute Power required
5125
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
5616
+ Preq_i = AC.Preq(
5617
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
5618
+ )
5126
5619
  # compute ROCD
5127
5620
  ROCD_i = (
5128
5621
  conv.m2ft(
@@ -5155,15 +5648,21 @@ def constantSpeedRating(
5155
5648
  # ensure continuity of configuration change within the segment
5156
5649
  if config:
5157
5650
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5158
- phase=phase, previousConfig=config[-1], currentConfig=config_i
5651
+ phase=phase,
5652
+ previousConfig=config[-1],
5653
+ currentConfig=config_i,
5159
5654
  )
5160
5655
 
5161
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
5656
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
5657
+ config=config_i
5658
+ )
5162
5659
 
5163
5660
  # compute lift coefficient
5164
5661
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
5165
5662
  # compute drag coefficient
5166
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
5663
+ CD = AC.CD(
5664
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
5665
+ )
5167
5666
  # compute drag force
5168
5667
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
5169
5668
  # compute ROCD
@@ -5204,7 +5703,10 @@ def constantSpeedRating(
5204
5703
  CL = AC.CL(tas=TAS_i, sigma=sigma, mass=mass_i, nz=nz)
5205
5704
  # compute drag coefficient
5206
5705
  CD = AC.CD(
5207
- CL=CL, config=config_i, expedite=expedite, speedBrakes=speedBrakes
5706
+ CL=CL,
5707
+ config=config_i,
5708
+ expedite=expedite,
5709
+ speedBrakes=speedBrakes,
5208
5710
  )
5209
5711
  # compute drag force
5210
5712
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
@@ -5327,10 +5829,14 @@ def constantSpeedRating(
5327
5829
  gamma_i = 90 * np.sign(ROCD_i)
5328
5830
  else:
5329
5831
  if AC.BADAFamily.BADAE:
5330
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
5832
+ gamma_i = degrees(
5833
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
5834
+ )
5331
5835
  else:
5332
5836
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
5333
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
5837
+ gamma_i = degrees(
5838
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
5839
+ )
5334
5840
 
5335
5841
  # ground speed can be calcualted as TAS projected on the ground minus wind
5336
5842
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -5366,7 +5872,9 @@ def constantSpeedRating(
5366
5872
  if turnFlight:
5367
5873
  step_distance = conv.m2nm(
5368
5874
  turn.distance(
5369
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
5875
+ rateOfTurn=rateOfTurn,
5876
+ TAS=TAS_i,
5877
+ timeOfTurn=step_time,
5370
5878
  )
5371
5879
  ) # arcLength during the turn [NM]
5372
5880
  else:
@@ -5583,60 +6091,85 @@ def constantSpeedRating_time(
5583
6091
  initRating=None,
5584
6092
  **kwargs,
5585
6093
  ):
5586
- """This function computes time and fuel required by an aircraft to perform a climb/descent from Hp_init for set amount of time at constant speed and constant engine rating
5587
-
5588
- :param AC: aircraft {BADA3/4/H/E}
5589
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
5590
- :param length: length of a segment to fly [s]
5591
- :param step_length: length of a step of a segment - [s]
5592
- :param v: what kind of speed is followed - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
5593
- :param Hp_init: initial pressure altitude [ft].
5594
- :param phase: phase of flight {Climb, Descent}
5595
- :param m_init: initial aircraft mass [kg].
5596
- :param DeltaTemp: deviation with respect to ISA [K].
5597
- :param wS: longitudinal wind speed (TAS) [kt].
5598
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
5599
- :param SOC_init: initial state of charge [%].
5600
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
5601
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
5602
- :param ROCD_min: lower ROCD threshold to identify the climbing capabilities (service ceiling) [ft/min].
5603
- :param Lat: Geographical Latitude [deg]
5604
- :param Lon: Geographical Longitude [deg]
5605
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
5606
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
5607
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
5608
- :param m_iter: number of iterations for integration loop [-]
5609
- :param reducedPower: reduction of Power during the climb {True/False}
5610
- :param initRating: default rating settings
5611
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
5612
- :type speedType: string.
5613
- :type length: float.
5614
- :type step_length: float.
5615
- :type v: float.
5616
- :type Hp_init: float.
5617
- :type phase: string.
5618
- :type m_init: float.
5619
- :type DeltaTemp: float.
5620
- :type wS: float.
5621
- :type turnMetrics: {float,float,string}.
5622
- :type SOC_init: float.
5623
- :type config: string.
5624
- :type speedBrakes: dict{boolean,float}.
5625
- :type ROCD_min: float.
5626
- :type Lat: float.
5627
- :type Lon: float.
5628
- :type initialHeading: {float,float,boolean}.
5629
- :type magneticDeclinationGrid: magneticDeclinationGrid.
5630
- :type mass_const: boolean.
5631
- :type m_iter: integer.
5632
- :type reducedPower: boolean.
5633
- :type initRating: string
5634
- :returns:
5635
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
5636
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
5637
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
5638
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
5639
- :rtype: dict[list[float]}.
6094
+ """
6095
+ Calculates the time, fuel consumption, and other flight parameters required for an aircraft to perform
6096
+ a climb or descent at constant speed and engine rating for a specified duration.
6097
+
6098
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key parameters
6099
+ such as rate of climb/descent (ROCD), thrust, drag, fuel burn, and power requirements. The function also supports complex
6100
+ flight dynamics, including turns, heading changes, and the effect of wind.
6101
+
6102
+ :param AC: Aircraft object {BADA3/4/H/E}.
6103
+ :param length: Duration of the flight segment [s].
6104
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
6105
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
6106
+ :param Hp_init: Initial pressure altitude [ft].
6107
+ :param phase: Phase of flight (Climb or Descent).
6108
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
6109
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
6110
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
6111
+ :param turnMetrics: A dictionary defining the turn parameters:
6112
+ - rateOfTurn [deg/s]
6113
+ - bankAngle [deg]
6114
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
6115
+ :param Lat: Initial latitude [deg]. Default is None.
6116
+ :param Lon: Initial longitude [deg]. Default is None.
6117
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
6118
+ - magnetic: Magnetic heading [deg].
6119
+ - true: True heading [deg].
6120
+ - constantHeading: Whether to maintain a constant heading. Default is None.
6121
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
6122
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
6123
+ :param expedite: Boolean flag to expedite the climb/descent. Default is False.
6124
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
6125
+ :param initRating: Initial engine rating settings. Default is None.
6126
+ :param kwargs: Additional optional parameters:
6127
+ - step_length: Step size in time for the iterative calculation [s]. Default is 1 s.
6128
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
6129
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
6130
+ - ROCD_min: Minimum rate of climb/descent to determine service ceiling [ft/min]. Default varies by aircraft type.
6131
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
6132
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
6133
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
6134
+
6135
+ :returns: A pandas DataFrame containing flight trajectory data with the following columns:
6136
+ - Hp: Pressure altitude [ft]
6137
+ - TAS: True Air Speed [kt]
6138
+ - CAS: Calibrated Air Speed [kt]
6139
+ - GS: Ground Speed [kt]
6140
+ - M: Mach number [-]
6141
+ - ROCD: Rate of climb/descent [ft/min]
6142
+ - ESF: Energy Share Factor [-]
6143
+ - FUEL: Fuel flow [kg/s]
6144
+ - FUELCONSUMED: Total fuel consumed [kg]
6145
+ - THR: Thrust force [N]
6146
+ - DRAG: Drag force [N]
6147
+ - time: Elapsed time [s]
6148
+ - dist: Distance flown [NM]
6149
+ - slope: Flight trajectory slope (angle) [deg]
6150
+ - mass: Aircraft mass [kg]
6151
+ - config: Aerodynamic configuration
6152
+ - LAT: Latitude [deg]
6153
+ - LON: Longitude [deg]
6154
+ - HDGTrue: True heading [deg]
6155
+ - HDGMagnetic: Magnetic heading [deg]
6156
+ - BankAngle: Bank angle during the turn [deg]
6157
+ - ROT: Rate of turn [deg/s]
6158
+ - Comment: Comments describing the flight segment
6159
+ - For BADAH:
6160
+ - Preq: Required power for level flight [W]
6161
+ - Peng: Generated power [W]
6162
+ - Pav: Available power [W]
6163
+ - For BADAE (electric aircraft):
6164
+ - Pmec: Mechanical power [W]
6165
+ - Pelc: Electrical power [W]
6166
+ - Pbat: Battery power [W]
6167
+ - SOCr: Rate of battery state of charge depletion [%/h]
6168
+ - SOC: Battery state of charge [%]
6169
+ - Ibat: Battery current [A]
6170
+ - Vbat: Battery voltage [V]
6171
+ - Vgbat: Ground battery voltage [V]
6172
+ :rtype: pandas.DataFrame
5640
6173
  """
5641
6174
 
5642
6175
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -5687,7 +6220,9 @@ def constantSpeedRating_time(
5687
6220
 
5688
6221
  # speed brakes application
5689
6222
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
5690
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
6223
+ speedBrakes = kwargs.get(
6224
+ "speedBrakes", {"deployed": False, "value": 0.03}
6225
+ )
5691
6226
 
5692
6227
  # step size in [s]
5693
6228
  step_length = kwargs.get("step_length", 1)
@@ -5722,7 +6257,9 @@ def constantSpeedRating_time(
5722
6257
  else:
5723
6258
  rating = "LIDL"
5724
6259
  else:
5725
- raise Exception("Phase definition is wrong! It should be Climb or Descent")
6260
+ raise Exception(
6261
+ "Phase definition is wrong! It should be Climb or Descent"
6262
+ )
5726
6263
  else:
5727
6264
  rating = initRating
5728
6265
 
@@ -5738,7 +6275,13 @@ def constantSpeedRating_time(
5738
6275
 
5739
6276
  # comment line describing type of trajectory calculation
5740
6277
  comment = (
5741
- phase + turnComment + "_const_" + speedType + "_" + rating + constHeadingStr
6278
+ phase
6279
+ + turnComment
6280
+ + "_const_"
6281
+ + speedType
6282
+ + "_"
6283
+ + rating
6284
+ + constHeadingStr
5742
6285
  )
5743
6286
 
5744
6287
  if Lat and Lon and (magneticHeading or trueHeading):
@@ -5763,7 +6306,9 @@ def constantSpeedRating_time(
5763
6306
  )
5764
6307
 
5765
6308
  # weight iteration constant
5766
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
6309
+ m_iter = kwargs.get(
6310
+ "m_iter", 5
6311
+ ) # number of iterations for integration loop[-]
5767
6312
 
5768
6313
  # The thrust_fuel method for BADA 3 models applies the cruise fuel correction
5769
6314
  # whenever the thrust is adapted, instead of only in cruise: this correction
@@ -5843,8 +6388,12 @@ def constantSpeedRating_time(
5843
6388
  for _ in itertools.repeat(None, m_iter):
5844
6389
  # atmosphere properties
5845
6390
  H_m = conv.ft2m(Hp_i) # altitude [m]
5846
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
5847
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
6391
+ [theta, delta, sigma] = atm.atmosphereProperties(
6392
+ h=H_m, DeltaTemp=DeltaTemp
6393
+ )
6394
+ temp_const = (theta * const.temp_0) / (
6395
+ theta * const.temp_0 - DeltaTemp
6396
+ )
5848
6397
 
5849
6398
  # aircraft speed
5850
6399
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -5854,7 +6403,9 @@ def constantSpeedRating_time(
5854
6403
  if turnFlight:
5855
6404
  if turnMetrics["bankAngle"] != 0.0:
5856
6405
  # bankAngle is defined
5857
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
6406
+ rateOfTurn = AC.rateOfTurn_bankAngle(
6407
+ TAS=TAS_i, bankAngle=bankAngle
6408
+ )
5858
6409
  else:
5859
6410
  # rateOfTurn is defined
5860
6411
  bankAngle = AC.bankAngle(
@@ -5866,7 +6417,10 @@ def constantSpeedRating_time(
5866
6417
 
5867
6418
  # compute Energy Share Factor (ESF)
5868
6419
  ESF_i = AC.esf(
5869
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
6420
+ h=H_m,
6421
+ M=M_i,
6422
+ DeltaTemp=DeltaTemp,
6423
+ flightEvolution=("const" + speedType),
5870
6424
  )
5871
6425
 
5872
6426
  step_time = length_loop - time[-1]
@@ -5879,7 +6433,9 @@ def constantSpeedRating_time(
5879
6433
  0.1 * AC.P0
5880
6434
  ) # No minimum power model: assume 10% torque
5881
6435
  else:
5882
- Preq_target_i = AC.Pav(rating=rating, theta=theta, delta=delta)
6436
+ Preq_target_i = AC.Pav(
6437
+ rating=rating, theta=theta, delta=delta
6438
+ )
5883
6439
 
5884
6440
  Pav_i = AC.Pav(rating="MTKF", theta=theta, delta=delta)
5885
6441
 
@@ -5904,13 +6460,19 @@ def constantSpeedRating_time(
5904
6460
  Pelc_i = Preq_target_i / AC.eta
5905
6461
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
5906
6462
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
5907
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
6463
+ Vgbat_i = (
6464
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
6465
+ )
5908
6466
 
5909
6467
  # BADA4
5910
6468
  elif AC.BADAFamily.BADA4:
5911
6469
  # compute thrust force and fuel flow
5912
6470
  THR_i = AC.Thrust(
5913
- rating=rating, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
6471
+ rating=rating,
6472
+ delta=delta,
6473
+ theta=theta,
6474
+ M=M_i,
6475
+ DeltaTemp=DeltaTemp,
5914
6476
  ) # [N]
5915
6477
  CT = AC.CT(Thrust=THR_i, delta=delta)
5916
6478
  FUEL_i = AC.ff(
@@ -5941,7 +6503,11 @@ def constantSpeedRating_time(
5941
6503
 
5942
6504
  # compute thrust force and fuel flow
5943
6505
  THR_i = AC.Thrust(
5944
- rating=rating, v=TAS_i, h=H_m, config=config_i, DeltaTemp=DeltaTemp
6506
+ rating=rating,
6507
+ v=TAS_i,
6508
+ h=H_m,
6509
+ config=config_i,
6510
+ DeltaTemp=DeltaTemp,
5945
6511
  )
5946
6512
  FUEL_i = AC.ff(
5947
6513
  flightPhase=phase,
@@ -5955,7 +6521,9 @@ def constantSpeedRating_time(
5955
6521
  # BADAH or BADAE
5956
6522
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
5957
6523
  # compute Power required
5958
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
6524
+ Preq_i = AC.Preq(
6525
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
6526
+ )
5959
6527
  # compute ROCD
5960
6528
  ROCD_i = (
5961
6529
  conv.m2ft(
@@ -5988,15 +6556,21 @@ def constantSpeedRating_time(
5988
6556
  # ensure continuity of configuration change within the segment
5989
6557
  if config:
5990
6558
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5991
- phase=phase, previousConfig=config[-1], currentConfig=config_i
6559
+ phase=phase,
6560
+ previousConfig=config[-1],
6561
+ currentConfig=config_i,
5992
6562
  )
5993
6563
 
5994
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
6564
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
6565
+ config=config_i
6566
+ )
5995
6567
 
5996
6568
  # compute lift coefficient
5997
6569
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
5998
6570
  # compute drag coefficient
5999
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
6571
+ CD = AC.CD(
6572
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
6573
+ )
6000
6574
  # compute drag force
6001
6575
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
6002
6576
 
@@ -6037,7 +6611,10 @@ def constantSpeedRating_time(
6037
6611
  CL = AC.CL(tas=TAS_i, sigma=sigma, mass=mass_i, nz=nz)
6038
6612
  # compute drag coefficient
6039
6613
  CD = AC.CD(
6040
- CL=CL, config=config_i, expedite=expedite, speedBrakes=speedBrakes
6614
+ CL=CL,
6615
+ config=config_i,
6616
+ expedite=expedite,
6617
+ speedBrakes=speedBrakes,
6041
6618
  )
6042
6619
  # compute drag force
6043
6620
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
@@ -6167,12 +6744,18 @@ def constantSpeedRating_time(
6167
6744
  [theta, delta, sigma] = atm.atmosphereProperties(
6168
6745
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
6169
6746
  )
6170
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
6747
+ temp_const = (theta * const.temp_0) / (
6748
+ theta * const.temp_0 - DeltaTemp
6749
+ )
6171
6750
  if AC.BADAFamily.BADAE:
6172
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
6751
+ gamma_i = degrees(
6752
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
6753
+ )
6173
6754
  else:
6174
6755
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
6175
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
6756
+ gamma_i = degrees(
6757
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
6758
+ )
6176
6759
 
6177
6760
  # ground speed can be calcualted as TAS projected on the ground minus wind
6178
6761
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -6209,7 +6792,9 @@ def constantSpeedRating_time(
6209
6792
  if turnFlight:
6210
6793
  step_distance = conv.m2nm(
6211
6794
  turn.distance(
6212
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
6795
+ rateOfTurn=rateOfTurn,
6796
+ TAS=TAS_i,
6797
+ timeOfTurn=step_time,
6213
6798
  )
6214
6799
  ) # arcLength during the turn [NM]
6215
6800
  else:
@@ -6411,77 +6996,94 @@ def accDec(
6411
6996
  magneticDeclinationGrid=None,
6412
6997
  **kwargs,
6413
6998
  ):
6414
- """This function computes time and fuel required by an aircraft to perform an acceleration/deceleration from v_init to v_final in climb cruise or descent
6999
+ """
7000
+ Calculates the time, fuel consumption, and other key flight parameters required for an aircraft
7001
+ to perform an acceleration or deceleration from an initial speed (v_init) to a final speed (v_final)
7002
+ during the climb, cruise, or descent phases of flight.
7003
+
7004
+ The flight parameters are calculated using different models for the BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE).
7005
+ The function can also accommodate different control laws, vertical evolution phases, wind conditions, and complex flight dynamics like turns.
6415
7006
 
6416
7007
  .. note::
6417
- The control law used during the segment depends on the targets provided in input parameter 'control':
6418
- - ROCD/slope+ESF: law is ROCD/slope+ESF
6419
- - ROCD/slope+acc: law is ROCD/slope+acc
6420
- - ROCD/slope only: law is rating+ROCD/slope
6421
- - ESF only: law is rating+ESF
6422
- - acc only: law is rating+acc
6423
- - Neither: law is rating+default ESF
6424
-
6425
- :param AC: aircraft {BADA3/4/H/E}
6426
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
6427
- :param v_init: initial speed to follow - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
6428
- :param v_final: final speed to follow - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
6429
- :param phase: vertical evolution {Climb, Descent, Cruise}
6430
- :param control: structure containing a combination of the following targets:
6431
- :param ROCDtarget: Rate of climb/descent to be followed [ft/min].
6432
- :param slopetarget: slope (flight path angle) to be followed [deg].
6433
- :param acctarget: acceleration to be followed [m/s^2].
6434
- :param ESFtarget: Energy Share Factor to be followed [-].
6435
- :param maxRating: rating to be used as a limit on the maximum thrust/power [-].
6436
- :param Hp_init: initial pressure altitude [ft].
6437
- :param m_init: initial aircraft mass [kg].
6438
- :param DeltaTemp: deviation with respect to ISA [K].
6439
- :param wS: longitudinal wind speed (TAS) [kt].
6440
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
6441
- :param SOC_init: initial state of charge [%].
6442
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
6443
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
6444
- :param speed_step: step of the speed for the speed iteration loop [-] for M, [kt] for TAS or CAS
6445
- :param Lat: Geographical Latitude [deg]
6446
- :param Lon: Geographical Longitude [deg]
6447
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
6448
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
6449
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
6450
- :param m_iter: number of iterations for integration loop [-]
6451
- :param reducedPower: reduction of Power during the climb {True/False}
6452
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
6453
- :type speedType: string.
6454
- :type v_init: float.
6455
- :type v_final: float.
6456
- :type phase: string.
6457
- :type control: structure.
6458
- :type ROCDtarget: float.
6459
- :type slopetarget: float.
6460
- :type acctarget: float.
6461
- :type ESFtarget: float.
6462
- :type maxRating: float.
6463
- :type Hp_init: float.
6464
- :type m_init: float.
6465
- :type DeltaTemp: float.
6466
- :type wS: float.
6467
- :type turnMetrics: {float,float,string}.
6468
- :type SOC_init: float.
6469
- :type config: string.
6470
- :type speedBrakes: dict{boolean,float}.
6471
- :type speed_step: float.
6472
- :type Lat: float.
6473
- :type Lon: float.
6474
- :type initialHeading: {float,float,boolean}.
6475
- :type magneticDeclinationGrid: magneticDeclinationGrid.
6476
- :type mass_const: boolean.
6477
- :type m_iter: integer.
6478
- :type reducedPower: boolean.
6479
- :returns:
6480
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
6481
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
6482
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
6483
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
6484
- :rtype: dict[list[float]}.
7008
+ The control law used during the segment depends on the targets provided in the input parameter 'control':
7009
+ - ROCD/slope+ESF: Law based on ROCD/slope + ESF
7010
+ - ROCD/slope+acc: Law based on ROCD/slope + acceleration
7011
+ - ROCD/slope only: Law based on rating + ROCD/slope
7012
+ - ESF only: Law based on rating + ESF
7013
+ - acc only: Law based on rating + acceleration
7014
+ - Neither: Law is rating + default ESF
7015
+
7016
+ :param AC: Aircraft object {BADA3/4/H/E}.
7017
+ :param speedType: Type of speed being followed {M, CAS, TAS}.
7018
+ :param v_init: Initial speed [kt] (CAS/TAS) or [-] MACH.
7019
+ :param v_final: Final speed [kt] (CAS/TAS) or [-] MACH.
7020
+ :param phase: Vertical evolution phase {Climb, Descent, Cruise}.
7021
+ :param control: A dictionary containing the following targets:
7022
+ - ROCDtarget: Rate of climb/descent to be followed [ft/min].
7023
+ - slopetarget: Slope (flight path angle) to be followed [deg].
7024
+ - acctarget: Acceleration to be followed [m/s^2].
7025
+ - ESFtarget: Energy Share Factor to be followed [-].
7026
+ :param Hp_init: Initial pressure altitude [ft].
7027
+ :param m_init: Initial aircraft mass [kg].
7028
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
7029
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
7030
+ :param turnMetrics: A dictionary defining turn parameters:
7031
+ - rateOfTurn [deg/s]
7032
+ - bankAngle [deg]
7033
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
7034
+ :param Lat: Initial latitude [deg]. Default is None.
7035
+ :param Lon: Initial longitude [deg]. Default is None.
7036
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
7037
+ - magnetic: Magnetic heading [deg].
7038
+ - true: True heading [deg].
7039
+ - constantHeading: Whether to maintain a constant heading. Default is None.
7040
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
7041
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
7042
+ :param kwargs: Additional optional parameters:
7043
+ - speed_step: Speed step size for the iterative calculation [-] for M, [kt] for TAS/CAS. Default is 0.01 Mach, 5 kt for TAS/CAS.
7044
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
7045
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
7046
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
7047
+ - m_iter: Number of iterations for the mass integration loop. Default is 10 for BADA3/4/H, 5 for BADAE.
7048
+ :returns: A pandas DataFrame containing flight trajectory data with the following columns:
7049
+ - Hp: Pressure altitude [ft]
7050
+ - TAS: True Air Speed [kt]
7051
+ - CAS: Calibrated Air Speed [kt]
7052
+ - GS: Ground Speed [kt]
7053
+ - M: Mach number [-]
7054
+ - acc: Acceleration rate [m/s^2]
7055
+ - ROCD: Rate of climb/descent [ft/min]
7056
+ - ESF: Energy Share Factor [-]
7057
+ - FUEL: Fuel flow [kg/s]
7058
+ - FUELCONSUMED: Total fuel consumed [kg]
7059
+ - THR: Thrust force [N]
7060
+ - DRAG: Drag force [N]
7061
+ - time: Elapsed time [s]
7062
+ - dist: Distance flown [NM]
7063
+ - slope: Flight trajectory slope (angle) [deg]
7064
+ - mass: Aircraft mass [kg]
7065
+ - config: Aerodynamic configuration
7066
+ - LAT: Latitude [deg]
7067
+ - LON: Longitude [deg]
7068
+ - HDGTrue: True heading [deg]
7069
+ - HDGMagnetic: Magnetic heading [deg]
7070
+ - BankAngle: Bank angle during the turn [deg]
7071
+ - ROT: Rate of turn [deg/s]
7072
+ - Comment: Comments describing the flight segment
7073
+ - For BADAH:
7074
+ - Preq: Required power for level flight [W]
7075
+ - Peng: Generated power [W]
7076
+ - Pav: Available power [W]
7077
+ - For BADAE (electric aircraft):
7078
+ - Pmec: Mechanical power [W]
7079
+ - Pelc: Electrical power [W]
7080
+ - Pbat: Battery power [W]
7081
+ - SOCr: Rate of battery state of charge depletion [%/h]
7082
+ - SOC: Battery state of charge [%]
7083
+ - Ibat: Battery current [A]
7084
+ - Vbat: Battery voltage [V]
7085
+ - Vgbat: Ground battery voltage [V]
7086
+ :rtype: pandas.DataFrame
6485
7087
  """
6486
7088
 
6487
7089
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -6532,7 +7134,9 @@ def accDec(
6532
7134
 
6533
7135
  # speed brakes application
6534
7136
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
6535
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
7137
+ speedBrakes = kwargs.get(
7138
+ "speedBrakes", {"deployed": False, "value": 0.03}
7139
+ )
6536
7140
 
6537
7141
  # iteratin step of speed loop
6538
7142
  if speedType == "M":
@@ -6543,7 +7147,9 @@ def accDec(
6543
7147
  # number of iteration of mass/altitude loop
6544
7148
  # BADAE
6545
7149
  if AC.BADAFamily.BADAE:
6546
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
7150
+ m_iter = kwargs.get(
7151
+ "m_iter", 5
7152
+ ) # number of iterations for integration loop[-]
6547
7153
  # BADA3 or BADA4 or BADAH
6548
7154
  else:
6549
7155
  m_iter = kwargs.get(
@@ -6700,9 +7306,9 @@ def accDec(
6700
7306
  maxRating = checkArgument("maxRating", **kwargs)
6701
7307
 
6702
7308
  # Determine engine rating
6703
- if (control.ROCDtarget is not None or control.slopetarget is not None) and (
6704
- control.ESFtarget is not None or control.acctarget is not None
6705
- ):
7309
+ if (
7310
+ control.ROCDtarget is not None or control.slopetarget is not None
7311
+ ) and (control.ESFtarget is not None or control.acctarget is not None):
6706
7312
  rating = None
6707
7313
  else:
6708
7314
  if phase == "Climb" or (phase == "Cruise" and speedEvol == "acc"):
@@ -6806,18 +7412,28 @@ def accDec(
6806
7412
  for _ in itertools.repeat(None, m_iter):
6807
7413
  # atmosphere properties
6808
7414
  H_m = conv.ft2m(Hp_i) # altitude [m]
6809
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
6810
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
7415
+ [theta, delta, sigma] = atm.atmosphereProperties(
7416
+ h=H_m, DeltaTemp=DeltaTemp
7417
+ )
7418
+ temp_const = (theta * const.temp_0) / (
7419
+ theta * const.temp_0 - DeltaTemp
7420
+ )
6811
7421
 
6812
7422
  # aircraft speed
6813
7423
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
6814
- v=v_i, speedType=speedType, theta=theta, delta=delta, sigma=sigma
7424
+ v=v_i,
7425
+ speedType=speedType,
7426
+ theta=theta,
7427
+ delta=delta,
7428
+ sigma=sigma,
6815
7429
  )
6816
7430
 
6817
7431
  if turnFlight:
6818
7432
  if turnMetrics["bankAngle"] != 0.0:
6819
7433
  # bankAngle is defined
6820
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
7434
+ rateOfTurn = AC.rateOfTurn_bankAngle(
7435
+ TAS=TAS_i, bankAngle=bankAngle
7436
+ )
6821
7437
  else:
6822
7438
  # rateOfTurn is defined
6823
7439
  bankAngle = AC.bankAngle(
@@ -6845,7 +7461,9 @@ def accDec(
6845
7461
  # BADAH or BADAE
6846
7462
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
6847
7463
  # compute Power required
6848
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
7464
+ Preq_i = AC.Preq(
7465
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
7466
+ )
6849
7467
 
6850
7468
  # compute engine power
6851
7469
  if rating is None:
@@ -6863,11 +7481,17 @@ def accDec(
6863
7481
 
6864
7482
  # Check that required thrust/power fits in the available thrust/power envelope,
6865
7483
  # recompute ROCD if necessary and compute fuel coefficient accordingly
6866
- Pmin = 0.1 * AC.P0 # No minimum power model: assume 10% torque
7484
+ Pmin = (
7485
+ 0.1 * AC.P0
7486
+ ) # No minimum power model: assume 10% torque
6867
7487
 
6868
7488
  if AC.BADAFamily.BADAH:
6869
- Pmax = AC.Pav(rating=maxRating, theta=theta, delta=delta)
6870
- Pav_i = AC.Pav(rating=maxRating, theta=theta, delta=delta)
7489
+ Pmax = AC.Pav(
7490
+ rating=maxRating, theta=theta, delta=delta
7491
+ )
7492
+ Pav_i = AC.Pav(
7493
+ rating=maxRating, theta=theta, delta=delta
7494
+ )
6871
7495
  elif AC.BADAFamily.BADAE:
6872
7496
  Pmax = AC.Pav(rating=maxRating, SOC=SOC[-1])
6873
7497
  Pav_i = AC.Pav(rating=maxRating, SOC=SOC[-1])
@@ -6892,7 +7516,11 @@ def accDec(
6892
7516
  elif control.acctarget is not None:
6893
7517
  ROCD_i = (
6894
7518
  conv.m2ft(
6895
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
7519
+ (
7520
+ P_i
7521
+ - mass_i * TAS_i * control.acctarget
7522
+ - Preq_i
7523
+ )
6896
7524
  / (mass_i * const.g * temp_const)
6897
7525
  )
6898
7526
  * 60
@@ -6918,7 +7546,11 @@ def accDec(
6918
7546
  elif control.acctarget is not None:
6919
7547
  ROCD_i = (
6920
7548
  conv.m2ft(
6921
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
7549
+ (
7550
+ P_i
7551
+ - mass_i * TAS_i * control.acctarget
7552
+ - Preq_i
7553
+ )
6922
7554
  / (mass_i * const.g * temp_const)
6923
7555
  )
6924
7556
  * 60
@@ -6929,12 +7561,20 @@ def accDec(
6929
7561
  else:
6930
7562
  # Compute available power
6931
7563
  if rating == "UNKNOWN":
6932
- P_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
6933
- Pav_i = AC.Pav(rating=maxRating, theta=theta, delta=delta)
7564
+ P_i = (
7565
+ 0.1 * AC.P0
7566
+ ) # No minimum power model: assume 10% torque
7567
+ Pav_i = AC.Pav(
7568
+ rating=maxRating, theta=theta, delta=delta
7569
+ )
6934
7570
  else:
6935
7571
  if AC.BADAFamily.BADAH:
6936
- P_i = AC.Pav(rating=rating, theta=theta, delta=delta)
6937
- Pav_i = AC.Pav(rating=rating, theta=theta, delta=delta)
7572
+ P_i = AC.Pav(
7573
+ rating=rating, theta=theta, delta=delta
7574
+ )
7575
+ Pav_i = AC.Pav(
7576
+ rating=rating, theta=theta, delta=delta
7577
+ )
6938
7578
  elif AC.BADAFamily.BADAE:
6939
7579
  P_i = AC.Pav(rating=rating, SOC=SOC[-1])
6940
7580
  Pav_i = AC.Pav(rating=rating, SOC=SOC[-1])
@@ -6957,7 +7597,9 @@ def accDec(
6957
7597
  Pelc_i = P_i / AC.eta
6958
7598
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
6959
7599
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
6960
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
7600
+ Vgbat_i = (
7601
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
7602
+ )
6961
7603
 
6962
7604
  # BADA4
6963
7605
  elif AC.BADAFamily.BADA4:
@@ -6976,15 +7618,21 @@ def accDec(
6976
7618
  # ensure continuity of configuration change within the segment
6977
7619
  if config:
6978
7620
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
6979
- phase=phase, previousConfig=config[-1], currentConfig=config_i
7621
+ phase=phase,
7622
+ previousConfig=config[-1],
7623
+ currentConfig=config_i,
6980
7624
  )
6981
7625
 
6982
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
7626
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
7627
+ config=config_i
7628
+ )
6983
7629
 
6984
7630
  # compute lift coefficient
6985
7631
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
6986
7632
  # compute drag coefficient
6987
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
7633
+ CD = AC.CD(
7634
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
7635
+ )
6988
7636
  # compute drag force
6989
7637
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
6990
7638
 
@@ -7044,7 +7692,11 @@ def accDec(
7044
7692
  else:
7045
7693
  CT = AC.CT(Thrust=THR_i, delta=delta)
7046
7694
  FUEL_i = AC.ff(
7047
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
7695
+ CT=CT,
7696
+ delta=delta,
7697
+ theta=theta,
7698
+ M=M_i,
7699
+ DeltaTemp=DeltaTemp,
7048
7700
  )
7049
7701
  else:
7050
7702
  THR_i = AC.Thrust(
@@ -7056,7 +7708,11 @@ def accDec(
7056
7708
  ) # [N]
7057
7709
  CT = AC.CT(Thrust=THR_i, delta=delta)
7058
7710
  FUEL_i = AC.ff(
7059
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
7711
+ CT=CT,
7712
+ delta=delta,
7713
+ theta=theta,
7714
+ M=M_i,
7715
+ DeltaTemp=DeltaTemp,
7060
7716
  )
7061
7717
 
7062
7718
  # compute excess power
@@ -7111,7 +7767,11 @@ def accDec(
7111
7767
  # recompute ROCD if necessary and compute fuel flow accordingly
7112
7768
 
7113
7769
  THR_min = AC.Thrust(
7114
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
7770
+ rating="LIDL",
7771
+ v=TAS_i,
7772
+ h=H_m,
7773
+ config="CR",
7774
+ DeltaTemp=DeltaTemp,
7115
7775
  ) # IDLE Thrust
7116
7776
  FUEL_min = AC.ff(
7117
7777
  flightPhase="Descent",
@@ -7122,7 +7782,11 @@ def accDec(
7122
7782
  adapted=False,
7123
7783
  ) # IDLE Fuel Flow
7124
7784
  THR_max = AC.Thrust(
7125
- rating="MCMB", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
7785
+ rating="MCMB",
7786
+ v=TAS_i,
7787
+ h=H_m,
7788
+ config="CR",
7789
+ DeltaTemp=DeltaTemp,
7126
7790
  ) # MCMB Thrust
7127
7791
  FUEL_max = AC.ff(
7128
7792
  flightPhase="Climb",
@@ -7141,7 +7805,11 @@ def accDec(
7141
7805
  FUEL_i = FUEL_max
7142
7806
  else:
7143
7807
  FUEL_i = AC.ff(
7144
- v=TAS_i, h=H_m, T=THR_i, config=config_i, adapted=True
7808
+ v=TAS_i,
7809
+ h=H_m,
7810
+ T=THR_i,
7811
+ config=config_i,
7812
+ adapted=True,
7145
7813
  )
7146
7814
  else:
7147
7815
  THR_i = AC.Thrust(
@@ -7206,7 +7874,10 @@ def accDec(
7206
7874
  dhdtisu = PC_i / (mass_i * const.g) # [m/s]
7207
7875
  ROCDisu = dhdtisu * 1 / temp_const # [m/s]
7208
7876
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
7209
- elif control.slopetarget is not None or control.ROCDtarget is not None:
7877
+ elif (
7878
+ control.slopetarget is not None
7879
+ or control.ROCDtarget is not None
7880
+ ):
7210
7881
  dhdtisu = dh_dt_i # [m/s]
7211
7882
  ROCDisu = dh_dt_i * 1 / temp_const # [m/s]
7212
7883
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
@@ -7309,7 +7980,10 @@ def accDec(
7309
7980
  # BADAH or BADAE
7310
7981
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
7311
7982
  check.append(
7312
- P_i - Preq_i - mass_i * const.g * dhdtisu - mass_i * TAS_i * dVdtisu_i
7983
+ P_i
7984
+ - Preq_i
7985
+ - mass_i * const.g * dhdtisu
7986
+ - mass_i * TAS_i * dVdtisu_i
7313
7987
  )
7314
7988
 
7315
7989
  # BADA3 or BADA4
@@ -7327,12 +8001,18 @@ def accDec(
7327
8001
  [theta, delta, sigma] = atm.atmosphereProperties(
7328
8002
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
7329
8003
  )
7330
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
8004
+ temp_const = (theta * const.temp_0) / (
8005
+ theta * const.temp_0 - DeltaTemp
8006
+ )
7331
8007
  if AC.BADAFamily.BADAE:
7332
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
8008
+ gamma_i = degrees(
8009
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
8010
+ )
7333
8011
  else:
7334
8012
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
7335
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
8013
+ gamma_i = degrees(
8014
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
8015
+ )
7336
8016
 
7337
8017
  # ground speed can be calcualted as TAS projected on the ground minus wind
7338
8018
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -7427,14 +8107,16 @@ def accDec(
7427
8107
 
7428
8108
  else:
7429
8109
  # calculate the turn
7430
- (Lat_i, Lon_i, HDGTrue_i) = turn.destinationPoint_finalBearing(
7431
- LAT_init=LAT[-1],
7432
- LON_init=LON[-1],
7433
- bearingInit=HDGTrue[-1],
7434
- TAS=TAS_i,
7435
- rateOfTurn=rateOfTurn,
7436
- timeOfTurn=step_time,
7437
- directionOfTurn=directionOfTurn,
8110
+ (Lat_i, Lon_i, HDGTrue_i) = (
8111
+ turn.destinationPoint_finalBearing(
8112
+ LAT_init=LAT[-1],
8113
+ LON_init=LON[-1],
8114
+ bearingInit=HDGTrue[-1],
8115
+ TAS=TAS_i,
8116
+ rateOfTurn=rateOfTurn,
8117
+ timeOfTurn=step_time,
8118
+ directionOfTurn=directionOfTurn,
8119
+ )
7438
8120
  )
7439
8121
 
7440
8122
  if magneticDeclinationGrid is not None:
@@ -7472,14 +8154,16 @@ def accDec(
7472
8154
 
7473
8155
  else:
7474
8156
  # calculate the turn
7475
- (Lat_i, Lon_i, HDGTrue_i) = turn.destinationPoint_finalBearing(
7476
- LAT_init=LAT[-1],
7477
- LON_init=LON[-1],
7478
- bearingInit=HDGTrue[-1],
7479
- TAS=TAS_i,
7480
- rateOfTurn=rateOfTurn,
7481
- timeOfTurn=step_time,
7482
- directionOfTurn=directionOfTurn,
8157
+ (Lat_i, Lon_i, HDGTrue_i) = (
8158
+ turn.destinationPoint_finalBearing(
8159
+ LAT_init=LAT[-1],
8160
+ LON_init=LON[-1],
8161
+ bearingInit=HDGTrue[-1],
8162
+ TAS=TAS_i,
8163
+ rateOfTurn=rateOfTurn,
8164
+ timeOfTurn=step_time,
8165
+ directionOfTurn=directionOfTurn,
8166
+ )
7483
8167
  )
7484
8168
 
7485
8169
  if magneticDeclinationGrid is not None:
@@ -7580,79 +8264,95 @@ def accDec_time(
7580
8264
  magneticDeclinationGrid=None,
7581
8265
  **kwargs,
7582
8266
  ):
7583
- """This function computes time and fuel required by an aircraft to perform an acceleration/deceleration from v_init for set amount of time in climb cruise or descent
8267
+ """
8268
+ Calculates the time, fuel consumption, and other key flight parameters required for an aircraft
8269
+ to perform an acceleration or deceleration from an initial speed (v_init) over a set period of time
8270
+ during the climb, cruise, or descent phases of flight.
8271
+
8272
+ The flight parameters are calculated using different models for the BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE).
8273
+ The function can also accommodate different control laws, vertical evolution phases, wind conditions, and complex flight dynamics like turns.
7584
8274
 
7585
8275
  .. note::
7586
- The control law used during the segment depends on the targets provided in input parameter 'control':
7587
- - ROCD/slope+ESF: law is ROCD/slope+ESF
7588
- - ROCD/slope+acc: law is ROCD/slope+acc
7589
- - ROCD/slope only: law is rating+ROCD/slope
7590
- - ESF only: law is rating+ESF
7591
- - acc only: law is rating+acc
7592
- - Neither: law is rating+default ESF
7593
-
7594
- :param AC: aircraft {BADA3/4/H/E}
7595
- :param speedType: what kind of speed is followed {M, CAS, TAS}.
7596
- :param length: length of a segment to fly [s]
7597
- :param step_length: length of a step of a segment - [s]
7598
- :param v_init: initial speed to follow - [kt] CAS/TAS speed to follow or [-] MACH speed to follow.
7599
- :param speedEvol: speed evolution {acc, dec}
7600
- :param phase: vertical evolution {Climb, Descent, Cruise}
7601
- :param control: structure containing a combination of the following targets:
7602
- :param ROCDtarget: Rate of climb/descent to be followed [ft/min].
7603
- :param slopetarget: slope (flight path angle) to be followed [deg].
7604
- :param acctarget: acceleration to be followed [m/s^2].
7605
- :param ESFtarget: Energy Share Factor to be followed [-].
7606
- :param maxRating: rating to be used as a limit on the maximum thrust/power [-].
7607
- :param Hp_init: initial pressure altitude [ft].
7608
- :param m_init: initial aircraft mass [kg].
7609
- :param DeltaTemp: deviation with respect to ISA [K].
7610
- :param wS: longitudinal wind speed (TAS) [kt].
7611
- :param turnMetrics: Metrics for turn performance {"rateOfTurn":0.0,"bankAngle":0.0,"directionOfTurn":None} {[deg/s],[deg],[LEFT/RIGHT]}
7612
- :param SOC_init: initial state of charge [%].
7613
- :param config: aircraft default aerodynamic configuration {TO,IC,CR,AP,LD}.
7614
- :param speedBrakes: deployed or not speedbrakes including value to be added to the drag coeffcient {deployed:False,value:0.03} {deployed:[True/False],value:[-]}.
7615
- :param Lat: Geographical Latitude [deg]
7616
- :param Lon: Geographical Longitude [deg]
7617
- :param initialHeading: aircraft magnetic heading, true heading and definition of constant heading(ORTHODROME=False, LOXODROME=True) {[deg],[deg],-}
7618
- :param magneticDeclinationGrid: geographical grid of a magnetic declination on Earth [deg]
7619
- :param mass_const: kind of mass canculation {mass_integrated=False, mass_constant=True}.
7620
- :param m_iter: number of iterations for integration loop [-]
7621
- :param reducedPower: reduction of Power during the climb {True/False}
7622
- :type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
7623
- :type speedType: string.
7624
- :type length: float.
7625
- :type step_length: float.
7626
- :type v_init: float.
7627
- :type speedEvol: string.
7628
- :type phase: string.
7629
- :type control: structure.
7630
- :type ROCDtarget: float.
7631
- :type slopetarget: float.
7632
- :type acctarget: float.
7633
- :type ESFtarget: float.
7634
- :type maxRating: float.
7635
- :type Hp_init: float.
7636
- :type m_init: float.
7637
- :type DeltaTemp: float.
7638
- :type wS: float.
7639
- :type turnMetrics: {float,float,string}.
7640
- :type SOC_init: float.
7641
- :type config: string.
7642
- :type speedBrakes: dict{boolean,float}.
7643
- :type Lat: float.
7644
- :type Lon: float.
7645
- :type initialHeading: {float,float,boolean}.
7646
- :type magneticDeclinationGrid: magneticDeclinationGrid.
7647
- :type mass_const: boolean.
7648
- :type m_iter: integer.
7649
- :type reducedPower: boolean.
7650
- :returns:
7651
- BADA3: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, time, dist, slope, mass, config, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, s, NM, deg, kg, -, -,deg,deg,deg,deg,deg,deg/s]
7652
- BADA4: [Hp, TAS, CAS, M, GS, acc, ROCD, ESF, FUEL, FUELCONSUMED, THR, P[Pmec, Pbat, Pelc Ibat, Vbat, Vgbat, SOCr, SOC], time, dist, slope, mass, config, HLid, LG, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, N, [W,W,W,A,V,V,%/h,%], s, NM, deg, kg, -, -, -, -,deg,deg,deg,deg,deg,deg/s]
7653
- BADAH: [Hp, TAS, CAS, M, GS, ROCD, ESF, FUEL, FUELCONSUMED, Peng, Preq, Pav, time, dist, slope, mass, comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [ft, kt, kt, -, kt, m/s^2, ft/min, kg/s, kg, W, W, W, s, NM, deg, kg, -,deg,deg,deg,deg,deg,deg/s]
7654
- BADAE: [time, dist, Hp, TAS, CAS, M, GS, acc, ROCD, ESF, slope, mass, P[Pmec, Pelc, Pbat, SOCr, SOC, Ibat, Vbat, Vgbat] comment, LAT, LON, HDGMagnetic, HDGTrue, bank angle, ROT] [s, NM, ft, kt, kt, -, kt, m/s^2, ft/min, deg, kg, [W,W,W,%/h,%,A,V,V], -,deg,deg,deg,deg,deg,deg/s]
7655
- :rtype: dict[list[float]}.
8276
+ The control law used during the segment depends on the targets provided in the input parameter 'control':
8277
+ - ROCD/slope+ESF: Law based on ROCD/slope + ESF
8278
+ - ROCD/slope+acc: Law based on ROCD/slope + acceleration
8279
+ - ROCD/slope only: Law based on rating + ROCD/slope
8280
+ - ESF only: Law based on rating + ESF
8281
+ - acc only: Law based on rating + acceleration
8282
+ - Neither: Law is rating + default ESF
8283
+
8284
+ :param AC: Aircraft object {BADA3/4/H/E}.
8285
+ :param length: Total duration of the flight segment [s].
8286
+ :param speedType: Type of speed being followed {M, CAS, TAS}.
8287
+ :param v_init: Initial speed [kt] (CAS/TAS) or [-] MACH.
8288
+ :param speedEvol: Evolution of speed {acc, dec} (acceleration or deceleration).
8289
+ :param phase: Vertical evolution phase {Climb, Descent, Cruise}.
8290
+ :param control: A dictionary containing the following targets:
8291
+ - ROCDtarget: Rate of climb/descent to be followed [ft/min].
8292
+ - slopetarget: Slope (flight path angle) to be followed [deg].
8293
+ - acctarget: Acceleration to be followed [m/s^2].
8294
+ - ESFtarget: Energy Share Factor to be followed [-].
8295
+ :param Hp_init: Initial pressure altitude [ft].
8296
+ :param m_init: Initial aircraft mass [kg].
8297
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
8298
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
8299
+ :param turnMetrics: A dictionary defining turn parameters:
8300
+ - rateOfTurn [deg/s]
8301
+ - bankAngle [deg]
8302
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
8303
+ :param Lat: Initial latitude [deg]. Default is None.
8304
+ :param Lon: Initial longitude [deg]. Default is None.
8305
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
8306
+ - magnetic: Magnetic heading [deg].
8307
+ - true: True heading [deg].
8308
+ - constantHeading: Whether to maintain a constant heading. Default is None.
8309
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
8310
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
8311
+ :param kwargs: Additional optional parameters:
8312
+ - step_length: Length of each time step in the calculation [s]. Default is 1 second.
8313
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
8314
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
8315
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
8316
+ - m_iter: Number of iterations for the mass integration loop. Default is 10 for BADA3/4/H, 5 for BADAE.
8317
+ :returns: A pandas DataFrame containing flight trajectory data with the following columns:
8318
+ - Hp: Pressure altitude [ft]
8319
+ - TAS: True Air Speed [kt]
8320
+ - CAS: Calibrated Air Speed [kt]
8321
+ - GS: Ground Speed [kt]
8322
+ - M: Mach number [-]
8323
+ - acc: Acceleration rate [m/s^2]
8324
+ - ROCD: Rate of climb/descent [ft/min]
8325
+ - ESF: Energy Share Factor [-]
8326
+ - FUEL: Fuel flow [kg/s]
8327
+ - FUELCONSUMED: Total fuel consumed [kg]
8328
+ - THR: Thrust force [N]
8329
+ - DRAG: Drag force [N]
8330
+ - time: Elapsed time [s]
8331
+ - dist: Distance flown [NM]
8332
+ - slope: Flight trajectory slope (angle) [deg]
8333
+ - mass: Aircraft mass [kg]
8334
+ - config: Aerodynamic configuration
8335
+ - LAT: Latitude [deg]
8336
+ - LON: Longitude [deg]
8337
+ - HDGTrue: True heading [deg]
8338
+ - HDGMagnetic: Magnetic heading [deg]
8339
+ - BankAngle: Bank angle during the turn [deg]
8340
+ - ROT: Rate of turn [deg/s]
8341
+ - Comment: Comments describing the flight segment
8342
+ - For BADAH:
8343
+ - Preq: Required power for level flight [W]
8344
+ - Peng: Generated power [W]
8345
+ - Pav: Available power [W]
8346
+ - For BADAE (electric aircraft):
8347
+ - Pmec: Mechanical power [W]
8348
+ - Pelc: Electrical power [W]
8349
+ - Pbat: Battery power [W]
8350
+ - SOCr: Rate of battery state of charge depletion [%/h]
8351
+ - SOC: Battery state of charge [%]
8352
+ - Ibat: Battery current [A]
8353
+ - Vbat: Battery voltage [V]
8354
+ - Vgbat: Ground battery voltage [V]
8355
+ :rtype: pandas.DataFrame
7656
8356
  """
7657
8357
 
7658
8358
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -7703,7 +8403,9 @@ def accDec_time(
7703
8403
 
7704
8404
  # speed brakes application
7705
8405
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
7706
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
8406
+ speedBrakes = kwargs.get(
8407
+ "speedBrakes", {"deployed": False, "value": 0.03}
8408
+ )
7707
8409
 
7708
8410
  # step size in [s]
7709
8411
  step_length = kwargs.get("step_length", 1)
@@ -7711,7 +8413,9 @@ def accDec_time(
7711
8413
  # number of iteration of mass/altitude loop
7712
8414
  # BADAE
7713
8415
  if AC.BADAFamily.BADAE:
7714
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
8416
+ m_iter = kwargs.get(
8417
+ "m_iter", 5
8418
+ ) # number of iterations for integration loop[-]
7715
8419
  # BADA3 or BADA4 or BADAH
7716
8420
  else:
7717
8421
  m_iter = kwargs.get(
@@ -7861,9 +8565,9 @@ def accDec_time(
7861
8565
  maxRating = checkArgument("maxRating", **kwargs)
7862
8566
 
7863
8567
  # Determine engine rating
7864
- if (control.ROCDtarget is not None or control.slopetarget is not None) and (
7865
- control.ESFtarget is not None or control.acctarget is not None
7866
- ):
8568
+ if (
8569
+ control.ROCDtarget is not None or control.slopetarget is not None
8570
+ ) and (control.ESFtarget is not None or control.acctarget is not None):
7867
8571
  rating = None
7868
8572
  else:
7869
8573
  if phase == "Climb" or (phase == "Cruise" and speedEvol == "acc"):
@@ -7981,8 +8685,12 @@ def accDec_time(
7981
8685
  for _ in itertools.repeat(None, m_iter):
7982
8686
  # atmosphere properties
7983
8687
  H_m = conv.ft2m(Hp_i) # altitude [m]
7984
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
7985
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
8688
+ [theta, delta, sigma] = atm.atmosphereProperties(
8689
+ h=H_m, DeltaTemp=DeltaTemp
8690
+ )
8691
+ temp_const = (theta * const.temp_0) / (
8692
+ theta * const.temp_0 - DeltaTemp
8693
+ )
7986
8694
 
7987
8695
  step_time = length_loop - time[-1]
7988
8696
 
@@ -7994,7 +8702,9 @@ def accDec_time(
7994
8702
  if turnFlight:
7995
8703
  if turnMetrics["bankAngle"] != 0.0:
7996
8704
  # bankAngle is defined
7997
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
8705
+ rateOfTurn = AC.rateOfTurn_bankAngle(
8706
+ TAS=TAS_i, bankAngle=bankAngle
8707
+ )
7998
8708
  else:
7999
8709
  # rateOfTurn is defined
8000
8710
  bankAngle = AC.bankAngle(
@@ -8021,7 +8731,9 @@ def accDec_time(
8021
8731
  # BADAH or BADAE
8022
8732
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
8023
8733
  # compute Power required
8024
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
8734
+ Preq_i = AC.Preq(
8735
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
8736
+ )
8025
8737
 
8026
8738
  # compute engine power
8027
8739
  if rating is None:
@@ -8039,11 +8751,17 @@ def accDec_time(
8039
8751
 
8040
8752
  # Check that required thrust/power fits in the available thrust/power envelope,
8041
8753
  # recompute ROCD if necessary and compute fuel coefficient accordingly
8042
- Pmin = 0.1 * AC.P0 # No minimum power model: assume 10% torque
8754
+ Pmin = (
8755
+ 0.1 * AC.P0
8756
+ ) # No minimum power model: assume 10% torque
8043
8757
 
8044
8758
  if AC.BADAFamily.BADAH:
8045
- Pmax = AC.Pav(rating=maxRating, theta=theta, delta=delta)
8046
- Pav_i = AC.Pav(rating=maxRating, theta=theta, delta=delta)
8759
+ Pmax = AC.Pav(
8760
+ rating=maxRating, theta=theta, delta=delta
8761
+ )
8762
+ Pav_i = AC.Pav(
8763
+ rating=maxRating, theta=theta, delta=delta
8764
+ )
8047
8765
  elif AC.BADAFamily.BADAE:
8048
8766
  Pmax = AC.Pav(rating=maxRating, SOC=SOC[-1])
8049
8767
  Pav_i = AC.Pav(rating=maxRating, SOC=SOC[-1])
@@ -8068,7 +8786,11 @@ def accDec_time(
8068
8786
  elif control.acctarget is not None:
8069
8787
  ROCD_i = (
8070
8788
  conv.m2ft(
8071
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
8789
+ (
8790
+ P_i
8791
+ - mass_i * TAS_i * control.acctarget
8792
+ - Preq_i
8793
+ )
8072
8794
  / (mass_i * const.g * temp_const)
8073
8795
  )
8074
8796
  * 60
@@ -8093,7 +8815,11 @@ def accDec_time(
8093
8815
  elif control.acctarget is not None:
8094
8816
  ROCD_i = (
8095
8817
  conv.m2ft(
8096
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
8818
+ (
8819
+ P_i
8820
+ - mass_i * TAS_i * control.acctarget
8821
+ - Preq_i
8822
+ )
8097
8823
  / (mass_i * const.g * temp_const)
8098
8824
  )
8099
8825
  * 60
@@ -8104,12 +8830,20 @@ def accDec_time(
8104
8830
  else:
8105
8831
  # Compute available power
8106
8832
  if rating == "UNKNOWN":
8107
- P_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
8108
- Pav_i = AC.Pav(rating=maxRating, theta=theta, delta=delta)
8833
+ P_i = (
8834
+ 0.1 * AC.P0
8835
+ ) # No minimum power model: assume 10% torque
8836
+ Pav_i = AC.Pav(
8837
+ rating=maxRating, theta=theta, delta=delta
8838
+ )
8109
8839
  else:
8110
8840
  if AC.BADAFamily.BADAH:
8111
- P_i = AC.Pav(rating=rating, theta=theta, delta=delta)
8112
- Pav_i = AC.Pav(rating=rating, theta=theta, delta=delta)
8841
+ P_i = AC.Pav(
8842
+ rating=rating, theta=theta, delta=delta
8843
+ )
8844
+ Pav_i = AC.Pav(
8845
+ rating=rating, theta=theta, delta=delta
8846
+ )
8113
8847
  elif AC.BADAFamily.BADAE:
8114
8848
  P_i = AC.Pav(rating=rating, SOC=SOC[-1])
8115
8849
  Pav_i = AC.Pav(rating=rating, SOC=SOC[-1])
@@ -8132,7 +8866,9 @@ def accDec_time(
8132
8866
  Pelc_i = P_i / AC.eta
8133
8867
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
8134
8868
  Vbat_i = AC.Vbat(I=Ibat_i, SOC=SOC[-1])
8135
- Vgbat_i = AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
8869
+ Vgbat_i = (
8870
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
8871
+ )
8136
8872
 
8137
8873
  # BADA4
8138
8874
  elif AC.BADAFamily.BADA4:
@@ -8151,15 +8887,21 @@ def accDec_time(
8151
8887
  # ensure continuity of configuration change within the segment
8152
8888
  if config:
8153
8889
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
8154
- phase=phase, previousConfig=config[-1], currentConfig=config_i
8890
+ phase=phase,
8891
+ previousConfig=config[-1],
8892
+ currentConfig=config_i,
8155
8893
  )
8156
8894
 
8157
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
8895
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
8896
+ config=config_i
8897
+ )
8158
8898
 
8159
8899
  # compute lift coefficient
8160
8900
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
8161
8901
  # compute drag coefficient
8162
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
8902
+ CD = AC.CD(
8903
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
8904
+ )
8163
8905
  # compute drag force
8164
8906
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
8165
8907
 
@@ -8219,7 +8961,11 @@ def accDec_time(
8219
8961
  else:
8220
8962
  CT = AC.CT(Thrust=THR_i, delta=delta)
8221
8963
  FUEL_i = AC.ff(
8222
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
8964
+ CT=CT,
8965
+ delta=delta,
8966
+ theta=theta,
8967
+ M=M_i,
8968
+ DeltaTemp=DeltaTemp,
8223
8969
  )
8224
8970
  else:
8225
8971
  THR_i = AC.Thrust(
@@ -8293,7 +9039,11 @@ def accDec_time(
8293
9039
  # recompute ROCD if necessary and compute fuel flow accordingly
8294
9040
 
8295
9041
  THR_min = AC.Thrust(
8296
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
9042
+ rating="LIDL",
9043
+ v=TAS_i,
9044
+ h=H_m,
9045
+ config="CR",
9046
+ DeltaTemp=DeltaTemp,
8297
9047
  ) # IDLE Thrust
8298
9048
  FUEL_min = AC.ff(
8299
9049
  flightPhase="Descent",
@@ -8304,7 +9054,11 @@ def accDec_time(
8304
9054
  adapted=False,
8305
9055
  ) # IDLE Fuel Flow
8306
9056
  THR_max = AC.Thrust(
8307
- rating="MCMB", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
9057
+ rating="MCMB",
9058
+ v=TAS_i,
9059
+ h=H_m,
9060
+ config="CR",
9061
+ DeltaTemp=DeltaTemp,
8308
9062
  ) # MCMB Thrust
8309
9063
  FUEL_max = AC.ff(
8310
9064
  flightPhase="Climb",
@@ -8323,7 +9077,11 @@ def accDec_time(
8323
9077
  FUEL_i = FUEL_max
8324
9078
  else:
8325
9079
  FUEL_i = AC.ff(
8326
- v=TAS_i, h=H_m, T=THR_i, config=config_i, adapted=True
9080
+ v=TAS_i,
9081
+ h=H_m,
9082
+ T=THR_i,
9083
+ config=config_i,
9084
+ adapted=True,
8327
9085
  )
8328
9086
  else:
8329
9087
  THR_i = AC.Thrust(
@@ -8386,7 +9144,10 @@ def accDec_time(
8386
9144
  dhdtisu = PC_i / (mass_i * const.g) # [m/s]
8387
9145
  ROCDisu = dhdtisu * 1 / temp_const # [m/s]
8388
9146
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
8389
- elif control.slopetarget is not None or control.ROCDtarget is not None:
9147
+ elif (
9148
+ control.slopetarget is not None
9149
+ or control.ROCDtarget is not None
9150
+ ):
8390
9151
  dhdtisu = dh_dt_i # [m/s]
8391
9152
  ROCDisu = dh_dt_i * 1 / temp_const # [m/s]
8392
9153
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
@@ -8487,7 +9248,10 @@ def accDec_time(
8487
9248
  # BADAH or BADAE
8488
9249
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
8489
9250
  check.append(
8490
- P_i - Preq_i - mass_i * const.g * dhdtisu - mass_i * TAS_i * dVdtisu_i
9251
+ P_i
9252
+ - Preq_i
9253
+ - mass_i * const.g * dhdtisu
9254
+ - mass_i * TAS_i * dVdtisu_i
8491
9255
  )
8492
9256
 
8493
9257
  # BADA3 or BADA4
@@ -8505,12 +9269,18 @@ def accDec_time(
8505
9269
  [theta, delta, sigma] = atm.atmosphereProperties(
8506
9270
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
8507
9271
  )
8508
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
9272
+ temp_const = (theta * const.temp_0) / (
9273
+ theta * const.temp_0 - DeltaTemp
9274
+ )
8509
9275
  if AC.BADAFamily.BADAE:
8510
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
9276
+ gamma_i = degrees(
9277
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
9278
+ )
8511
9279
  else:
8512
9280
  # using SIN assumes the TAS to be in the direction of the aircraft axis, not ground plane. Which means, this should be mathematically the correct equation for all the aircraft
8513
- gamma_i = degrees(asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
9281
+ gamma_i = degrees(
9282
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
9283
+ )
8514
9284
 
8515
9285
  # ground speed can be calcualted as TAS projected on the ground minus wind
8516
9286
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -8521,7 +9291,9 @@ def accDec_time(
8521
9291
  ROT.append(rateOfTurn)
8522
9292
 
8523
9293
  # integrated data
8524
- if length_loop != 0: # exclude first point: initial t/d/m already known
9294
+ if (
9295
+ length_loop != 0
9296
+ ): # exclude first point: initial t/d/m already known
8525
9297
  if AC.BADAFamily.BADAE:
8526
9298
  SOC.append(SOC_i)
8527
9299
 
@@ -8609,14 +9381,16 @@ def accDec_time(
8609
9381
 
8610
9382
  else:
8611
9383
  # calculate the turn
8612
- (Lat_i, Lon_i, HDGTrue_i) = turn.destinationPoint_finalBearing(
8613
- LAT_init=LAT[-1],
8614
- LON_init=LON[-1],
8615
- bearingInit=HDGTrue[-1],
8616
- TAS=TAS_i,
8617
- rateOfTurn=rateOfTurn,
8618
- timeOfTurn=step_time,
8619
- directionOfTurn=directionOfTurn,
9384
+ (Lat_i, Lon_i, HDGTrue_i) = (
9385
+ turn.destinationPoint_finalBearing(
9386
+ LAT_init=LAT[-1],
9387
+ LON_init=LON[-1],
9388
+ bearingInit=HDGTrue[-1],
9389
+ TAS=TAS_i,
9390
+ rateOfTurn=rateOfTurn,
9391
+ timeOfTurn=step_time,
9392
+ directionOfTurn=directionOfTurn,
9393
+ )
8620
9394
  )
8621
9395
 
8622
9396
  if magneticDeclinationGrid is not None:
@@ -8654,14 +9428,16 @@ def accDec_time(
8654
9428
 
8655
9429
  else:
8656
9430
  # calculate the turn
8657
- (Lat_i, Lon_i, HDGTrue_i) = turn.destinationPoint_finalBearing(
8658
- LAT_init=LAT[-1],
8659
- LON_init=LON[-1],
8660
- bearingInit=HDGTrue[-1],
8661
- TAS=TAS_i,
8662
- rateOfTurn=rateOfTurn,
8663
- timeOfTurn=step_time,
8664
- directionOfTurn=directionOfTurn,
9431
+ (Lat_i, Lon_i, HDGTrue_i) = (
9432
+ turn.destinationPoint_finalBearing(
9433
+ LAT_init=LAT[-1],
9434
+ LON_init=LON[-1],
9435
+ bearingInit=HDGTrue[-1],
9436
+ TAS=TAS_i,
9437
+ rateOfTurn=rateOfTurn,
9438
+ timeOfTurn=step_time,
9439
+ directionOfTurn=directionOfTurn,
9440
+ )
8665
9441
  )
8666
9442
 
8667
9443
  if magneticDeclinationGrid is not None: