pyBADA 0.1.0__py3-none-any.whl → 0.1.2__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 (63) hide show
  1. pyBADA/TCL.py +1623 -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 +201 -216
  42. pyBADA/atmosphere.py +117 -87
  43. pyBADA/bada3.py +1412 -843
  44. pyBADA/bada4.py +1678 -988
  45. pyBADA/badaH.py +1129 -619
  46. pyBADA/configuration.py +142 -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.2.dist-info}/METADATA +22 -9
  54. pybada-0.1.2.dist-info/RECORD +97 -0
  55. {pybada-0.1.0.dist-info → pybada-0.1.2.dist-info}/WHEEL +1 -1
  56. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.dat +0 -38
  57. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.dat +0 -58
  58. pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.dat +0 -38
  59. pyBADA/aircraft/BADA4/DUMMY/aircraft_model_default.xml +0 -311
  60. pyBADA/badaE.py +0 -3317
  61. pybada-0.1.0.dist-info/RECORD +0 -99
  62. {pybada-0.1.0.dist-info → pybada-0.1.2.dist-info}/licenses/AUTHORS +0 -0
  63. {pybada-0.1.0.dist-info → pybada-0.1.2.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,96 @@ 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
+
84
+ - rateOfTurn [deg/s]
85
+ - bankAngle [deg]
86
+ - directionOfTurn {LEFT/RIGHT}. Default is no turn (straight flight).
87
+ :param stepClimb: Boolean to enable or disable step climb during the cruise segment. Default is False.
88
+ :param Lat: Geographical latitude of the starting point [deg].
89
+ :param Lon: Geographical longitude of the starting point [deg].
90
+ :param initialHeading: Dictionary defining the initial heading and its type:
91
+
92
+ - magnetic: Magnetic heading [deg].
93
+ - true: True heading [deg].
94
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
95
+ :param flightPhase: Defines the phase of flight, e.g., "Cruise", "Climb", "Descent". Default is "Cruise".
96
+ :param magneticDeclinationGrid: Optional magnetic declination grid to correct headings. Default is None.
97
+ :param kwargs: Additional optional parameters:
98
+
99
+ - mass_const: Boolean. If True, keeps the aircraft mass constant during the segment. Default is False.
100
+ - SOC_init: Initial battery state of charge for electric aircraft [%]. Default is 100 for BADAE.
101
+ - speedBrakes: Dictionary defining whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
102
+ - ROCD_min: Minimum rate of climb/descent threshold to identify service ceiling [ft/min]. Default varies by aircraft type.
103
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD.
104
+ - HpStep: Altitude step for step climb [ft]. Default is 2000 ft.
105
+ - m_iter: Number of iterations for mass integration. Default is 1 for BADAE, 2 for others.
106
+ - 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.
107
+
108
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
109
+
110
+ - **Hp** - wAltitude [ft]
111
+ - **TAS** - True Air Speed [kt]
112
+ - **CAS** - Calibrated Air Speed [kt]
113
+ - **GS** - Ground Speed [kt]
114
+ - **M** - Mach number [-]
115
+ - **ROCD** - Rate of Climb/Descent [ft/min]
116
+ - **ESF** - Energy Share Factor [-]
117
+ - **FUEL** - Fuel flow [kg/s]
118
+ - **FUELCONSUMED** - Total fuel consumed [kg]
119
+ - **THR** - Thrust force [N]
120
+ - **DRAG** - Drag force [N]
121
+ - **time** - Elapsed time [s]
122
+ - **dist** - Distance flown [NM]
123
+ - **slope** - Trajectory slope [deg]
124
+ - **mass** - Aircraft mass [kg]
125
+ - **config** - Aerodynamic configuration
126
+ - **LAT** - Latitude [deg]
127
+ - **LON** - Longitude [deg]
128
+ - **HDGTrue** - True heading [deg]
129
+ - **HDGMagnetic** - Magnetic heading [deg]
130
+ - **BankAngle** - Bank angle [deg]
131
+ - **ROT** - Rate of turn [deg/s]
132
+ - **Comment** - Comments for each segment
133
+
134
+ - **For BADAH:**
135
+ - **Preq** - Required power [W]
136
+ - **Peng** - Generated power [W]
137
+ - **Pav** - Available power [W]
138
+
139
+ - **For BADAE (electric aircraft):**
140
+ - **Pmec** - Mechanical power [W]
141
+ - **Pelc** - Electrical power [W]
142
+ - **Pbat** - Power supplied by the battery [W]
143
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
144
+ - **SOC** - Battery state of charge [%]
145
+ - **Ibat** - Battery current [A]
146
+ - **Vbat** - Battery voltage [V]
147
+ - **Vgbat** - Ground battery voltage [V]
148
+ :rtype: pandas.DataFrame
149
+
150
+ This function works by iteratively calculating the flight trajectory for a given segment of the flight,
151
+ taking into account the specified flight conditions, and updating the aircraft’s state (altitude, speed, fuel, etc.)
152
+ at each step of the iteration. The trajectory is returned as a DataFrame containing all relevant flight parameters.
130
153
  """
131
154
 
132
155
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -177,7 +200,9 @@ def constantSpeedLevel(
177
200
 
178
201
  # speed brakes application
179
202
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
180
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
203
+ speedBrakes = kwargs.get(
204
+ "speedBrakes", {"deployed": False, "value": 0.03}
205
+ )
181
206
 
182
207
  # optional parameter - iteration step length based on the type of aircraft
183
208
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -191,9 +216,13 @@ def constantSpeedLevel(
191
216
 
192
217
  # weight iteration constant
193
218
  if AC.BADAFamily.BADAE:
194
- m_iter = kwargs.get("m_iter", 1) # number of iterations for integration loop[-]
219
+ m_iter = kwargs.get(
220
+ "m_iter", 1
221
+ ) # number of iterations for integration loop[-]
195
222
  else:
196
- m_iter = kwargs.get("m_iter", 2) # number of iterations for integration loop[-]
223
+ m_iter = kwargs.get(
224
+ "m_iter", 2
225
+ ) # number of iterations for integration loop[-]
197
226
 
198
227
  # comment line describing type of trajectory calculation
199
228
  if flightPhase != "Cruise":
@@ -317,7 +346,9 @@ def constantSpeedLevel(
317
346
 
318
347
  # atmosphere properties
319
348
  H_m = conv.ft2m(Hp_i) # altitude [m]
320
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
349
+ [theta, delta, sigma] = atm.atmosphereProperties(
350
+ h=H_m, DeltaTemp=DeltaTemp
351
+ )
321
352
  # aircraft speed
322
353
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
323
354
  v=v, speedType=speedType, theta=theta, delta=delta, sigma=sigma
@@ -327,10 +358,14 @@ def constantSpeedLevel(
327
358
  if turnFlight:
328
359
  if turnMetrics["bankAngle"] != 0.0:
329
360
  # bankAngle is defined
330
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
361
+ rateOfTurn = AC.rateOfTurn_bankAngle(
362
+ TAS=TAS_i, bankAngle=bankAngle
363
+ )
331
364
  else:
332
365
  # rateOfTurn is defined
333
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
366
+ bankAngle = AC.bankAngle(
367
+ rateOfTurn=rateOfTurn, v=TAS_i
368
+ ) # [degrees]
334
369
 
335
370
  if lengthType == "distance":
336
371
  # step time is: distance differantial divided by ground speed
@@ -359,7 +394,9 @@ def constantSpeedLevel(
359
394
  # BADAH or BADAE
360
395
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
361
396
  # compute Power required for level flight
362
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
397
+ Preq_i = AC.Preq(
398
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
399
+ )
363
400
  Peng_i = Preq_i
364
401
  if AC.BADAFamily.BADAH:
365
402
  Pav_i = AC.Pav(
@@ -372,7 +409,8 @@ def constantSpeedLevel(
372
409
 
373
410
  if Pav_i < Preq_i:
374
411
  warnings.warn(
375
- "Power Available is lower than Power Required", UserWarning
412
+ "Power Available is lower than Power Required",
413
+ UserWarning,
376
414
  )
377
415
 
378
416
  # BADAH
@@ -390,7 +428,9 @@ def constantSpeedLevel(
390
428
  Pelc_i = Preq_i / AC.eta
391
429
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC_i)
392
430
  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
431
+ Vgbat_i = (
432
+ AC.Vocbat(SOC=SOC_i) - AC.R0bat(SOC=SOC_i) * Ibat_i
433
+ )
394
434
 
395
435
  # BADA4
396
436
  elif AC.BADAFamily.BADA4:
@@ -414,12 +454,16 @@ def constantSpeedLevel(
414
454
  currentConfig=config_i,
415
455
  )
416
456
 
417
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
457
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
458
+ config=config_i
459
+ )
418
460
 
419
461
  # compute lift coefficient
420
462
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
421
463
  # compute drag coefficient
422
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
464
+ CD = AC.CD(
465
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
466
+ )
423
467
  # compute drag force
424
468
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
425
469
  # compute thrust force and fuel flow
@@ -702,7 +746,9 @@ def constantSpeedLevel(
702
746
  # determine atmosphere properties at upper cruise altitude
703
747
  nextHp = min(Hp_i + HpStep, maxRFL)
704
748
  H_m = conv.ft2m(nextHp) # altitude [m]
705
- [theta, delta, sigma] = atm.atmosphereProperties(h=H_m, DeltaTemp=DeltaTemp)
749
+ [theta, delta, sigma] = atm.atmosphereProperties(
750
+ h=H_m, DeltaTemp=DeltaTemp
751
+ )
706
752
 
707
753
  # aircraft speed at upper cruise altitude
708
754
  [M_up, CAS_up, TAS_up] = atm.convertSpeed(
@@ -771,19 +817,31 @@ def constantSpeedLevel(
771
817
  currentConfig=config_i,
772
818
  )
773
819
 
774
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
820
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
821
+ config=config_i
822
+ )
775
823
 
776
824
  # compute lift coefficient
777
825
  CL = AC.CL(M=M_up, delta=delta, mass=mass_i, nz=nz)
778
826
  # compute drag coefficient
779
- CD = AC.CD(M=M_up, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
827
+ CD = AC.CD(
828
+ M=M_up,
829
+ CL=CL,
830
+ HLid=HLid_i,
831
+ LG=LG_i,
832
+ speedBrakes=speedBrakes,
833
+ )
780
834
  # compute drag force
781
835
  Drag = AC.D(M=M_up, delta=delta, CD=CD)
782
836
  # compute thrust force and fuel flow
783
837
  THR_up = Drag
784
838
  CT = AC.CT(Thrust=THR_up, delta=delta)
785
839
  FUEL_up = AC.ff(
786
- CT=CT, delta=delta, theta=theta, M=M_up, DeltaTemp=DeltaTemp
840
+ CT=CT,
841
+ delta=delta,
842
+ theta=theta,
843
+ M=M_up,
844
+ DeltaTemp=DeltaTemp,
787
845
  ) # [kg/s]
788
846
 
789
847
  # Compare specific range at current and upper cruise altitudes
@@ -808,7 +866,10 @@ def constantSpeedLevel(
808
866
 
809
867
  flightEvolution = "const" + speedType
810
868
  ESF_i = AC.esf(
811
- h=H_m, flightEvolution=flightEvolution, M=M_up, DeltaTemp=DeltaTemp
869
+ h=H_m,
870
+ flightEvolution=flightEvolution,
871
+ M=M_up,
872
+ DeltaTemp=DeltaTemp,
812
873
  )
813
874
  temp_const = (theta * const.temp_0) / (
814
875
  theta * const.temp_0 - DeltaTemp
@@ -894,7 +955,9 @@ def constantSpeedLevel(
894
955
  ROT.extend(flightTrajectory_CL["ROT"])
895
956
 
896
957
  comment_CL = flightTrajectory_CL["comment"]
897
- Comment.extend([com + "_stepClimb" for com in comment_CL])
958
+ Comment.extend(
959
+ [com + "_stepClimb" for com in comment_CL]
960
+ )
898
961
 
899
962
  # BADA4
900
963
  if AC.BADAFamily.BADA4:
@@ -916,7 +979,9 @@ def constantSpeedLevel(
916
979
  if Lat and Lon and magneticHeading:
917
980
  LAT.extend(flightTrajectory_CL["LAT"])
918
981
  LON.extend(flightTrajectory_CL["LON"])
919
- HDGMagnetic.extend(flightTrajectory_CL["HDGMagnetic"])
982
+ HDGMagnetic.extend(
983
+ flightTrajectory_CL["HDGMagnetic"]
984
+ )
920
985
  HDGTrue.extend(flightTrajectory_CL["HDGTrue"])
921
986
 
922
987
  # Compute cruise fuel at upper altitude
@@ -936,18 +1001,20 @@ def constantSpeedLevel(
936
1001
 
937
1002
  # ensure continuity of configuration change within the segment
938
1003
  if config:
939
- config_i = (
940
- AC.flightEnvelope.checkConfigurationContinuity(
941
- phase=flightPhase,
942
- previousConfig=config[-1],
943
- currentConfig=config_i,
944
- )
1004
+ config_i = AC.flightEnvelope.checkConfigurationContinuity(
1005
+ phase=flightPhase,
1006
+ previousConfig=config[-1],
1007
+ currentConfig=config_i,
945
1008
  )
946
1009
 
947
1010
  # compute lift coefficient
948
- CL = AC.CL(tas=TAS_up, sigma=sigma, mass=mass[-1], nz=nz)
1011
+ CL = AC.CL(
1012
+ tas=TAS_up, sigma=sigma, mass=mass[-1], nz=nz
1013
+ )
949
1014
  # compute drag coefficient
950
- CD = AC.CD(CL=CL, config=config_i, speedBrakes=speedBrakes)
1015
+ CD = AC.CD(
1016
+ CL=CL, config=config_i, speedBrakes=speedBrakes
1017
+ )
951
1018
  # compute drag force
952
1019
  Drag = AC.D(tas=TAS_up, sigma=sigma, CD=CD)
953
1020
  # compute thrust force and fuel flow
@@ -977,12 +1044,10 @@ def constantSpeedLevel(
977
1044
 
978
1045
  # ensure continuity of configuration change within the segment
979
1046
  if config:
980
- config_i = (
981
- AC.flightEnvelope.checkConfigurationContinuity(
982
- phase=flightPhase,
983
- previousConfig=config[-1],
984
- currentConfig=config_i,
985
- )
1047
+ config_i = AC.flightEnvelope.checkConfigurationContinuity(
1048
+ phase=flightPhase,
1049
+ previousConfig=config[-1],
1050
+ currentConfig=config_i,
986
1051
  )
987
1052
 
988
1053
  [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
@@ -990,7 +1055,9 @@ def constantSpeedLevel(
990
1055
  )
991
1056
 
992
1057
  # compute lift coefficient
993
- CL = AC.CL(M=M_up, delta=delta, mass=mass[-1], nz=nz)
1058
+ CL = AC.CL(
1059
+ M=M_up, delta=delta, mass=mass[-1], nz=nz
1060
+ )
994
1061
  # compute drag coefficient
995
1062
  CD = AC.CD(
996
1063
  M=M_up,
@@ -1121,58 +1188,95 @@ def constantSpeedROCD(
1121
1188
  magneticDeclinationGrid=None,
1122
1189
  **kwargs,
1123
1190
  ):
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]}.
1191
+ """
1192
+ Computes the time, fuel consumption, and other parameters required for an aircraft to climb or descend
1193
+ from a given initial altitude (Hp_init) to a final altitude (Hp_final) at a constant speed and rate of climb/descent (ROCD).
1194
+
1195
+ The function handles multiple BADA families (BADA3, BADA4, BADAH, BADAE), computing various parameters
1196
+ such as altitude, speed, fuel consumption, power, heading, and mass based on the aircraft's performance
1197
+ characteristics. The function supports turn performance, optional heading (true or magnetic), and
1198
+ handling mass changes during the flight.
1199
+
1200
+ :param AC: Aircraft object {BADA3/4/H/E}
1201
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
1202
+ :param v: Speed to maintain during the flight - [kt] CAS/TAS or [-] MACH.
1203
+ :param Hp_init: Initial pressure altitude at the start of the segment [ft].
1204
+ :param Hp_final: Final pressure altitude at the end of the segment [ft].
1205
+ :param ROCDtarget: Target rate of climb/descent [ft/min].
1206
+ :param m_init: Initial aircraft mass at the start of the segment [kg].
1207
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
1208
+ :param wS: Wind speed component along the longitudinal axis [kt]. Positive values for headwind, negative for tailwind. Default is 0.0.
1209
+ :param turnMetrics: Dictionary defining turn parameters:
1210
+
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
+
1218
+ - magnetic: Magnetic heading [deg].
1219
+ - true: True heading [deg].
1220
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
1221
+ :param reducedPower: Boolean specifying whether to apply reduced power during the climb. Default is None.
1222
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
1223
+ :param magneticDeclinationGrid: Optional grid of magnetic declinations used to correct headings. Default is None.
1224
+ :param kwargs: Additional optional parameters:
1225
+
1226
+ - Hp_step: Altitude step size [ft]. Default is 1000 for BADA3/4, 500 for BADAH/BADAE.
1227
+ - SOC_init: Initial state of charge for electric aircraft [%]. Default is 100 for BADAE.
1228
+ - speedBrakes: Dictionary specifying whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
1229
+ - ROCD_min: Minimum ROCD to identify the service ceiling [ft/min]. Default varies by aircraft type.
1230
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD. Default is None.
1231
+ - mass_const: Boolean specifying whether to keep the mass constant during the segment. Default is False.
1232
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
1233
+
1234
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
1235
+
1236
+ - **Hp** - wAltitude [ft]
1237
+ - **TAS** - True Air Speed [kt]
1238
+ - **CAS** - Calibrated Air Speed [kt]
1239
+ - **GS** - Ground Speed [kt]
1240
+ - **M** - Mach number [-]
1241
+ - **ROCD** - Rate of Climb/Descent [ft/min]
1242
+ - **ESF** - Energy Share Factor [-]
1243
+ - **FUEL** - Fuel flow [kg/s]
1244
+ - **FUELCONSUMED** - Total fuel consumed [kg]
1245
+ - **THR** - Thrust force [N]
1246
+ - **DRAG** - Drag force [N]
1247
+ - **time** - Elapsed time [s]
1248
+ - **dist** - Distance flown [NM]
1249
+ - **slope** - Trajectory slope [deg]
1250
+ - **mass** - Aircraft mass [kg]
1251
+ - **config** - Aerodynamic configuration
1252
+ - **LAT** - Latitude [deg]
1253
+ - **LON** - Longitude [deg]
1254
+ - **HDGTrue** - True heading [deg]
1255
+ - **HDGMagnetic** - Magnetic heading [deg]
1256
+ - **BankAngle** - Bank angle [deg]
1257
+ - **ROT** - Rate of turn [deg/s]
1258
+ - **Comment** - Comments for each segment
1259
+
1260
+ - **For BADAH:**
1261
+ - **Preq** - Required power [W]
1262
+ - **Peng** - Generated power [W]
1263
+ - **Pav** - Available power [W]
1264
+
1265
+ - **For BADAE (electric aircraft):**
1266
+ - **Pmec** - Mechanical power [W]
1267
+ - **Pelc** - Electrical power [W]
1268
+ - **Pbat** - Power supplied by the battery [W]
1269
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
1270
+ - **SOC** - Battery state of charge [%]
1271
+ - **Ibat** - Battery current [A]
1272
+ - **Vbat** - Battery voltage [V]
1273
+ - **Vgbat** - Ground battery voltage [V]
1274
+ :rtype: pandas.DataFrame
1275
+
1276
+ Notes:
1277
+ - The function iteratively calculates flight parameters for each altitude step, adjusting fuel, power, and mass.
1278
+ - Magnetic heading and true heading can be adjusted using the magnetic declination grid if provided.
1279
+ - The function supports turns, and constant or changing headings based on input parameters.
1176
1280
  """
1177
1281
 
1178
1282
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -1223,7 +1327,9 @@ def constantSpeedROCD(
1223
1327
 
1224
1328
  # speed brakes application
1225
1329
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
1226
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
1330
+ speedBrakes = kwargs.get(
1331
+ "speedBrakes", {"deployed": False, "value": 0.03}
1332
+ )
1227
1333
 
1228
1334
  # optional parameter - iteration step for altitude loop
1229
1335
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -1271,7 +1377,9 @@ def constantSpeedROCD(
1271
1377
  constHeadingStr = ""
1272
1378
 
1273
1379
  # comment line describing type of trajectory calculation
1274
- comment = phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
1380
+ comment = (
1381
+ phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
1382
+ )
1275
1383
 
1276
1384
  if Lat and Lon and (magneticHeading or trueHeading):
1277
1385
  comment = comment + "_" + headingToFly + "_Heading"
@@ -1292,7 +1400,9 @@ def constantSpeedROCD(
1292
1400
  )
1293
1401
 
1294
1402
  # weight iteration constant
1295
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
1403
+ m_iter = kwargs.get(
1404
+ "m_iter", 5
1405
+ ) # number of iterations for integration loop[-]
1296
1406
 
1297
1407
  # convert ROCD to IS units
1298
1408
  ROCDisu = conv.ft2m(ROCDtarget) / 60
@@ -1361,8 +1471,12 @@ def constantSpeedROCD(
1361
1471
 
1362
1472
  # atmosphere properties
1363
1473
  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)
1474
+ [theta, delta, sigma] = atm.atmosphereProperties(
1475
+ h=H_m, DeltaTemp=DeltaTemp
1476
+ )
1477
+ temp_const = (theta * const.temp_0) / (
1478
+ theta * const.temp_0 - DeltaTemp
1479
+ )
1366
1480
 
1367
1481
  # aircraft speed
1368
1482
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -1371,16 +1485,23 @@ def constantSpeedROCD(
1371
1485
 
1372
1486
  # compute Energy Share Factor (ESF)
1373
1487
  ESF_i = AC.esf(
1374
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
1488
+ h=H_m,
1489
+ M=M_i,
1490
+ DeltaTemp=DeltaTemp,
1491
+ flightEvolution=("const" + speedType),
1375
1492
  )
1376
1493
 
1377
1494
  if turnFlight:
1378
1495
  if turnMetrics["bankAngle"] != 0.0:
1379
1496
  # bankAngle is defined
1380
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
1497
+ rateOfTurn = AC.rateOfTurn_bankAngle(
1498
+ TAS=TAS_i, bankAngle=bankAngle
1499
+ )
1381
1500
  else:
1382
1501
  # rateOfTurn is defined
1383
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
1502
+ bankAngle = AC.bankAngle(
1503
+ rateOfTurn=rateOfTurn, v=TAS_i
1504
+ ) # [degrees]
1384
1505
 
1385
1506
  # Load factor
1386
1507
  nz = 1 / cos(radians(bankAngle))
@@ -1394,7 +1515,9 @@ def constantSpeedROCD(
1394
1515
  # BADAH or BADAE
1395
1516
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
1396
1517
  # compute Power required for level flight
1397
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
1518
+ Preq_i = AC.Preq(
1519
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
1520
+ )
1398
1521
  # Compute power required for target ROCD
1399
1522
  Preq_target_i = AC.Peng_target(
1400
1523
  temp=theta * const.temp_0,
@@ -1422,20 +1545,27 @@ def constantSpeedROCD(
1422
1545
  # ensure continuity of configuration change within the segment
1423
1546
  if config:
1424
1547
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
1425
- phase=phase, previousConfig=config[-1], currentConfig=config_i
1548
+ phase=phase,
1549
+ previousConfig=config[-1],
1550
+ currentConfig=config_i,
1426
1551
  )
1427
1552
 
1428
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
1553
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
1554
+ config=config_i
1555
+ )
1429
1556
 
1430
1557
  # compute lift coefficient
1431
1558
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
1432
1559
  # compute drag coefficient
1433
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
1560
+ CD = AC.CD(
1561
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
1562
+ )
1434
1563
  # compute drag force
1435
1564
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
1436
1565
  # compute thrust force
1437
1566
  THR_i = (
1438
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
1567
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
1568
+ + Drag
1439
1569
  ) # [N]
1440
1570
 
1441
1571
  # BADA3
@@ -1468,7 +1598,8 @@ def constantSpeedROCD(
1468
1598
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
1469
1599
  # compute thrust force
1470
1600
  THR_i = (
1471
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
1601
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
1602
+ + Drag
1472
1603
  ) # [N]
1473
1604
 
1474
1605
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -1567,21 +1698,39 @@ def constantSpeedROCD(
1567
1698
  Pelc_i = Preq_target_i / AC.eta
1568
1699
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
1569
1700
  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
1701
+ Vgbat_i = (
1702
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
1703
+ )
1571
1704
 
1572
1705
  # BADA4
1573
1706
  elif AC.BADAFamily.BADA4:
1574
1707
  THR_min = AC.Thrust(
1575
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1708
+ rating="LIDL",
1709
+ delta=delta,
1710
+ theta=theta,
1711
+ M=M_i,
1712
+ DeltaTemp=DeltaTemp,
1576
1713
  ) # IDLE Thrust
1577
1714
  FUEL_min = AC.ff(
1578
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1715
+ rating="LIDL",
1716
+ delta=delta,
1717
+ theta=theta,
1718
+ M=M_i,
1719
+ DeltaTemp=DeltaTemp,
1579
1720
  ) # IDLE Fuel Flow
1580
1721
  THR_max = AC.Thrust(
1581
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1722
+ rating="MCMB",
1723
+ delta=delta,
1724
+ theta=theta,
1725
+ M=M_i,
1726
+ DeltaTemp=DeltaTemp,
1582
1727
  ) # MCMB Thrust
1583
1728
  FUEL_max = AC.ff(
1584
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1729
+ rating="MCMB",
1730
+ delta=delta,
1731
+ theta=theta,
1732
+ M=M_i,
1733
+ DeltaTemp=DeltaTemp,
1585
1734
  ) # MCMB Fuel Flow
1586
1735
  if THR_i < THR_min:
1587
1736
  THR_i = THR_min
@@ -1612,14 +1761,22 @@ def constantSpeedROCD(
1612
1761
  else:
1613
1762
  CT = AC.CT(Thrust=THR_i, delta=delta)
1614
1763
  FUEL_i = AC.ff(
1615
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
1764
+ CT=CT,
1765
+ delta=delta,
1766
+ theta=theta,
1767
+ M=M_i,
1768
+ DeltaTemp=DeltaTemp,
1616
1769
  ) # [kg/s]
1617
1770
  ROCD_i = ROCDtarget
1618
1771
 
1619
1772
  # BADA3
1620
1773
  elif AC.BADAFamily.BADA3:
1621
1774
  THR_min = AC.Thrust(
1622
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
1775
+ rating="LIDL",
1776
+ v=TAS_i,
1777
+ h=H_m,
1778
+ config="CR",
1779
+ DeltaTemp=DeltaTemp,
1623
1780
  ) # IDLE Thrust
1624
1781
  FUEL_min = AC.ff(
1625
1782
  flightPhase="Descent",
@@ -1630,7 +1787,11 @@ def constantSpeedROCD(
1630
1787
  adapted=False,
1631
1788
  ) # IDLE Fuel Flow
1632
1789
  THR_max = AC.Thrust(
1633
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
1790
+ rating="MCMB",
1791
+ v=TAS_i,
1792
+ h=H_m,
1793
+ DeltaTemp=DeltaTemp,
1794
+ config="CR",
1634
1795
  ) # MCMB Thrust
1635
1796
  FUEL_max = AC.ff(
1636
1797
  flightPhase="Climb",
@@ -1779,10 +1940,14 @@ def constantSpeedROCD(
1779
1940
  gamma_i = 90 * np.sign(ROCD_i)
1780
1941
  else:
1781
1942
  if AC.BADAFamily.BADAE:
1782
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
1943
+ gamma_i = degrees(
1944
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
1945
+ )
1783
1946
  else:
1784
1947
  # 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))
1948
+ gamma_i = degrees(
1949
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
1950
+ )
1786
1951
 
1787
1952
  Slope.append(gamma_i)
1788
1953
 
@@ -1815,7 +1980,9 @@ def constantSpeedROCD(
1815
1980
  if turnFlight:
1816
1981
  step_distance = conv.m2nm(
1817
1982
  turn.distance(
1818
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
1983
+ rateOfTurn=rateOfTurn,
1984
+ TAS=TAS_i,
1985
+ timeOfTurn=step_time,
1819
1986
  )
1820
1987
  ) # arcLength during the turn [NM]
1821
1988
  else:
@@ -2035,58 +2202,90 @@ def constantSpeedROCD_time(
2035
2202
  magneticDeclinationGrid=None,
2036
2203
  **kwargs,
2037
2204
  ):
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]}.
2205
+ """
2206
+ Computes the time, fuel consumption, and performance parameters required for an aircraft to
2207
+ perform a climb or descent based on a set amount of time, while maintaining a constant speed and constant
2208
+ rate of climb/descent (ROCD).
2209
+
2210
+ The function supports various BADA families (BADA3, BADA4, BADAH, BADAE), with different handling for mass changes,
2211
+ aerodynamic configurations, and energy consumption. It calculates parameters such as fuel consumption, power
2212
+ requirements, speed, heading, and altitude changes over the specified duration.
2213
+
2214
+ :param AC: Aircraft object {BADA3/4/H/E}
2215
+ :param length: The length of the segment to fly in time [s].
2216
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
2217
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
2218
+ :param Hp_init: Initial pressure altitude [ft].
2219
+ :param ROCDtarget: Rate of climb or descent [ft/min].
2220
+ :param m_init: Initial aircraft mass at the start of the segment [kg].
2221
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
2222
+ :param wS: Wind speed component along the longitudinal axis [kt]. Default is 0.0.
2223
+ :param turnMetrics: Dictionary defining turn parameters:
2224
+
2225
+ - rateOfTurn [deg/s]
2226
+ - bankAngle [deg]
2227
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
2228
+ :param Lat: Geographical latitude at the start [deg]. Default is None.
2229
+ :param Lon: Geographical longitude at the start [deg]. Default is None.
2230
+ :param initialHeading: Dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
2231
+
2232
+ - magnetic: Magnetic heading [deg].
2233
+ - true: True heading [deg].
2234
+ - constantHeading: Whether to fly along a constant heading (loxodrome). Default is None.
2235
+ :param reducedPower: Boolean specifying whether to apply reduced power during the climb. Default is None.
2236
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
2237
+ :param magneticDeclinationGrid: Optional grid of magnetic declinations used to correct headings. Default is None.
2238
+ :param kwargs: Additional optional parameters:
2239
+
2240
+ - step_length: Step size in seconds for time iteration. Default is 1 second.
2241
+ - SOC_init: Initial state of charge for electric aircraft [%]. Default is 100 for BADAE.
2242
+ - speedBrakes: Dictionary specifying whether speed brakes are deployed and their drag coefficient {deployed: False, value: 0.03}.
2243
+ - ROCD_min: Minimum ROCD to identify the service ceiling [ft/min]. Default varies by aircraft type.
2244
+ - config: Default aerodynamic configuration. Values: TO, IC, CR, AP, LD. Default is None.
2245
+ - mass_const: Boolean specifying whether to keep the mass constant during the segment. Default is False.
2246
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
2247
+
2248
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
2249
+
2250
+ - **Hp** - wAltitude [ft]
2251
+ - **TAS** - True Air Speed [kt]
2252
+ - **CAS** - Calibrated Air Speed [kt]
2253
+ - **GS** - Ground Speed [kt]
2254
+ - **M** - Mach number [-]
2255
+ - **ROCD** - Rate of Climb/Descent [ft/min]
2256
+ - **ESF** - Energy Share Factor [-]
2257
+ - **FUEL** - Fuel flow [kg/s]
2258
+ - **FUELCONSUMED** - Total fuel consumed [kg]
2259
+ - **THR** - Thrust force [N]
2260
+ - **DRAG** - Drag force [N]
2261
+ - **time** - Elapsed time [s]
2262
+ - **dist** - Distance flown [NM]
2263
+ - **slope** - Trajectory slope [deg]
2264
+ - **mass** - Aircraft mass [kg]
2265
+ - **config** - Aerodynamic configuration
2266
+ - **LAT** - Latitude [deg]
2267
+ - **LON** - Longitude [deg]
2268
+ - **HDGTrue** - True heading [deg]
2269
+ - **HDGMagnetic** - Magnetic heading [deg]
2270
+ - **BankAngle** - Bank angle [deg]
2271
+ - **ROT** - Rate of turn [deg/s]
2272
+ - **Comment** - Comments for each segment
2273
+
2274
+ - **For BADAH:**
2275
+ - **Preq** - Required power [W]
2276
+ - **Peng** - Generated power [W]
2277
+ - **Pav** - Available power [W]
2278
+
2279
+ - **For BADAE (electric aircraft):**
2280
+ - **Pmec** - Mechanical power [W]
2281
+ - **Pelc** - Electrical power [W]
2282
+ - **Pbat** - Power supplied by the battery [W]
2283
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
2284
+ - **SOC** - Battery state of charge [%]
2285
+ - **Ibat** - Battery current [A]
2286
+ - **Vbat** - Battery voltage [V]
2287
+ - **Vgbat** - Ground battery voltage [V]
2288
+ :rtype: pandas.DataFrame
2090
2289
  """
2091
2290
 
2092
2291
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -2137,7 +2336,9 @@ def constantSpeedROCD_time(
2137
2336
 
2138
2337
  # speed brakes application
2139
2338
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
2140
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
2339
+ speedBrakes = kwargs.get(
2340
+ "speedBrakes", {"deployed": False, "value": 0.03}
2341
+ )
2141
2342
 
2142
2343
  # step size in [s]
2143
2344
  step_length = kwargs.get("step_length", 1)
@@ -2170,7 +2371,9 @@ def constantSpeedROCD_time(
2170
2371
  constHeadingStr = ""
2171
2372
 
2172
2373
  # comment line describing type of trajectory calculation
2173
- comment = phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
2374
+ comment = (
2375
+ phase + turnComment + "_const_ROCD_" + speedType + constHeadingStr
2376
+ )
2174
2377
 
2175
2378
  if Lat and Lon and (magneticHeading or trueHeading):
2176
2379
  comment = comment + "_" + headingToFly + "_Heading"
@@ -2191,7 +2394,9 @@ def constantSpeedROCD_time(
2191
2394
  )
2192
2395
 
2193
2396
  # weight iteration constant
2194
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
2397
+ m_iter = kwargs.get(
2398
+ "m_iter", 5
2399
+ ) # number of iterations for integration loop[-]
2195
2400
 
2196
2401
  # convert ROCD to IS units
2197
2402
  ROCDisu = conv.ft2m(ROCDtarget) / 60
@@ -2269,8 +2474,12 @@ def constantSpeedROCD_time(
2269
2474
  for _ in itertools.repeat(None, m_iter):
2270
2475
  # atmosphere properties
2271
2476
  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)
2477
+ [theta, delta, sigma] = atm.atmosphereProperties(
2478
+ h=H_m, DeltaTemp=DeltaTemp
2479
+ )
2480
+ temp_const = (theta * const.temp_0) / (
2481
+ theta * const.temp_0 - DeltaTemp
2482
+ )
2274
2483
 
2275
2484
  # aircraft speed
2276
2485
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -2279,13 +2488,18 @@ def constantSpeedROCD_time(
2279
2488
 
2280
2489
  # compute Energy Share Factor (ESF)
2281
2490
  ESF_i = AC.esf(
2282
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
2491
+ h=H_m,
2492
+ M=M_i,
2493
+ DeltaTemp=DeltaTemp,
2494
+ flightEvolution=("const" + speedType),
2283
2495
  )
2284
2496
 
2285
2497
  if turnFlight:
2286
2498
  if turnMetrics["bankAngle"] != 0.0:
2287
2499
  # bankAngle is defined
2288
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
2500
+ rateOfTurn = AC.rateOfTurn_bankAngle(
2501
+ TAS=TAS_i, bankAngle=bankAngle
2502
+ )
2289
2503
  else:
2290
2504
  # rateOfTurn is defined
2291
2505
  bankAngle = AC.bankAngle(
@@ -2300,7 +2514,9 @@ def constantSpeedROCD_time(
2300
2514
  # BADAH or BADAE
2301
2515
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
2302
2516
  # compute Power required for level flight
2303
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
2517
+ Preq_i = AC.Preq(
2518
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
2519
+ )
2304
2520
  # Compute power required for target ROCD
2305
2521
  Preq_target_i = AC.Peng_target(
2306
2522
  temp=theta * const.temp_0,
@@ -2328,20 +2544,27 @@ def constantSpeedROCD_time(
2328
2544
  # ensure continuity of configuration change within the segment
2329
2545
  if config:
2330
2546
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
2331
- phase=phase, previousConfig=config[-1], currentConfig=config_i
2547
+ phase=phase,
2548
+ previousConfig=config[-1],
2549
+ currentConfig=config_i,
2332
2550
  )
2333
2551
 
2334
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
2552
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
2553
+ config=config_i
2554
+ )
2335
2555
 
2336
2556
  # compute lift coefficient
2337
2557
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
2338
2558
  # compute drag coefficient
2339
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
2559
+ CD = AC.CD(
2560
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
2561
+ )
2340
2562
  # compute drag force
2341
2563
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
2342
2564
  # compute thrust force
2343
2565
  THR_i = (
2344
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
2566
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
2567
+ + Drag
2345
2568
  ) # [N]
2346
2569
 
2347
2570
  # BADA3
@@ -2374,7 +2597,8 @@ def constantSpeedROCD_time(
2374
2597
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
2375
2598
  # compute thrust force
2376
2599
  THR_i = (
2377
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
2600
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
2601
+ + Drag
2378
2602
  ) # [N]
2379
2603
 
2380
2604
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -2473,21 +2697,39 @@ def constantSpeedROCD_time(
2473
2697
  Pelc_i = Preq_target_i / AC.eta
2474
2698
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
2475
2699
  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
2700
+ Vgbat_i = (
2701
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
2702
+ )
2477
2703
 
2478
2704
  # BADA4
2479
2705
  elif AC.BADAFamily.BADA4:
2480
2706
  THR_min = AC.Thrust(
2481
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2707
+ rating="LIDL",
2708
+ delta=delta,
2709
+ theta=theta,
2710
+ M=M_i,
2711
+ DeltaTemp=DeltaTemp,
2482
2712
  ) # IDLE Thrust
2483
2713
  FUEL_min = AC.ff(
2484
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2714
+ rating="LIDL",
2715
+ delta=delta,
2716
+ theta=theta,
2717
+ M=M_i,
2718
+ DeltaTemp=DeltaTemp,
2485
2719
  ) # IDLE Fuel Flow
2486
2720
  THR_max = AC.Thrust(
2487
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2721
+ rating="MCMB",
2722
+ delta=delta,
2723
+ theta=theta,
2724
+ M=M_i,
2725
+ DeltaTemp=DeltaTemp,
2488
2726
  ) # MCMB Thrust
2489
2727
  FUEL_max = AC.ff(
2490
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2728
+ rating="MCMB",
2729
+ delta=delta,
2730
+ theta=theta,
2731
+ M=M_i,
2732
+ DeltaTemp=DeltaTemp,
2491
2733
  ) # MCMB Fuel Flow
2492
2734
  if THR_i < THR_min:
2493
2735
  THR_i = THR_min
@@ -2518,14 +2760,22 @@ def constantSpeedROCD_time(
2518
2760
  else:
2519
2761
  CT = AC.CT(Thrust=THR_i, delta=delta)
2520
2762
  FUEL_i = AC.ff(
2521
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
2763
+ CT=CT,
2764
+ delta=delta,
2765
+ theta=theta,
2766
+ M=M_i,
2767
+ DeltaTemp=DeltaTemp,
2522
2768
  ) # [kg/s]
2523
2769
  ROCD_i = ROCDtarget
2524
2770
 
2525
2771
  # BADA3
2526
2772
  elif AC.BADAFamily.BADA3:
2527
2773
  THR_min = AC.Thrust(
2528
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
2774
+ rating="LIDL",
2775
+ v=TAS_i,
2776
+ h=H_m,
2777
+ config="CR",
2778
+ DeltaTemp=DeltaTemp,
2529
2779
  ) # IDLE Thrust
2530
2780
  FUEL_min = AC.ff(
2531
2781
  flightPhase="Descent",
@@ -2536,7 +2786,11 @@ def constantSpeedROCD_time(
2536
2786
  adapted=False,
2537
2787
  ) # IDLE Fuel Flow
2538
2788
  THR_max = AC.Thrust(
2539
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
2789
+ rating="MCMB",
2790
+ v=TAS_i,
2791
+ h=H_m,
2792
+ DeltaTemp=DeltaTemp,
2793
+ config="CR",
2540
2794
  ) # MCMB Thrust
2541
2795
  FUEL_max = AC.ff(
2542
2796
  flightPhase="Climb",
@@ -2688,12 +2942,18 @@ def constantSpeedROCD_time(
2688
2942
  [theta, delta, sigma] = atm.atmosphereProperties(
2689
2943
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
2690
2944
  )
2691
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
2945
+ temp_const = (theta * const.temp_0) / (
2946
+ theta * const.temp_0 - DeltaTemp
2947
+ )
2692
2948
  if AC.BADAFamily.BADAE:
2693
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
2949
+ gamma_i = degrees(
2950
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
2951
+ )
2694
2952
  else:
2695
2953
  # 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))
2954
+ gamma_i = degrees(
2955
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
2956
+ )
2697
2957
 
2698
2958
  # ground speed can be calcualted as TAS projected on the ground minus wind
2699
2959
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -2730,7 +2990,9 @@ def constantSpeedROCD_time(
2730
2990
  if turnFlight:
2731
2991
  step_distance = conv.m2nm(
2732
2992
  turn.distance(
2733
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
2993
+ rateOfTurn=rateOfTurn,
2994
+ TAS=TAS_i,
2995
+ timeOfTurn=step_time,
2734
2996
  )
2735
2997
  ) # arcLength during the turn [NM]
2736
2998
  else:
@@ -2932,58 +3194,89 @@ def constantSpeedSlope(
2932
3194
  magneticDeclinationGrid=None,
2933
3195
  **kwargs,
2934
3196
  ):
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]}.
3197
+ """
3198
+ Calculates time, fuel consumption, and other parameters required for an aircraft to perform a climb or descent
3199
+ from an initial altitude (Hp_init) to a final altitude (Hp_final) while maintaining a constant speed and a constant slope.
3200
+
3201
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key flight parameters
3202
+ such as energy consumption, rate of climb/descent (ROCD), fuel burn, mass changes, and power requirements. The function also supports
3203
+ complex flight dynamics including turns, heading changes, and wind influences.
3204
+
3205
+ :param AC: Aircraft object {BADA3/4/H/E}.
3206
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
3207
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
3208
+ :param Hp_init: Initial pressure altitude [ft].
3209
+ :param Hp_final: Final pressure altitude [ft].
3210
+ :param slopetarget: Target slope (trajectory angle) to be maintained during climb/descent [deg].
3211
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
3212
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
3213
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
3214
+ :param turnMetrics: A dictionary defining the turn parameters:
3215
+
3216
+ - rateOfTurn [deg/s]
3217
+ - bankAngle [deg]
3218
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
3219
+ :param Lat: Initial latitude [deg]. Default is None.
3220
+ :param Lon: Initial longitude [deg]. Default is None.
3221
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
3222
+
3223
+ - magnetic: Magnetic heading [deg].
3224
+ - true: True heading [deg].
3225
+ - constantHeading: Whether to maintain a constant heading. Default is None.
3226
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
3227
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
3228
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
3229
+ :param kwargs: Additional optional parameters:
3230
+
3231
+ - Hp_step: Step size in altitude for the iterative calculation [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
3232
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
3233
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
3234
+ - ROCD_min: Minimum rate of climb/descent used to determine service ceiling [ft/min]. Default varies based on aircraft type.
3235
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
3236
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
3237
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
3238
+
3239
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
3240
+
3241
+ - **Hp** - wAltitude [ft]
3242
+ - **TAS** - True Air Speed [kt]
3243
+ - **CAS** - Calibrated Air Speed [kt]
3244
+ - **GS** - Ground Speed [kt]
3245
+ - **M** - Mach number [-]
3246
+ - **ROCD** - Rate of Climb/Descent [ft/min]
3247
+ - **ESF** - Energy Share Factor [-]
3248
+ - **FUEL** - Fuel flow [kg/s]
3249
+ - **FUELCONSUMED** - Total fuel consumed [kg]
3250
+ - **THR** - Thrust force [N]
3251
+ - **DRAG** - Drag force [N]
3252
+ - **time** - Elapsed time [s]
3253
+ - **dist** - Distance flown [NM]
3254
+ - **slope** - Trajectory slope [deg]
3255
+ - **mass** - Aircraft mass [kg]
3256
+ - **config** - Aerodynamic configuration
3257
+ - **LAT** - Latitude [deg]
3258
+ - **LON** - Longitude [deg]
3259
+ - **HDGTrue** - True heading [deg]
3260
+ - **HDGMagnetic** - Magnetic heading [deg]
3261
+ - **BankAngle** - Bank angle [deg]
3262
+ - **ROT** - Rate of turn [deg/s]
3263
+ - **Comment** - Comments for each segment
3264
+
3265
+ - **For BADAH:**
3266
+ - **Preq** - Required power [W]
3267
+ - **Peng** - Generated power [W]
3268
+ - **Pav** - Available power [W]
3269
+
3270
+ - **For BADAE (electric aircraft):**
3271
+ - **Pmec** - Mechanical power [W]
3272
+ - **Pelc** - Electrical power [W]
3273
+ - **Pbat** - Power supplied by the battery [W]
3274
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
3275
+ - **SOC** - Battery state of charge [%]
3276
+ - **Ibat** - Battery current [A]
3277
+ - **Vbat** - Battery voltage [V]
3278
+ - **Vgbat** - Ground battery voltage [V]
3279
+ :rtype: pandas.DataFrame
2987
3280
  """
2988
3281
 
2989
3282
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -3034,7 +3327,9 @@ def constantSpeedSlope(
3034
3327
 
3035
3328
  # speed brakes application
3036
3329
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
3037
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
3330
+ speedBrakes = kwargs.get(
3331
+ "speedBrakes", {"deployed": False, "value": 0.03}
3332
+ )
3038
3333
 
3039
3334
  # optional parameter - iteration step for altitude loop
3040
3335
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -3079,7 +3374,9 @@ def constantSpeedSlope(
3079
3374
  constHeadingStr = ""
3080
3375
 
3081
3376
  # comment line describing type of trajectory calculation
3082
- comment = phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
3377
+ comment = (
3378
+ phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
3379
+ )
3083
3380
 
3084
3381
  if Lat and Lon and (magneticHeading or trueHeading):
3085
3382
  comment = comment + "_" + headingToFly + "_Heading"
@@ -3100,7 +3397,9 @@ def constantSpeedSlope(
3100
3397
  )
3101
3398
 
3102
3399
  # weight iteration constant
3103
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
3400
+ m_iter = kwargs.get(
3401
+ "m_iter", 5
3402
+ ) # number of iterations for integration loop[-]
3104
3403
 
3105
3404
  # initialize output parameters
3106
3405
  Hp = []
@@ -3166,8 +3465,12 @@ def constantSpeedSlope(
3166
3465
 
3167
3466
  # atmosphere properties
3168
3467
  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)
3468
+ [theta, delta, sigma] = atm.atmosphereProperties(
3469
+ h=H_m, DeltaTemp=DeltaTemp
3470
+ )
3471
+ temp_const = (theta * const.temp_0) / (
3472
+ theta * const.temp_0 - DeltaTemp
3473
+ )
3171
3474
 
3172
3475
  # aircraft speed
3173
3476
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -3177,17 +3480,24 @@ def constantSpeedSlope(
3177
3480
  if turnFlight:
3178
3481
  if turnMetrics["bankAngle"] != 0.0:
3179
3482
  # bankAngle is defined
3180
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
3483
+ rateOfTurn = AC.rateOfTurn_bankAngle(
3484
+ TAS=TAS_i, bankAngle=bankAngle
3485
+ )
3181
3486
  else:
3182
3487
  # rateOfTurn is defined
3183
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
3488
+ bankAngle = AC.bankAngle(
3489
+ rateOfTurn=rateOfTurn, v=TAS_i
3490
+ ) # [degrees]
3184
3491
 
3185
3492
  # Load factor
3186
3493
  nz = 1 / cos(radians(bankAngle))
3187
3494
 
3188
3495
  # compute Energy Share Factor (ESF)
3189
3496
  ESF_i = AC.esf(
3190
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
3497
+ h=H_m,
3498
+ M=M_i,
3499
+ DeltaTemp=DeltaTemp,
3500
+ flightEvolution=("const" + speedType),
3191
3501
  )
3192
3502
 
3193
3503
  if AC.BADAFamily.BADAE:
@@ -3205,7 +3515,9 @@ def constantSpeedSlope(
3205
3515
  # BADAH or BADAE
3206
3516
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
3207
3517
  # compute Power required for level flight
3208
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
3518
+ Preq_i = AC.Preq(
3519
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
3520
+ )
3209
3521
  # Compute power required for target ROCD
3210
3522
  Preq_target_i = AC.Peng_target(
3211
3523
  temp=theta * const.temp_0,
@@ -3233,20 +3545,27 @@ def constantSpeedSlope(
3233
3545
  # ensure continuity of configuration change within the segment
3234
3546
  if config:
3235
3547
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
3236
- phase=phase, previousConfig=config[-1], currentConfig=config_i
3548
+ phase=phase,
3549
+ previousConfig=config[-1],
3550
+ currentConfig=config_i,
3237
3551
  )
3238
3552
 
3239
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
3553
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
3554
+ config=config_i
3555
+ )
3240
3556
 
3241
3557
  # compute lift coefficient
3242
3558
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
3243
3559
  # compute drag coefficient
3244
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
3560
+ CD = AC.CD(
3561
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
3562
+ )
3245
3563
  # compute drag force
3246
3564
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
3247
3565
  # compute thrust force
3248
3566
  THR_i = (
3249
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
3567
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
3568
+ + Drag
3250
3569
  ) # [N]
3251
3570
 
3252
3571
  # BADA3
@@ -3279,7 +3598,8 @@ def constantSpeedSlope(
3279
3598
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
3280
3599
  # compute thrust force
3281
3600
  THR_i = (
3282
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
3601
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
3602
+ + Drag
3283
3603
  ) # [N]
3284
3604
 
3285
3605
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -3378,21 +3698,39 @@ def constantSpeedSlope(
3378
3698
  Pelc_i = Preq_target_i / AC.eta
3379
3699
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
3380
3700
  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
3701
+ Vgbat_i = (
3702
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
3703
+ )
3382
3704
 
3383
3705
  # BADA4
3384
3706
  elif AC.BADAFamily.BADA4:
3385
3707
  THR_min = AC.Thrust(
3386
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3708
+ rating="LIDL",
3709
+ delta=delta,
3710
+ theta=theta,
3711
+ M=M_i,
3712
+ DeltaTemp=DeltaTemp,
3387
3713
  ) # IDLE Thrust
3388
3714
  FUEL_min = AC.ff(
3389
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3715
+ rating="LIDL",
3716
+ delta=delta,
3717
+ theta=theta,
3718
+ M=M_i,
3719
+ DeltaTemp=DeltaTemp,
3390
3720
  ) # IDLE Fuel Flow
3391
3721
  THR_max = AC.Thrust(
3392
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3722
+ rating="MCMB",
3723
+ delta=delta,
3724
+ theta=theta,
3725
+ M=M_i,
3726
+ DeltaTemp=DeltaTemp,
3393
3727
  ) # MCMB Thrust
3394
3728
  FUEL_max = AC.ff(
3395
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3729
+ rating="MCMB",
3730
+ delta=delta,
3731
+ theta=theta,
3732
+ M=M_i,
3733
+ DeltaTemp=DeltaTemp,
3396
3734
  ) # MCMB Fuel Flow
3397
3735
 
3398
3736
  if THR_i < THR_min:
@@ -3424,14 +3762,22 @@ def constantSpeedSlope(
3424
3762
  else:
3425
3763
  CT = AC.CT(Thrust=THR_i, delta=delta)
3426
3764
  FUEL_i = AC.ff(
3427
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
3765
+ CT=CT,
3766
+ delta=delta,
3767
+ theta=theta,
3768
+ M=M_i,
3769
+ DeltaTemp=DeltaTemp,
3428
3770
  ) # [kg/s]
3429
3771
  ROCD_i = conv.m2ft(ROCDisu) * 60
3430
3772
 
3431
3773
  # BADA3
3432
3774
  elif AC.BADAFamily.BADA3:
3433
3775
  THR_min = AC.Thrust(
3434
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
3776
+ rating="LIDL",
3777
+ v=TAS_i,
3778
+ h=H_m,
3779
+ config="CR",
3780
+ DeltaTemp=DeltaTemp,
3435
3781
  ) # IDLE Thrust
3436
3782
  FUEL_min = AC.ff(
3437
3783
  flightPhase="Descent",
@@ -3442,7 +3788,11 @@ def constantSpeedSlope(
3442
3788
  adapted=False,
3443
3789
  ) # IDLE Fuel Flow
3444
3790
  THR_max = AC.Thrust(
3445
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
3791
+ rating="MCMB",
3792
+ v=TAS_i,
3793
+ h=H_m,
3794
+ DeltaTemp=DeltaTemp,
3795
+ config="CR",
3446
3796
  ) # MCMB Thrust
3447
3797
  FUEL_max = AC.ff(
3448
3798
  flightPhase="Climb",
@@ -3590,10 +3940,14 @@ def constantSpeedSlope(
3590
3940
  gamma_i = 90 * np.sign(ROCD_i)
3591
3941
  else:
3592
3942
  if AC.BADAFamily.BADAE:
3593
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
3943
+ gamma_i = degrees(
3944
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
3945
+ )
3594
3946
  else:
3595
3947
  # 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))
3948
+ gamma_i = degrees(
3949
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
3950
+ )
3597
3951
 
3598
3952
  # ground speed can be calcualted as TAS projected on the ground minus wind
3599
3953
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -3629,7 +3983,9 @@ def constantSpeedSlope(
3629
3983
  if turnFlight:
3630
3984
  step_distance = conv.m2nm(
3631
3985
  turn.distance(
3632
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
3986
+ rateOfTurn=rateOfTurn,
3987
+ TAS=TAS_i,
3988
+ timeOfTurn=step_time,
3633
3989
  )
3634
3990
  ) # arcLength during the turn [NM]
3635
3991
  else:
@@ -3844,59 +4200,87 @@ def constantSpeedSlope_time(
3844
4200
  magneticDeclinationGrid=None,
3845
4201
  **kwargs,
3846
4202
  ):
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]}.
4203
+ """
4204
+ Computes the time, fuel, and trajectory parameters required by an aircraft to climb or descend at constant speed and slope over a given duration.
4205
+
4206
+ 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.
4207
+
4208
+ :param AC: Aircraft object {BADA3, BADA4, BADAH, BADAE}.
4209
+ :param length: Total duration of the segment [s].
4210
+ :param speedType: Speed type to follow during the trajectory {M, CAS, TAS}.
4211
+ :param v: Speed to follow (in knots for CAS/TAS or as a Mach number) [kt] or [-] for Mach.
4212
+ :param Hp_init: Initial pressure altitude [ft].
4213
+ :param slopetarget: Desired slope (trajectory angle) to follow [deg].
4214
+ :param m_init: Initial aircraft mass [kg].
4215
+ :param DeltaTemp: Deviation from standard ISA temperature [K].
4216
+ :param wS: Longitudinal wind speed component (affects ground speed) [kt]. Default is 0.0.
4217
+ :param turnMetrics: A dictionary defining the turn parameters:
4218
+
4219
+ - rateOfTurn [deg/s]
4220
+ - bankAngle [deg]
4221
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
4222
+ :param Lat: Initial latitude [deg]. Default is None.
4223
+ :param Lon: Initial longitude [deg]. Default is None.
4224
+ :param initialHeading: A dictionary specifying the initial heading (magnetic or true) and whether to fly a constant heading:
4225
+
4226
+ - magnetic: Magnetic heading [deg].
4227
+ - true: True heading [deg].
4228
+ - constantHeading: Whether to maintain a constant heading [True/False].
4229
+ :param reducedPower: Boolean specifying if reduced power is applied during climb/descent. Default is None.
4230
+ :param directionOfTurn: Direction of turn {LEFT, RIGHT}. Default is None.
4231
+ :param magneticDeclinationGrid: Optional magnetic declination grid for correcting magnetic heading. Default is None.
4232
+ :param kwargs: Additional optional parameters:
4233
+
4234
+ - step_length: Step length for trajectory calculation [s]. Default is 1 second.
4235
+ - Hp_step: Altitude step size for calculations [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
4236
+ - SOC_init: Initial battery state of charge (for electric aircraft) [%]. Default is 100.
4237
+ - config: Default aerodynamic configuration {TO, IC, CR, AP, LD}. If not provided, configuration is calculated automatically.
4238
+ - speedBrakes: Dictionary specifying if speed brakes are deployed and additional drag coefficient {deployed: False, value: 0.03}.
4239
+ - ROCD_min: Minimum Rate of Climb/Descent to determine service ceiling [ft/min]. Defaults depend on aircraft type and engine.
4240
+ - mass_const: Boolean indicating whether mass remains constant during the flight. Default is False.
4241
+ - m_iter: Number of iterations for mass integration. Default is 5.
4242
+
4243
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
4244
+
4245
+ - **Hp** - wAltitude [ft]
4246
+ - **TAS** - True Air Speed [kt]
4247
+ - **CAS** - Calibrated Air Speed [kt]
4248
+ - **GS** - Ground Speed [kt]
4249
+ - **M** - Mach number [-]
4250
+ - **ROCD** - Rate of Climb/Descent [ft/min]
4251
+ - **ESF** - Energy Share Factor [-]
4252
+ - **FUEL** - Fuel flow [kg/s]
4253
+ - **FUELCONSUMED** - Total fuel consumed [kg]
4254
+ - **THR** - Thrust force [N]
4255
+ - **DRAG** - Drag force [N]
4256
+ - **time** - Elapsed time [s]
4257
+ - **dist** - Distance flown [NM]
4258
+ - **slope** - Trajectory slope [deg]
4259
+ - **mass** - Aircraft mass [kg]
4260
+ - **config** - Aerodynamic configuration
4261
+ - **LAT** - Latitude [deg]
4262
+ - **LON** - Longitude [deg]
4263
+ - **HDGTrue** - True heading [deg]
4264
+ - **HDGMagnetic** - Magnetic heading [deg]
4265
+ - **BankAngle** - Bank angle [deg]
4266
+ - **ROT** - Rate of turn [deg/s]
4267
+ - **Comment** - Comments for each segment
4268
+
4269
+ - **For BADAH:**
4270
+ - **Preq** - Required power [W]
4271
+ - **Peng** - Generated power [W]
4272
+ - **Pav** - Available power [W]
4273
+
4274
+ - **For BADAE (electric aircraft):**
4275
+ - **Pmec** - Mechanical power [W]
4276
+ - **Pelc** - Electrical power [W]
4277
+ - **Pbat** - Power supplied by the battery [W]
4278
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
4279
+ - **SOC** - Battery state of charge [%]
4280
+ - **Ibat** - Battery current [A]
4281
+ - **Vbat** - Battery voltage [V]
4282
+ - **Vgbat** - Ground battery voltage [V]
4283
+ :rtype: pandas.DataFrame
3900
4284
  """
3901
4285
 
3902
4286
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -3947,7 +4331,9 @@ def constantSpeedSlope_time(
3947
4331
 
3948
4332
  # speed brakes application
3949
4333
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
3950
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
4334
+ speedBrakes = kwargs.get(
4335
+ "speedBrakes", {"deployed": False, "value": 0.03}
4336
+ )
3951
4337
 
3952
4338
  # step size in [s]
3953
4339
  step_length = kwargs.get("step_length", 1)
@@ -3980,7 +4366,9 @@ def constantSpeedSlope_time(
3980
4366
  constHeadingStr = ""
3981
4367
 
3982
4368
  # comment line describing type of trajectory calculation
3983
- comment = phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
4369
+ comment = (
4370
+ phase + turnComment + "_const_Slope_" + speedType + constHeadingStr
4371
+ )
3984
4372
 
3985
4373
  if Lat and Lon and (magneticHeading or trueHeading):
3986
4374
  comment = comment + "_" + headingToFly + "_Heading"
@@ -4001,7 +4389,9 @@ def constantSpeedSlope_time(
4001
4389
  )
4002
4390
 
4003
4391
  # weight iteration constant
4004
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
4392
+ m_iter = kwargs.get(
4393
+ "m_iter", 5
4394
+ ) # number of iterations for integration loop[-]
4005
4395
 
4006
4396
  # initialize output parameters
4007
4397
  Hp = [Hp_init]
@@ -4075,8 +4465,12 @@ def constantSpeedSlope_time(
4075
4465
  for _ in itertools.repeat(None, m_iter):
4076
4466
  # atmosphere properties
4077
4467
  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)
4468
+ [theta, delta, sigma] = atm.atmosphereProperties(
4469
+ h=H_m, DeltaTemp=DeltaTemp
4470
+ )
4471
+ temp_const = (theta * const.temp_0) / (
4472
+ theta * const.temp_0 - DeltaTemp
4473
+ )
4080
4474
 
4081
4475
  # aircraft speed
4082
4476
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -4086,7 +4480,9 @@ def constantSpeedSlope_time(
4086
4480
  if turnFlight:
4087
4481
  if turnMetrics["bankAngle"] != 0.0:
4088
4482
  # bankAngle is defined
4089
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
4483
+ rateOfTurn = AC.rateOfTurn_bankAngle(
4484
+ TAS=TAS_i, bankAngle=bankAngle
4485
+ )
4090
4486
  else:
4091
4487
  # rateOfTurn is defined
4092
4488
  bankAngle = AC.bankAngle(
@@ -4098,7 +4494,10 @@ def constantSpeedSlope_time(
4098
4494
 
4099
4495
  # compute Energy Share Factor (ESF)
4100
4496
  ESF_i = AC.esf(
4101
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
4497
+ h=H_m,
4498
+ M=M_i,
4499
+ DeltaTemp=DeltaTemp,
4500
+ flightEvolution=("const" + speedType),
4102
4501
  )
4103
4502
 
4104
4503
  step_time = length_loop - time[-1]
@@ -4106,14 +4505,20 @@ def constantSpeedSlope_time(
4106
4505
  # Compute required ROCD
4107
4506
  if AC.BADAFamily.BADAE:
4108
4507
  # special case for BADAE, in future it may apply also for BADAH
4109
- ROCDisu = tan(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4508
+ ROCDisu = (
4509
+ tan(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4510
+ )
4110
4511
  else:
4111
- ROCDisu = sin(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4512
+ ROCDisu = (
4513
+ sin(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
4514
+ )
4112
4515
 
4113
4516
  # BADAH or BADAE
4114
4517
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
4115
4518
  # compute Power required for level flight
4116
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
4519
+ Preq_i = AC.Preq(
4520
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
4521
+ )
4117
4522
  # Compute power required for target ROCD
4118
4523
  Preq_target_i = AC.Peng_target(
4119
4524
  temp=theta * const.temp_0,
@@ -4141,20 +4546,27 @@ def constantSpeedSlope_time(
4141
4546
  # ensure continuity of configuration change within the segment
4142
4547
  if config:
4143
4548
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
4144
- phase=phase, previousConfig=config[-1], currentConfig=config_i
4549
+ phase=phase,
4550
+ previousConfig=config[-1],
4551
+ currentConfig=config_i,
4145
4552
  )
4146
4553
 
4147
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
4554
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
4555
+ config=config_i
4556
+ )
4148
4557
 
4149
4558
  # compute lift coefficient
4150
4559
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
4151
4560
  # compute drag coefficient
4152
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
4561
+ CD = AC.CD(
4562
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
4563
+ )
4153
4564
  # compute drag force
4154
4565
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
4155
4566
  # compute thrust force
4156
4567
  THR_i = (
4157
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
4568
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
4569
+ + Drag
4158
4570
  ) # [N]
4159
4571
 
4160
4572
  # BADA3
@@ -4187,7 +4599,8 @@ def constantSpeedSlope_time(
4187
4599
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
4188
4600
  # compute thrust force
4189
4601
  THR_i = (
4190
- ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i) + Drag
4602
+ ROCDisu * mass_i * const.g * temp_const / (TAS_i * ESF_i)
4603
+ + Drag
4191
4604
  ) # [N]
4192
4605
 
4193
4606
  # check that required thrust/power fits in the avialable thrust/power envelope,
@@ -4286,21 +4699,39 @@ def constantSpeedSlope_time(
4286
4699
  Pelc_i = Preq_target_i / AC.eta
4287
4700
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
4288
4701
  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
4702
+ Vgbat_i = (
4703
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
4704
+ )
4290
4705
 
4291
4706
  # BADA4
4292
4707
  elif AC.BADAFamily.BADA4:
4293
4708
  THR_min = AC.Thrust(
4294
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4709
+ rating="LIDL",
4710
+ delta=delta,
4711
+ theta=theta,
4712
+ M=M_i,
4713
+ DeltaTemp=DeltaTemp,
4295
4714
  ) # IDLE Thrust
4296
4715
  FUEL_min = AC.ff(
4297
- rating="LIDL", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4716
+ rating="LIDL",
4717
+ delta=delta,
4718
+ theta=theta,
4719
+ M=M_i,
4720
+ DeltaTemp=DeltaTemp,
4298
4721
  ) # IDLE Fuel Flow
4299
4722
  THR_max = AC.Thrust(
4300
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4723
+ rating="MCMB",
4724
+ delta=delta,
4725
+ theta=theta,
4726
+ M=M_i,
4727
+ DeltaTemp=DeltaTemp,
4301
4728
  ) # MCMB Thrust
4302
4729
  FUEL_max = AC.ff(
4303
- rating="MCMB", delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4730
+ rating="MCMB",
4731
+ delta=delta,
4732
+ theta=theta,
4733
+ M=M_i,
4734
+ DeltaTemp=DeltaTemp,
4304
4735
  ) # MCMB Fuel Flow
4305
4736
 
4306
4737
  if THR_i < THR_min:
@@ -4332,14 +4763,22 @@ def constantSpeedSlope_time(
4332
4763
  else:
4333
4764
  CT = AC.CT(Thrust=THR_i, delta=delta)
4334
4765
  FUEL_i = AC.ff(
4335
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
4766
+ CT=CT,
4767
+ delta=delta,
4768
+ theta=theta,
4769
+ M=M_i,
4770
+ DeltaTemp=DeltaTemp,
4336
4771
  ) # [kg/s]
4337
4772
  ROCD_i = conv.m2ft(ROCDisu) * 60
4338
4773
 
4339
4774
  # BADA3
4340
4775
  elif AC.BADAFamily.BADA3:
4341
4776
  THR_min = AC.Thrust(
4342
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
4777
+ rating="LIDL",
4778
+ v=TAS_i,
4779
+ h=H_m,
4780
+ config="CR",
4781
+ DeltaTemp=DeltaTemp,
4343
4782
  ) # IDLE Thrust
4344
4783
  FUEL_min = AC.ff(
4345
4784
  flightPhase="Descent",
@@ -4350,7 +4789,11 @@ def constantSpeedSlope_time(
4350
4789
  adapted=False,
4351
4790
  ) # IDLE Fuel Flow
4352
4791
  THR_max = AC.Thrust(
4353
- rating="MCMB", v=TAS_i, h=H_m, DeltaTemp=DeltaTemp, config="CR"
4792
+ rating="MCMB",
4793
+ v=TAS_i,
4794
+ h=H_m,
4795
+ DeltaTemp=DeltaTemp,
4796
+ config="CR",
4354
4797
  ) # MCMB Thrust
4355
4798
  FUEL_max = AC.ff(
4356
4799
  flightPhase="Climb",
@@ -4502,12 +4945,18 @@ def constantSpeedSlope_time(
4502
4945
  [theta, delta, sigma] = atm.atmosphereProperties(
4503
4946
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
4504
4947
  )
4505
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
4948
+ temp_const = (theta * const.temp_0) / (
4949
+ theta * const.temp_0 - DeltaTemp
4950
+ )
4506
4951
  if AC.BADAFamily.BADAE:
4507
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
4952
+ gamma_i = degrees(
4953
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
4954
+ )
4508
4955
  else:
4509
4956
  # 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))
4957
+ gamma_i = degrees(
4958
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
4959
+ )
4511
4960
 
4512
4961
  # ground speed can be calcualted as TAS projected on the ground minus wind
4513
4962
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -4544,7 +4993,9 @@ def constantSpeedSlope_time(
4544
4993
  if turnFlight:
4545
4994
  step_distance = conv.m2nm(
4546
4995
  turn.distance(
4547
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
4996
+ rateOfTurn=rateOfTurn,
4997
+ TAS=TAS_i,
4998
+ timeOfTurn=step_time,
4548
4999
  )
4549
5000
  ) # arcLength during the turn [NM]
4550
5001
  else:
@@ -4747,58 +5198,89 @@ def constantSpeedRating(
4747
5198
  initRating=None,
4748
5199
  **kwargs,
4749
5200
  ):
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]}.
5201
+ """
5202
+ Calculates time, fuel consumption, and other parameters required for an aircraft to perform a climb or descent
5203
+ from an initial altitude (Hp_init) to a final altitude (Hp_final) while maintaining a constant speed and engine rating.
5204
+
5205
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key flight parameters
5206
+ such as fuel burn, rate of climb/descent (ROCD), thrust, drag, and energy requirements. The function also supports
5207
+ complex flight dynamics including turns, heading changes, and wind influences.
5208
+
5209
+ :param AC: Aircraft object {BADA3/4/H/E}.
5210
+ :param speedType: Type of speed to maintain during the flight {M (Mach), CAS, TAS}.
5211
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
5212
+ :param Hp_init: Initial pressure altitude [ft].
5213
+ :param Hp_final: Final pressure altitude [ft].
5214
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
5215
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
5216
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
5217
+ :param turnMetrics: A dictionary defining the turn parameters:
5218
+
5219
+ - rateOfTurn [deg/s]
5220
+ - bankAngle [deg]
5221
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
5222
+ :param Lat: Initial latitude [deg]. Default is None.
5223
+ :param Lon: Initial longitude [deg]. Default is None.
5224
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
5225
+
5226
+ - magnetic: Magnetic heading [deg].
5227
+ - true: True heading [deg].
5228
+ - constantHeading: Whether to maintain a constant heading. Default is None.
5229
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
5230
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
5231
+ :param expedite: Boolean flag to expedite climb/descent. Default is False.
5232
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
5233
+ :param kwargs: Additional optional parameters:
5234
+
5235
+ - Hp_step: Step size in altitude for the iterative calculation [ft]. Default is 1000 ft for BADA3/BADA4, 500 ft for BADAH/BADAE.
5236
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
5237
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
5238
+ - ROCD_min: Minimum rate of climb/descent used to determine service ceiling [ft/min]. Default varies based on aircraft type.
5239
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
5240
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
5241
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
5242
+
5243
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
5244
+
5245
+ - **Hp** - wAltitude [ft]
5246
+ - **TAS** - True Air Speed [kt]
5247
+ - **CAS** - Calibrated Air Speed [kt]
5248
+ - **GS** - Ground Speed [kt]
5249
+ - **M** - Mach number [-]
5250
+ - **ROCD** - Rate of Climb/Descent [ft/min]
5251
+ - **ESF** - Energy Share Factor [-]
5252
+ - **FUEL** - Fuel flow [kg/s]
5253
+ - **FUELCONSUMED** - Total fuel consumed [kg]
5254
+ - **THR** - Thrust force [N]
5255
+ - **DRAG** - Drag force [N]
5256
+ - **time** - Elapsed time [s]
5257
+ - **dist** - Distance flown [NM]
5258
+ - **slope** - Trajectory slope [deg]
5259
+ - **mass** - Aircraft mass [kg]
5260
+ - **config** - Aerodynamic configuration
5261
+ - **LAT** - Latitude [deg]
5262
+ - **LON** - Longitude [deg]
5263
+ - **HDGTrue** - True heading [deg]
5264
+ - **HDGMagnetic** - Magnetic heading [deg]
5265
+ - **BankAngle** - Bank angle [deg]
5266
+ - **ROT** - Rate of turn [deg/s]
5267
+ - **Comment** - Comments for each segment
5268
+
5269
+ - **For BADAH:**
5270
+ - **Preq** - Required power [W]
5271
+ - **Peng** - Generated power [W]
5272
+ - **Pav** - Available power [W]
5273
+
5274
+ - **For BADAE (electric aircraft):**
5275
+ - **Pmec** - Mechanical power [W]
5276
+ - **Pelc** - Electrical power [W]
5277
+ - **Pbat** - Power supplied by the battery [W]
5278
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
5279
+ - **SOC** - Battery state of charge [%]
5280
+ - **Ibat** - Battery current [A]
5281
+ - **Vbat** - Battery voltage [V]
5282
+ - **Vgbat** - Ground battery voltage [V]
5283
+ :rtype: pandas.DataFrame
4802
5284
  """
4803
5285
 
4804
5286
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -4849,7 +5331,9 @@ def constantSpeedRating(
4849
5331
 
4850
5332
  # speed brakes application
4851
5333
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
4852
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
5334
+ speedBrakes = kwargs.get(
5335
+ "speedBrakes", {"deployed": False, "value": 0.03}
5336
+ )
4853
5337
 
4854
5338
  # optional parameter - iteration step for altitude loop
4855
5339
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
@@ -4908,7 +5392,13 @@ def constantSpeedRating(
4908
5392
 
4909
5393
  # comment line describing type of trajectory calculation
4910
5394
  comment = (
4911
- phase + turnComment + "_const_" + speedType + "_" + rating + constHeadingStr
5395
+ phase
5396
+ + turnComment
5397
+ + "_const_"
5398
+ + speedType
5399
+ + "_"
5400
+ + rating
5401
+ + constHeadingStr
4912
5402
  )
4913
5403
 
4914
5404
  if Lat and Lon and (magneticHeading or trueHeading):
@@ -4933,7 +5423,9 @@ def constantSpeedRating(
4933
5423
  )
4934
5424
 
4935
5425
  # weight iteration constant
4936
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
5426
+ m_iter = kwargs.get(
5427
+ "m_iter", 5
5428
+ ) # number of iterations for integration loop[-]
4937
5429
 
4938
5430
  # The thrust_fuel method for BADA 3 models applies the cruise fuel correction
4939
5431
  # whenever the thrust is adapted, instead of only in cruise: this correction
@@ -5004,8 +5496,12 @@ def constantSpeedRating(
5004
5496
  ## atmosphere, speeds, thrust. fuel flow, ESF
5005
5497
  # atmosphere properties
5006
5498
  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)
5499
+ [theta, delta, sigma] = atm.atmosphereProperties(
5500
+ h=H_m, DeltaTemp=DeltaTemp
5501
+ )
5502
+ temp_const = (theta * const.temp_0) / (
5503
+ theta * const.temp_0 - DeltaTemp
5504
+ )
5009
5505
 
5010
5506
  # aircraft speed
5011
5507
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -5015,17 +5511,24 @@ def constantSpeedRating(
5015
5511
  if turnFlight:
5016
5512
  if turnMetrics["bankAngle"] != 0.0:
5017
5513
  # bankAngle is defined
5018
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
5514
+ rateOfTurn = AC.rateOfTurn_bankAngle(
5515
+ TAS=TAS_i, bankAngle=bankAngle
5516
+ )
5019
5517
  else:
5020
5518
  # rateOfTurn is defined
5021
- bankAngle = AC.bankAngle(rateOfTurn=rateOfTurn, v=TAS_i) # [degrees]
5519
+ bankAngle = AC.bankAngle(
5520
+ rateOfTurn=rateOfTurn, v=TAS_i
5521
+ ) # [degrees]
5022
5522
 
5023
5523
  # Load factor
5024
5524
  nz = 1 / cos(radians(bankAngle))
5025
5525
 
5026
5526
  # compute Energy Share Factor (ESF)
5027
5527
  ESF_i = AC.esf(
5028
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
5528
+ h=H_m,
5529
+ M=M_i,
5530
+ DeltaTemp=DeltaTemp,
5531
+ flightEvolution=("const" + speedType),
5029
5532
  )
5030
5533
 
5031
5534
  mass_i = mass[-1]
@@ -5034,7 +5537,9 @@ def constantSpeedRating(
5034
5537
  if AC.BADAFamily.BADAH:
5035
5538
  # compute available power
5036
5539
  if rating == "UNKNOWN":
5037
- Preq_target_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
5540
+ Preq_target_i = (
5541
+ 0.1 * AC.P0
5542
+ ) # No minimum power model: assume 10% torque
5038
5543
  else:
5039
5544
  Preq_target_i = AC.Pav(rating=rating, theta=theta, delta=delta)
5040
5545
 
@@ -5048,7 +5553,9 @@ def constantSpeedRating(
5048
5553
  elif AC.BADAFamily.BADAE:
5049
5554
  # compute available power
5050
5555
  if rating == "UNKNOWN":
5051
- Preq_target_i = 0.1 * AC.P0 # No minimum power model: assume 10% torque
5556
+ Preq_target_i = (
5557
+ 0.1 * AC.P0
5558
+ ) # No minimum power model: assume 10% torque
5052
5559
  else:
5053
5560
  Preq_target_i = AC.Pav(rating=rating, SOC=SOC[-1])
5054
5561
 
@@ -5067,10 +5574,16 @@ def constantSpeedRating(
5067
5574
  elif AC.BADAFamily.BADA4:
5068
5575
  # compute thrust force and fuel flow
5069
5576
  THR_i = AC.Thrust(
5070
- rating=rating, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
5577
+ rating=rating,
5578
+ delta=delta,
5579
+ theta=theta,
5580
+ M=M_i,
5581
+ DeltaTemp=DeltaTemp,
5071
5582
  ) # [N]
5072
5583
  CT = AC.CT(Thrust=THR_i, delta=delta)
5073
- FUEL_i = AC.ff(CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp)
5584
+ FUEL_i = AC.ff(
5585
+ CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
5586
+ )
5074
5587
 
5075
5588
  # BADA3
5076
5589
  elif AC.BADAFamily.BADA3:
@@ -5089,12 +5602,18 @@ def constantSpeedRating(
5089
5602
  # ensure continuity of configuration change within the segment
5090
5603
  if config:
5091
5604
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5092
- phase=phase, previousConfig=config[-1], currentConfig=config_i
5605
+ phase=phase,
5606
+ previousConfig=config[-1],
5607
+ currentConfig=config_i,
5093
5608
  )
5094
5609
 
5095
5610
  # compute thrust force and fuel flow
5096
5611
  THR_i = AC.Thrust(
5097
- rating=rating, v=TAS_i, h=H_m, config=config_i, DeltaTemp=DeltaTemp
5612
+ rating=rating,
5613
+ v=TAS_i,
5614
+ h=H_m,
5615
+ config=config_i,
5616
+ DeltaTemp=DeltaTemp,
5098
5617
  )
5099
5618
  FUEL_i = AC.ff(
5100
5619
  flightPhase=phase,
@@ -5122,7 +5641,9 @@ def constantSpeedRating(
5122
5641
  # BADAH or BADAE
5123
5642
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
5124
5643
  # compute Power required
5125
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
5644
+ Preq_i = AC.Preq(
5645
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
5646
+ )
5126
5647
  # compute ROCD
5127
5648
  ROCD_i = (
5128
5649
  conv.m2ft(
@@ -5155,15 +5676,21 @@ def constantSpeedRating(
5155
5676
  # ensure continuity of configuration change within the segment
5156
5677
  if config:
5157
5678
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5158
- phase=phase, previousConfig=config[-1], currentConfig=config_i
5679
+ phase=phase,
5680
+ previousConfig=config[-1],
5681
+ currentConfig=config_i,
5159
5682
  )
5160
5683
 
5161
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
5684
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
5685
+ config=config_i
5686
+ )
5162
5687
 
5163
5688
  # compute lift coefficient
5164
5689
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
5165
5690
  # compute drag coefficient
5166
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
5691
+ CD = AC.CD(
5692
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
5693
+ )
5167
5694
  # compute drag force
5168
5695
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
5169
5696
  # compute ROCD
@@ -5204,7 +5731,10 @@ def constantSpeedRating(
5204
5731
  CL = AC.CL(tas=TAS_i, sigma=sigma, mass=mass_i, nz=nz)
5205
5732
  # compute drag coefficient
5206
5733
  CD = AC.CD(
5207
- CL=CL, config=config_i, expedite=expedite, speedBrakes=speedBrakes
5734
+ CL=CL,
5735
+ config=config_i,
5736
+ expedite=expedite,
5737
+ speedBrakes=speedBrakes,
5208
5738
  )
5209
5739
  # compute drag force
5210
5740
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
@@ -5327,10 +5857,14 @@ def constantSpeedRating(
5327
5857
  gamma_i = 90 * np.sign(ROCD_i)
5328
5858
  else:
5329
5859
  if AC.BADAFamily.BADAE:
5330
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
5860
+ gamma_i = degrees(
5861
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
5862
+ )
5331
5863
  else:
5332
5864
  # 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))
5865
+ gamma_i = degrees(
5866
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
5867
+ )
5334
5868
 
5335
5869
  # ground speed can be calcualted as TAS projected on the ground minus wind
5336
5870
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -5366,7 +5900,9 @@ def constantSpeedRating(
5366
5900
  if turnFlight:
5367
5901
  step_distance = conv.m2nm(
5368
5902
  turn.distance(
5369
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
5903
+ rateOfTurn=rateOfTurn,
5904
+ TAS=TAS_i,
5905
+ timeOfTurn=step_time,
5370
5906
  )
5371
5907
  ) # arcLength during the turn [NM]
5372
5908
  else:
@@ -5583,60 +6119,91 @@ def constantSpeedRating_time(
5583
6119
  initRating=None,
5584
6120
  **kwargs,
5585
6121
  ):
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]}.
6122
+ """
6123
+ Calculates the time, fuel consumption, and other flight parameters required for an aircraft to perform
6124
+ a climb or descent at constant speed and engine rating for a specified duration.
6125
+
6126
+ It uses different models for BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE) to compute key parameters
6127
+ such as rate of climb/descent (ROCD), thrust, drag, fuel burn, and power requirements. The function also supports complex
6128
+ flight dynamics, including turns, heading changes, and the effect of wind.
6129
+
6130
+ :param AC: Aircraft object {BADA3/4/H/E}.
6131
+ :param length: Duration of the flight segment [s].
6132
+ :param speedType: Type of speed to maintain during the flight {M, CAS, TAS}.
6133
+ :param v: Speed to follow - [kt] CAS/TAS or [-] MACH.
6134
+ :param Hp_init: Initial pressure altitude [ft].
6135
+ :param phase: Phase of flight (Climb or Descent).
6136
+ :param m_init: Initial mass of the aircraft at the start of the segment [kg].
6137
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
6138
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
6139
+ :param turnMetrics: A dictionary defining the turn parameters:
6140
+
6141
+ - rateOfTurn [deg/s]
6142
+ - bankAngle [deg]
6143
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
6144
+ :param Lat: Initial latitude [deg]. Default is None.
6145
+ :param Lon: Initial longitude [deg]. Default is None.
6146
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
6147
+
6148
+ - magnetic: Magnetic heading [deg].
6149
+ - true: True heading [deg].
6150
+ - constantHeading: Whether to maintain a constant heading. Default is None.
6151
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
6152
+ :param directionOfTurn: Direction of the turn {LEFT, RIGHT}. Default is None.
6153
+ :param expedite: Boolean flag to expedite the climb/descent. Default is False.
6154
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
6155
+ :param initRating: Initial engine rating settings. Default is None.
6156
+ :param kwargs: Additional optional parameters:
6157
+
6158
+ - step_length: Step size in time for the iterative calculation [s]. Default is 1 s.
6159
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
6160
+ - speedBrakes: A dictionary specifying whether speed brakes are deployed and the additional drag coefficient {deployed: False, value: 0.03}.
6161
+ - ROCD_min: Minimum rate of climb/descent to determine service ceiling [ft/min]. Default varies by aircraft type.
6162
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
6163
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
6164
+ - m_iter: Number of iterations for the mass integration loop. Default is 5.
6165
+
6166
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
6167
+
6168
+ - **Hp** - wAltitude [ft]
6169
+ - **TAS** - True Air Speed [kt]
6170
+ - **CAS** - Calibrated Air Speed [kt]
6171
+ - **GS** - Ground Speed [kt]
6172
+ - **M** - Mach number [-]
6173
+ - **ROCD** - Rate of Climb/Descent [ft/min]
6174
+ - **ESF** - Energy Share Factor [-]
6175
+ - **FUEL** - Fuel flow [kg/s]
6176
+ - **FUELCONSUMED** - Total fuel consumed [kg]
6177
+ - **THR** - Thrust force [N]
6178
+ - **DRAG** - Drag force [N]
6179
+ - **time** - Elapsed time [s]
6180
+ - **dist** - Distance flown [NM]
6181
+ - **slope** - Trajectory slope [deg]
6182
+ - **mass** - Aircraft mass [kg]
6183
+ - **config** - Aerodynamic configuration
6184
+ - **LAT** - Latitude [deg]
6185
+ - **LON** - Longitude [deg]
6186
+ - **HDGTrue** - True heading [deg]
6187
+ - **HDGMagnetic** - Magnetic heading [deg]
6188
+ - **BankAngle** - Bank angle [deg]
6189
+ - **ROT** - Rate of turn [deg/s]
6190
+ - **Comment** - Comments for each segment
6191
+
6192
+ - **For BADAH:**
6193
+ - **Preq** - Required power [W]
6194
+ - **Peng** - Generated power [W]
6195
+ - **Pav** - Available power [W]
6196
+
6197
+ - **For BADAE (electric aircraft):**
6198
+ - **Pmec** - Mechanical power [W]
6199
+ - **Pelc** - Electrical power [W]
6200
+ - **Pbat** - Power supplied by the battery [W]
6201
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
6202
+ - **SOC** - Battery state of charge [%]
6203
+ - **Ibat** - Battery current [A]
6204
+ - **Vbat** - Battery voltage [V]
6205
+ - **Vgbat** - Ground battery voltage [V]
6206
+ :rtype: pandas.DataFrame
5640
6207
  """
5641
6208
 
5642
6209
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -5687,7 +6254,9 @@ def constantSpeedRating_time(
5687
6254
 
5688
6255
  # speed brakes application
5689
6256
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
5690
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
6257
+ speedBrakes = kwargs.get(
6258
+ "speedBrakes", {"deployed": False, "value": 0.03}
6259
+ )
5691
6260
 
5692
6261
  # step size in [s]
5693
6262
  step_length = kwargs.get("step_length", 1)
@@ -5722,7 +6291,9 @@ def constantSpeedRating_time(
5722
6291
  else:
5723
6292
  rating = "LIDL"
5724
6293
  else:
5725
- raise Exception("Phase definition is wrong! It should be Climb or Descent")
6294
+ raise Exception(
6295
+ "Phase definition is wrong! It should be Climb or Descent"
6296
+ )
5726
6297
  else:
5727
6298
  rating = initRating
5728
6299
 
@@ -5738,7 +6309,13 @@ def constantSpeedRating_time(
5738
6309
 
5739
6310
  # comment line describing type of trajectory calculation
5740
6311
  comment = (
5741
- phase + turnComment + "_const_" + speedType + "_" + rating + constHeadingStr
6312
+ phase
6313
+ + turnComment
6314
+ + "_const_"
6315
+ + speedType
6316
+ + "_"
6317
+ + rating
6318
+ + constHeadingStr
5742
6319
  )
5743
6320
 
5744
6321
  if Lat and Lon and (magneticHeading or trueHeading):
@@ -5763,7 +6340,9 @@ def constantSpeedRating_time(
5763
6340
  )
5764
6341
 
5765
6342
  # weight iteration constant
5766
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
6343
+ m_iter = kwargs.get(
6344
+ "m_iter", 5
6345
+ ) # number of iterations for integration loop[-]
5767
6346
 
5768
6347
  # The thrust_fuel method for BADA 3 models applies the cruise fuel correction
5769
6348
  # whenever the thrust is adapted, instead of only in cruise: this correction
@@ -5843,8 +6422,12 @@ def constantSpeedRating_time(
5843
6422
  for _ in itertools.repeat(None, m_iter):
5844
6423
  # atmosphere properties
5845
6424
  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)
6425
+ [theta, delta, sigma] = atm.atmosphereProperties(
6426
+ h=H_m, DeltaTemp=DeltaTemp
6427
+ )
6428
+ temp_const = (theta * const.temp_0) / (
6429
+ theta * const.temp_0 - DeltaTemp
6430
+ )
5848
6431
 
5849
6432
  # aircraft speed
5850
6433
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
@@ -5854,7 +6437,9 @@ def constantSpeedRating_time(
5854
6437
  if turnFlight:
5855
6438
  if turnMetrics["bankAngle"] != 0.0:
5856
6439
  # bankAngle is defined
5857
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
6440
+ rateOfTurn = AC.rateOfTurn_bankAngle(
6441
+ TAS=TAS_i, bankAngle=bankAngle
6442
+ )
5858
6443
  else:
5859
6444
  # rateOfTurn is defined
5860
6445
  bankAngle = AC.bankAngle(
@@ -5866,7 +6451,10 @@ def constantSpeedRating_time(
5866
6451
 
5867
6452
  # compute Energy Share Factor (ESF)
5868
6453
  ESF_i = AC.esf(
5869
- h=H_m, M=M_i, DeltaTemp=DeltaTemp, flightEvolution=("const" + speedType)
6454
+ h=H_m,
6455
+ M=M_i,
6456
+ DeltaTemp=DeltaTemp,
6457
+ flightEvolution=("const" + speedType),
5870
6458
  )
5871
6459
 
5872
6460
  step_time = length_loop - time[-1]
@@ -5879,7 +6467,9 @@ def constantSpeedRating_time(
5879
6467
  0.1 * AC.P0
5880
6468
  ) # No minimum power model: assume 10% torque
5881
6469
  else:
5882
- Preq_target_i = AC.Pav(rating=rating, theta=theta, delta=delta)
6470
+ Preq_target_i = AC.Pav(
6471
+ rating=rating, theta=theta, delta=delta
6472
+ )
5883
6473
 
5884
6474
  Pav_i = AC.Pav(rating="MTKF", theta=theta, delta=delta)
5885
6475
 
@@ -5904,13 +6494,19 @@ def constantSpeedRating_time(
5904
6494
  Pelc_i = Preq_target_i / AC.eta
5905
6495
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
5906
6496
  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
6497
+ Vgbat_i = (
6498
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
6499
+ )
5908
6500
 
5909
6501
  # BADA4
5910
6502
  elif AC.BADAFamily.BADA4:
5911
6503
  # compute thrust force and fuel flow
5912
6504
  THR_i = AC.Thrust(
5913
- rating=rating, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
6505
+ rating=rating,
6506
+ delta=delta,
6507
+ theta=theta,
6508
+ M=M_i,
6509
+ DeltaTemp=DeltaTemp,
5914
6510
  ) # [N]
5915
6511
  CT = AC.CT(Thrust=THR_i, delta=delta)
5916
6512
  FUEL_i = AC.ff(
@@ -5941,7 +6537,11 @@ def constantSpeedRating_time(
5941
6537
 
5942
6538
  # compute thrust force and fuel flow
5943
6539
  THR_i = AC.Thrust(
5944
- rating=rating, v=TAS_i, h=H_m, config=config_i, DeltaTemp=DeltaTemp
6540
+ rating=rating,
6541
+ v=TAS_i,
6542
+ h=H_m,
6543
+ config=config_i,
6544
+ DeltaTemp=DeltaTemp,
5945
6545
  )
5946
6546
  FUEL_i = AC.ff(
5947
6547
  flightPhase=phase,
@@ -5955,7 +6555,9 @@ def constantSpeedRating_time(
5955
6555
  # BADAH or BADAE
5956
6556
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
5957
6557
  # compute Power required
5958
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
6558
+ Preq_i = AC.Preq(
6559
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
6560
+ )
5959
6561
  # compute ROCD
5960
6562
  ROCD_i = (
5961
6563
  conv.m2ft(
@@ -5988,15 +6590,21 @@ def constantSpeedRating_time(
5988
6590
  # ensure continuity of configuration change within the segment
5989
6591
  if config:
5990
6592
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
5991
- phase=phase, previousConfig=config[-1], currentConfig=config_i
6593
+ phase=phase,
6594
+ previousConfig=config[-1],
6595
+ currentConfig=config_i,
5992
6596
  )
5993
6597
 
5994
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
6598
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
6599
+ config=config_i
6600
+ )
5995
6601
 
5996
6602
  # compute lift coefficient
5997
6603
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
5998
6604
  # compute drag coefficient
5999
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
6605
+ CD = AC.CD(
6606
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
6607
+ )
6000
6608
  # compute drag force
6001
6609
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
6002
6610
 
@@ -6037,7 +6645,10 @@ def constantSpeedRating_time(
6037
6645
  CL = AC.CL(tas=TAS_i, sigma=sigma, mass=mass_i, nz=nz)
6038
6646
  # compute drag coefficient
6039
6647
  CD = AC.CD(
6040
- CL=CL, config=config_i, expedite=expedite, speedBrakes=speedBrakes
6648
+ CL=CL,
6649
+ config=config_i,
6650
+ expedite=expedite,
6651
+ speedBrakes=speedBrakes,
6041
6652
  )
6042
6653
  # compute drag force
6043
6654
  Drag = AC.D(tas=TAS_i, sigma=sigma, CD=CD)
@@ -6167,12 +6778,18 @@ def constantSpeedRating_time(
6167
6778
  [theta, delta, sigma] = atm.atmosphereProperties(
6168
6779
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
6169
6780
  )
6170
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
6781
+ temp_const = (theta * const.temp_0) / (
6782
+ theta * const.temp_0 - DeltaTemp
6783
+ )
6171
6784
  if AC.BADAFamily.BADAE:
6172
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
6785
+ gamma_i = degrees(
6786
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
6787
+ )
6173
6788
  else:
6174
6789
  # 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))
6790
+ gamma_i = degrees(
6791
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
6792
+ )
6176
6793
 
6177
6794
  # ground speed can be calcualted as TAS projected on the ground minus wind
6178
6795
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -6209,7 +6826,9 @@ def constantSpeedRating_time(
6209
6826
  if turnFlight:
6210
6827
  step_distance = conv.m2nm(
6211
6828
  turn.distance(
6212
- rateOfTurn=rateOfTurn, TAS=TAS_i, timeOfTurn=step_time
6829
+ rateOfTurn=rateOfTurn,
6830
+ TAS=TAS_i,
6831
+ timeOfTurn=step_time,
6213
6832
  )
6214
6833
  ) # arcLength during the turn [NM]
6215
6834
  else:
@@ -6411,77 +7030,102 @@ def accDec(
6411
7030
  magneticDeclinationGrid=None,
6412
7031
  **kwargs,
6413
7032
  ):
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
7033
+ """
7034
+ Calculates the time, fuel consumption, and other key flight parameters required for an aircraft
7035
+ to perform an acceleration or deceleration from an initial speed (v_init) to a final speed (v_final)
7036
+ during the climb, cruise, or descent phases of flight.
7037
+
7038
+ The flight parameters are calculated using different models for the BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE).
7039
+ The function can also accommodate different control laws, vertical evolution phases, wind conditions, and complex flight dynamics like turns.
6415
7040
 
6416
7041
  .. 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]}.
7042
+ The control law used during the segment depends on the targets provided in the input parameter 'control':
7043
+
7044
+ - ROCD/slope+ESF: Law based on ROCD/slope + ESF
7045
+ - ROCD/slope+acc: Law based on ROCD/slope + acceleration
7046
+ - ROCD/slope only: Law based on rating + ROCD/slope
7047
+ - ESF only: Law based on rating + ESF
7048
+ - acc only: Law based on rating + acceleration
7049
+ - Neither: Law is rating + default ESF
7050
+
7051
+ :param AC: Aircraft object {BADA3/4/H/E}.
7052
+ :param speedType: Type of speed being followed {M, CAS, TAS}.
7053
+ :param v_init: Initial speed [kt] (CAS/TAS) or [-] MACH.
7054
+ :param v_final: Final speed [kt] (CAS/TAS) or [-] MACH.
7055
+ :param phase: Vertical evolution phase {Climb, Descent, Cruise}.
7056
+ :param control: A dictionary containing the following targets:
7057
+
7058
+ - ROCDtarget: Rate of climb/descent to be followed [ft/min].
7059
+ - slopetarget: Slope (flight path angle) to be followed [deg].
7060
+ - acctarget: Acceleration to be followed [m/s^2].
7061
+ - ESFtarget: Energy Share Factor to be followed [-].
7062
+ :param Hp_init: Initial pressure altitude [ft].
7063
+ :param m_init: Initial aircraft mass [kg].
7064
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
7065
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
7066
+ :param turnMetrics: A dictionary defining turn parameters:
7067
+
7068
+ - rateOfTurn [deg/s]
7069
+ - bankAngle [deg]
7070
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
7071
+ :param Lat: Initial latitude [deg]. Default is None.
7072
+ :param Lon: Initial longitude [deg]. Default is None.
7073
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
7074
+
7075
+ - magnetic: Magnetic heading [deg].
7076
+ - true: True heading [deg].
7077
+ - constantHeading: Whether to maintain a constant heading. Default is None.
7078
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
7079
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
7080
+ :param kwargs: Additional optional parameters:
7081
+
7082
+ - 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.
7083
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
7084
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
7085
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
7086
+ - m_iter: Number of iterations for the mass integration loop. Default is 10 for BADA3/4/H, 5 for BADAE.
7087
+
7088
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
7089
+
7090
+ - **Hp** - wAltitude [ft]
7091
+ - **TAS** - True Air Speed [kt]
7092
+ - **CAS** - Calibrated Air Speed [kt]
7093
+ - **GS** - Ground Speed [kt]
7094
+ - **M** - Mach number [-]
7095
+ - **ROCD** - Rate of Climb/Descent [ft/min]
7096
+ - **ESF** - Energy Share Factor [-]
7097
+ - **FUEL** - Fuel flow [kg/s]
7098
+ - **FUELCONSUMED** - Total fuel consumed [kg]
7099
+ - **THR** - Thrust force [N]
7100
+ - **DRAG** - Drag force [N]
7101
+ - **time** - Elapsed time [s]
7102
+ - **dist** - Distance flown [NM]
7103
+ - **slope** - Trajectory slope [deg]
7104
+ - **mass** - Aircraft mass [kg]
7105
+ - **config** - Aerodynamic configuration
7106
+ - **LAT** - Latitude [deg]
7107
+ - **LON** - Longitude [deg]
7108
+ - **HDGTrue** - True heading [deg]
7109
+ - **HDGMagnetic** - Magnetic heading [deg]
7110
+ - **BankAngle** - Bank angle [deg]
7111
+ - **ROT** - Rate of turn [deg/s]
7112
+ - **Comment** - Comments for each segment
7113
+
7114
+ - **For BADAH:**
7115
+ - **Preq** - Required power [W]
7116
+ - **Peng** - Generated power [W]
7117
+ - **Pav** - Available power [W]
7118
+
7119
+ - **For BADAE (electric aircraft):**
7120
+ - **Pmec** - Mechanical power [W]
7121
+ - **Pelc** - Electrical power [W]
7122
+ - **Pbat** - Power supplied by the battery [W]
7123
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
7124
+ - **SOC** - Battery state of charge [%]
7125
+ - **Ibat** - Battery current [A]
7126
+ - **Vbat** - Battery voltage [V]
7127
+ - **Vgbat** - Ground battery voltage [V]
7128
+ :rtype: pandas.DataFrame
6485
7129
  """
6486
7130
 
6487
7131
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -6532,7 +7176,9 @@ def accDec(
6532
7176
 
6533
7177
  # speed brakes application
6534
7178
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
6535
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
7179
+ speedBrakes = kwargs.get(
7180
+ "speedBrakes", {"deployed": False, "value": 0.03}
7181
+ )
6536
7182
 
6537
7183
  # iteratin step of speed loop
6538
7184
  if speedType == "M":
@@ -6543,7 +7189,9 @@ def accDec(
6543
7189
  # number of iteration of mass/altitude loop
6544
7190
  # BADAE
6545
7191
  if AC.BADAFamily.BADAE:
6546
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
7192
+ m_iter = kwargs.get(
7193
+ "m_iter", 5
7194
+ ) # number of iterations for integration loop[-]
6547
7195
  # BADA3 or BADA4 or BADAH
6548
7196
  else:
6549
7197
  m_iter = kwargs.get(
@@ -6700,9 +7348,9 @@ def accDec(
6700
7348
  maxRating = checkArgument("maxRating", **kwargs)
6701
7349
 
6702
7350
  # 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
- ):
7351
+ if (
7352
+ control.ROCDtarget is not None or control.slopetarget is not None
7353
+ ) and (control.ESFtarget is not None or control.acctarget is not None):
6706
7354
  rating = None
6707
7355
  else:
6708
7356
  if phase == "Climb" or (phase == "Cruise" and speedEvol == "acc"):
@@ -6806,18 +7454,28 @@ def accDec(
6806
7454
  for _ in itertools.repeat(None, m_iter):
6807
7455
  # atmosphere properties
6808
7456
  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)
7457
+ [theta, delta, sigma] = atm.atmosphereProperties(
7458
+ h=H_m, DeltaTemp=DeltaTemp
7459
+ )
7460
+ temp_const = (theta * const.temp_0) / (
7461
+ theta * const.temp_0 - DeltaTemp
7462
+ )
6811
7463
 
6812
7464
  # aircraft speed
6813
7465
  [M_i, CAS_i, TAS_i] = atm.convertSpeed(
6814
- v=v_i, speedType=speedType, theta=theta, delta=delta, sigma=sigma
7466
+ v=v_i,
7467
+ speedType=speedType,
7468
+ theta=theta,
7469
+ delta=delta,
7470
+ sigma=sigma,
6815
7471
  )
6816
7472
 
6817
7473
  if turnFlight:
6818
7474
  if turnMetrics["bankAngle"] != 0.0:
6819
7475
  # bankAngle is defined
6820
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
7476
+ rateOfTurn = AC.rateOfTurn_bankAngle(
7477
+ TAS=TAS_i, bankAngle=bankAngle
7478
+ )
6821
7479
  else:
6822
7480
  # rateOfTurn is defined
6823
7481
  bankAngle = AC.bankAngle(
@@ -6845,7 +7503,9 @@ def accDec(
6845
7503
  # BADAH or BADAE
6846
7504
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
6847
7505
  # compute Power required
6848
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
7506
+ Preq_i = AC.Preq(
7507
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
7508
+ )
6849
7509
 
6850
7510
  # compute engine power
6851
7511
  if rating is None:
@@ -6863,11 +7523,17 @@ def accDec(
6863
7523
 
6864
7524
  # Check that required thrust/power fits in the available thrust/power envelope,
6865
7525
  # recompute ROCD if necessary and compute fuel coefficient accordingly
6866
- Pmin = 0.1 * AC.P0 # No minimum power model: assume 10% torque
7526
+ Pmin = (
7527
+ 0.1 * AC.P0
7528
+ ) # No minimum power model: assume 10% torque
6867
7529
 
6868
7530
  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)
7531
+ Pmax = AC.Pav(
7532
+ rating=maxRating, theta=theta, delta=delta
7533
+ )
7534
+ Pav_i = AC.Pav(
7535
+ rating=maxRating, theta=theta, delta=delta
7536
+ )
6871
7537
  elif AC.BADAFamily.BADAE:
6872
7538
  Pmax = AC.Pav(rating=maxRating, SOC=SOC[-1])
6873
7539
  Pav_i = AC.Pav(rating=maxRating, SOC=SOC[-1])
@@ -6892,7 +7558,11 @@ def accDec(
6892
7558
  elif control.acctarget is not None:
6893
7559
  ROCD_i = (
6894
7560
  conv.m2ft(
6895
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
7561
+ (
7562
+ P_i
7563
+ - mass_i * TAS_i * control.acctarget
7564
+ - Preq_i
7565
+ )
6896
7566
  / (mass_i * const.g * temp_const)
6897
7567
  )
6898
7568
  * 60
@@ -6918,7 +7588,11 @@ def accDec(
6918
7588
  elif control.acctarget is not None:
6919
7589
  ROCD_i = (
6920
7590
  conv.m2ft(
6921
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
7591
+ (
7592
+ P_i
7593
+ - mass_i * TAS_i * control.acctarget
7594
+ - Preq_i
7595
+ )
6922
7596
  / (mass_i * const.g * temp_const)
6923
7597
  )
6924
7598
  * 60
@@ -6929,12 +7603,20 @@ def accDec(
6929
7603
  else:
6930
7604
  # Compute available power
6931
7605
  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)
7606
+ P_i = (
7607
+ 0.1 * AC.P0
7608
+ ) # No minimum power model: assume 10% torque
7609
+ Pav_i = AC.Pav(
7610
+ rating=maxRating, theta=theta, delta=delta
7611
+ )
6934
7612
  else:
6935
7613
  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)
7614
+ P_i = AC.Pav(
7615
+ rating=rating, theta=theta, delta=delta
7616
+ )
7617
+ Pav_i = AC.Pav(
7618
+ rating=rating, theta=theta, delta=delta
7619
+ )
6938
7620
  elif AC.BADAFamily.BADAE:
6939
7621
  P_i = AC.Pav(rating=rating, SOC=SOC[-1])
6940
7622
  Pav_i = AC.Pav(rating=rating, SOC=SOC[-1])
@@ -6957,7 +7639,9 @@ def accDec(
6957
7639
  Pelc_i = P_i / AC.eta
6958
7640
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
6959
7641
  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
7642
+ Vgbat_i = (
7643
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
7644
+ )
6961
7645
 
6962
7646
  # BADA4
6963
7647
  elif AC.BADAFamily.BADA4:
@@ -6976,15 +7660,21 @@ def accDec(
6976
7660
  # ensure continuity of configuration change within the segment
6977
7661
  if config:
6978
7662
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
6979
- phase=phase, previousConfig=config[-1], currentConfig=config_i
7663
+ phase=phase,
7664
+ previousConfig=config[-1],
7665
+ currentConfig=config_i,
6980
7666
  )
6981
7667
 
6982
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
7668
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
7669
+ config=config_i
7670
+ )
6983
7671
 
6984
7672
  # compute lift coefficient
6985
7673
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
6986
7674
  # compute drag coefficient
6987
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
7675
+ CD = AC.CD(
7676
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
7677
+ )
6988
7678
  # compute drag force
6989
7679
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
6990
7680
 
@@ -7044,7 +7734,11 @@ def accDec(
7044
7734
  else:
7045
7735
  CT = AC.CT(Thrust=THR_i, delta=delta)
7046
7736
  FUEL_i = AC.ff(
7047
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
7737
+ CT=CT,
7738
+ delta=delta,
7739
+ theta=theta,
7740
+ M=M_i,
7741
+ DeltaTemp=DeltaTemp,
7048
7742
  )
7049
7743
  else:
7050
7744
  THR_i = AC.Thrust(
@@ -7056,7 +7750,11 @@ def accDec(
7056
7750
  ) # [N]
7057
7751
  CT = AC.CT(Thrust=THR_i, delta=delta)
7058
7752
  FUEL_i = AC.ff(
7059
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
7753
+ CT=CT,
7754
+ delta=delta,
7755
+ theta=theta,
7756
+ M=M_i,
7757
+ DeltaTemp=DeltaTemp,
7060
7758
  )
7061
7759
 
7062
7760
  # compute excess power
@@ -7111,7 +7809,11 @@ def accDec(
7111
7809
  # recompute ROCD if necessary and compute fuel flow accordingly
7112
7810
 
7113
7811
  THR_min = AC.Thrust(
7114
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
7812
+ rating="LIDL",
7813
+ v=TAS_i,
7814
+ h=H_m,
7815
+ config="CR",
7816
+ DeltaTemp=DeltaTemp,
7115
7817
  ) # IDLE Thrust
7116
7818
  FUEL_min = AC.ff(
7117
7819
  flightPhase="Descent",
@@ -7122,7 +7824,11 @@ def accDec(
7122
7824
  adapted=False,
7123
7825
  ) # IDLE Fuel Flow
7124
7826
  THR_max = AC.Thrust(
7125
- rating="MCMB", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
7827
+ rating="MCMB",
7828
+ v=TAS_i,
7829
+ h=H_m,
7830
+ config="CR",
7831
+ DeltaTemp=DeltaTemp,
7126
7832
  ) # MCMB Thrust
7127
7833
  FUEL_max = AC.ff(
7128
7834
  flightPhase="Climb",
@@ -7141,7 +7847,11 @@ def accDec(
7141
7847
  FUEL_i = FUEL_max
7142
7848
  else:
7143
7849
  FUEL_i = AC.ff(
7144
- v=TAS_i, h=H_m, T=THR_i, config=config_i, adapted=True
7850
+ v=TAS_i,
7851
+ h=H_m,
7852
+ T=THR_i,
7853
+ config=config_i,
7854
+ adapted=True,
7145
7855
  )
7146
7856
  else:
7147
7857
  THR_i = AC.Thrust(
@@ -7206,7 +7916,10 @@ def accDec(
7206
7916
  dhdtisu = PC_i / (mass_i * const.g) # [m/s]
7207
7917
  ROCDisu = dhdtisu * 1 / temp_const # [m/s]
7208
7918
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
7209
- elif control.slopetarget is not None or control.ROCDtarget is not None:
7919
+ elif (
7920
+ control.slopetarget is not None
7921
+ or control.ROCDtarget is not None
7922
+ ):
7210
7923
  dhdtisu = dh_dt_i # [m/s]
7211
7924
  ROCDisu = dh_dt_i * 1 / temp_const # [m/s]
7212
7925
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
@@ -7309,7 +8022,10 @@ def accDec(
7309
8022
  # BADAH or BADAE
7310
8023
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
7311
8024
  check.append(
7312
- P_i - Preq_i - mass_i * const.g * dhdtisu - mass_i * TAS_i * dVdtisu_i
8025
+ P_i
8026
+ - Preq_i
8027
+ - mass_i * const.g * dhdtisu
8028
+ - mass_i * TAS_i * dVdtisu_i
7313
8029
  )
7314
8030
 
7315
8031
  # BADA3 or BADA4
@@ -7327,12 +8043,18 @@ def accDec(
7327
8043
  [theta, delta, sigma] = atm.atmosphereProperties(
7328
8044
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
7329
8045
  )
7330
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
8046
+ temp_const = (theta * const.temp_0) / (
8047
+ theta * const.temp_0 - DeltaTemp
8048
+ )
7331
8049
  if AC.BADAFamily.BADAE:
7332
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
8050
+ gamma_i = degrees(
8051
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
8052
+ )
7333
8053
  else:
7334
8054
  # 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))
8055
+ gamma_i = degrees(
8056
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
8057
+ )
7336
8058
 
7337
8059
  # ground speed can be calcualted as TAS projected on the ground minus wind
7338
8060
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -7427,14 +8149,16 @@ def accDec(
7427
8149
 
7428
8150
  else:
7429
8151
  # 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,
8152
+ (Lat_i, Lon_i, HDGTrue_i) = (
8153
+ turn.destinationPoint_finalBearing(
8154
+ LAT_init=LAT[-1],
8155
+ LON_init=LON[-1],
8156
+ bearingInit=HDGTrue[-1],
8157
+ TAS=TAS_i,
8158
+ rateOfTurn=rateOfTurn,
8159
+ timeOfTurn=step_time,
8160
+ directionOfTurn=directionOfTurn,
8161
+ )
7438
8162
  )
7439
8163
 
7440
8164
  if magneticDeclinationGrid is not None:
@@ -7472,14 +8196,16 @@ def accDec(
7472
8196
 
7473
8197
  else:
7474
8198
  # 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,
8199
+ (Lat_i, Lon_i, HDGTrue_i) = (
8200
+ turn.destinationPoint_finalBearing(
8201
+ LAT_init=LAT[-1],
8202
+ LON_init=LON[-1],
8203
+ bearingInit=HDGTrue[-1],
8204
+ TAS=TAS_i,
8205
+ rateOfTurn=rateOfTurn,
8206
+ timeOfTurn=step_time,
8207
+ directionOfTurn=directionOfTurn,
8208
+ )
7483
8209
  )
7484
8210
 
7485
8211
  if magneticDeclinationGrid is not None:
@@ -7580,79 +8306,103 @@ def accDec_time(
7580
8306
  magneticDeclinationGrid=None,
7581
8307
  **kwargs,
7582
8308
  ):
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
8309
+ """
8310
+ Calculates the time, fuel consumption, and other key flight parameters required for an aircraft
8311
+ to perform an acceleration or deceleration from an initial speed (v_init) over a set period of time
8312
+ during the climb, cruise, or descent phases of flight.
8313
+
8314
+ The flight parameters are calculated using different models for the BADA (Base of Aircraft Data) families (BADA3, BADA4, BADAH, BADAE).
8315
+ The function can also accommodate different control laws, vertical evolution phases, wind conditions, and complex flight dynamics like turns.
7584
8316
 
7585
8317
  .. 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]}.
8318
+ The control law used during the segment depends on the targets provided in the input parameter 'control':
8319
+
8320
+ - ROCD/slope+ESF: Law based on ROCD/slope + ESF
8321
+ - ROCD/slope+acc: Law based on ROCD/slope + acceleration
8322
+ - ROCD/slope only: Law based on rating + ROCD/slope
8323
+ - ESF only: Law based on rating + ESF
8324
+ - acc only: Law based on rating + acceleration
8325
+ - Neither: Law is rating + default ESF
8326
+
8327
+ :param AC: Aircraft object {BADA3/4/H/E}.
8328
+ :param length: Total duration of the flight segment [s].
8329
+ :param speedType: Type of speed being followed {M, CAS, TAS}.
8330
+ :param v_init: Initial speed [kt] (CAS/TAS) or [-] MACH.
8331
+ :param speedEvol: Evolution of speed {acc, dec} (acceleration or deceleration).
8332
+ :param phase: Vertical evolution phase {Climb, Descent, Cruise}.
8333
+ :param control: A dictionary containing the following targets:
8334
+
8335
+ - ROCDtarget: Rate of climb/descent to be followed [ft/min].
8336
+ - slopetarget: Slope (flight path angle) to be followed [deg].
8337
+ - acctarget: Acceleration to be followed [m/s^2].
8338
+ - ESFtarget: Energy Share Factor to be followed [-].
8339
+ :param Hp_init: Initial pressure altitude [ft].
8340
+ :param m_init: Initial aircraft mass [kg].
8341
+ :param DeltaTemp: Deviation from the standard ISA temperature [K].
8342
+ :param wS: Wind speed component along the longitudinal axis (affects ground speed) [kt]. Default is 0.0.
8343
+ :param turnMetrics: A dictionary defining turn parameters:
8344
+
8345
+ - rateOfTurn [deg/s]
8346
+ - bankAngle [deg]
8347
+ - directionOfTurn {LEFT/RIGHT}. Default is straight flight.
8348
+ :param Lat: Initial latitude [deg]. Default is None.
8349
+ :param Lon: Initial longitude [deg]. Default is None.
8350
+ :param initialHeading: A dictionary defining the initial heading (magnetic or true) and whether to fly a constant heading:
8351
+
8352
+ - magnetic: Magnetic heading [deg].
8353
+ - true: True heading [deg].
8354
+ - constantHeading: Whether to maintain a constant heading. Default is None.
8355
+ :param reducedPower: Boolean specifying if reduced power is applied during the climb. Default is None.
8356
+ :param magneticDeclinationGrid: Optional grid of magnetic declination used to correct magnetic heading. Default is None.
8357
+ :param kwargs: Additional optional parameters:
8358
+
8359
+ - step_length: Length of each time step in the calculation [s]. Default is 1 second.
8360
+ - SOC_init: Initial battery state of charge for electric aircraft (BADAE) [%]. Default is 100.
8361
+ - config: Default aerodynamic configuration (TO, IC, CR, AP, LD). Default is None.
8362
+ - mass_const: Boolean indicating whether mass remains constant during the flight segment. Default is False.
8363
+ - m_iter: Number of iterations for the mass integration loop. Default is 10 for BADA3/4/H, 5 for BADAE.
8364
+
8365
+ :returns: A pandas DataFrame containing the flight trajectory with columns such as:
8366
+
8367
+ - **Hp** - wAltitude [ft]
8368
+ - **TAS** - True Air Speed [kt]
8369
+ - **CAS** - Calibrated Air Speed [kt]
8370
+ - **GS** - Ground Speed [kt]
8371
+ - **M** - Mach number [-]
8372
+ - **ROCD** - Rate of Climb/Descent [ft/min]
8373
+ - **ESF** - Energy Share Factor [-]
8374
+ - **FUEL** - Fuel flow [kg/s]
8375
+ - **FUELCONSUMED** - Total fuel consumed [kg]
8376
+ - **THR** - Thrust force [N]
8377
+ - **DRAG** - Drag force [N]
8378
+ - **time** - Elapsed time [s]
8379
+ - **dist** - Distance flown [NM]
8380
+ - **slope** - Trajectory slope [deg]
8381
+ - **mass** - Aircraft mass [kg]
8382
+ - **config** - Aerodynamic configuration
8383
+ - **LAT** - Latitude [deg]
8384
+ - **LON** - Longitude [deg]
8385
+ - **HDGTrue** - True heading [deg]
8386
+ - **HDGMagnetic** - Magnetic heading [deg]
8387
+ - **BankAngle** - Bank angle [deg]
8388
+ - **ROT** - Rate of turn [deg/s]
8389
+ - **Comment** - Comments for each segment
8390
+
8391
+ - **For BADAH:**
8392
+ - **Preq** - Required power [W]
8393
+ - **Peng** - Generated power [W]
8394
+ - **Pav** - Available power [W]
8395
+
8396
+ - **For BADAE (electric aircraft):**
8397
+ - **Pmec** - Mechanical power [W]
8398
+ - **Pelc** - Electrical power [W]
8399
+ - **Pbat** - Power supplied by the battery [W]
8400
+ - **SOCr** - Rate of battery state of charge depletion [%/h]
8401
+ - **SOC** - Battery state of charge [%]
8402
+ - **Ibat** - Battery current [A]
8403
+ - **Vbat** - Battery voltage [V]
8404
+ - **Vgbat** - Ground battery voltage [V]
8405
+ :rtype: pandas.DataFrame
7656
8406
  """
7657
8407
 
7658
8408
  rateOfTurn = turnMetrics["rateOfTurn"]
@@ -7703,7 +8453,9 @@ def accDec_time(
7703
8453
 
7704
8454
  # speed brakes application
7705
8455
  if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4:
7706
- speedBrakes = kwargs.get("speedBrakes", {"deployed": False, "value": 0.03})
8456
+ speedBrakes = kwargs.get(
8457
+ "speedBrakes", {"deployed": False, "value": 0.03}
8458
+ )
7707
8459
 
7708
8460
  # step size in [s]
7709
8461
  step_length = kwargs.get("step_length", 1)
@@ -7711,7 +8463,9 @@ def accDec_time(
7711
8463
  # number of iteration of mass/altitude loop
7712
8464
  # BADAE
7713
8465
  if AC.BADAFamily.BADAE:
7714
- m_iter = kwargs.get("m_iter", 5) # number of iterations for integration loop[-]
8466
+ m_iter = kwargs.get(
8467
+ "m_iter", 5
8468
+ ) # number of iterations for integration loop[-]
7715
8469
  # BADA3 or BADA4 or BADAH
7716
8470
  else:
7717
8471
  m_iter = kwargs.get(
@@ -7861,9 +8615,9 @@ def accDec_time(
7861
8615
  maxRating = checkArgument("maxRating", **kwargs)
7862
8616
 
7863
8617
  # 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
- ):
8618
+ if (
8619
+ control.ROCDtarget is not None or control.slopetarget is not None
8620
+ ) and (control.ESFtarget is not None or control.acctarget is not None):
7867
8621
  rating = None
7868
8622
  else:
7869
8623
  if phase == "Climb" or (phase == "Cruise" and speedEvol == "acc"):
@@ -7981,8 +8735,12 @@ def accDec_time(
7981
8735
  for _ in itertools.repeat(None, m_iter):
7982
8736
  # atmosphere properties
7983
8737
  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)
8738
+ [theta, delta, sigma] = atm.atmosphereProperties(
8739
+ h=H_m, DeltaTemp=DeltaTemp
8740
+ )
8741
+ temp_const = (theta * const.temp_0) / (
8742
+ theta * const.temp_0 - DeltaTemp
8743
+ )
7986
8744
 
7987
8745
  step_time = length_loop - time[-1]
7988
8746
 
@@ -7994,7 +8752,9 @@ def accDec_time(
7994
8752
  if turnFlight:
7995
8753
  if turnMetrics["bankAngle"] != 0.0:
7996
8754
  # bankAngle is defined
7997
- rateOfTurn = AC.rateOfTurn_bankAngle(TAS=TAS_i, bankAngle=bankAngle)
8755
+ rateOfTurn = AC.rateOfTurn_bankAngle(
8756
+ TAS=TAS_i, bankAngle=bankAngle
8757
+ )
7998
8758
  else:
7999
8759
  # rateOfTurn is defined
8000
8760
  bankAngle = AC.bankAngle(
@@ -8021,7 +8781,9 @@ def accDec_time(
8021
8781
  # BADAH or BADAE
8022
8782
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
8023
8783
  # compute Power required
8024
- Preq_i = AC.Preq(sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle)
8784
+ Preq_i = AC.Preq(
8785
+ sigma=sigma, tas=TAS_i, mass=mass_i, phi=bankAngle
8786
+ )
8025
8787
 
8026
8788
  # compute engine power
8027
8789
  if rating is None:
@@ -8039,11 +8801,17 @@ def accDec_time(
8039
8801
 
8040
8802
  # Check that required thrust/power fits in the available thrust/power envelope,
8041
8803
  # recompute ROCD if necessary and compute fuel coefficient accordingly
8042
- Pmin = 0.1 * AC.P0 # No minimum power model: assume 10% torque
8804
+ Pmin = (
8805
+ 0.1 * AC.P0
8806
+ ) # No minimum power model: assume 10% torque
8043
8807
 
8044
8808
  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)
8809
+ Pmax = AC.Pav(
8810
+ rating=maxRating, theta=theta, delta=delta
8811
+ )
8812
+ Pav_i = AC.Pav(
8813
+ rating=maxRating, theta=theta, delta=delta
8814
+ )
8047
8815
  elif AC.BADAFamily.BADAE:
8048
8816
  Pmax = AC.Pav(rating=maxRating, SOC=SOC[-1])
8049
8817
  Pav_i = AC.Pav(rating=maxRating, SOC=SOC[-1])
@@ -8068,7 +8836,11 @@ def accDec_time(
8068
8836
  elif control.acctarget is not None:
8069
8837
  ROCD_i = (
8070
8838
  conv.m2ft(
8071
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
8839
+ (
8840
+ P_i
8841
+ - mass_i * TAS_i * control.acctarget
8842
+ - Preq_i
8843
+ )
8072
8844
  / (mass_i * const.g * temp_const)
8073
8845
  )
8074
8846
  * 60
@@ -8093,7 +8865,11 @@ def accDec_time(
8093
8865
  elif control.acctarget is not None:
8094
8866
  ROCD_i = (
8095
8867
  conv.m2ft(
8096
- (P_i - mass_i * TAS_i * control.acctarget - Preq_i)
8868
+ (
8869
+ P_i
8870
+ - mass_i * TAS_i * control.acctarget
8871
+ - Preq_i
8872
+ )
8097
8873
  / (mass_i * const.g * temp_const)
8098
8874
  )
8099
8875
  * 60
@@ -8104,12 +8880,20 @@ def accDec_time(
8104
8880
  else:
8105
8881
  # Compute available power
8106
8882
  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)
8883
+ P_i = (
8884
+ 0.1 * AC.P0
8885
+ ) # No minimum power model: assume 10% torque
8886
+ Pav_i = AC.Pav(
8887
+ rating=maxRating, theta=theta, delta=delta
8888
+ )
8109
8889
  else:
8110
8890
  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)
8891
+ P_i = AC.Pav(
8892
+ rating=rating, theta=theta, delta=delta
8893
+ )
8894
+ Pav_i = AC.Pav(
8895
+ rating=rating, theta=theta, delta=delta
8896
+ )
8113
8897
  elif AC.BADAFamily.BADAE:
8114
8898
  P_i = AC.Pav(rating=rating, SOC=SOC[-1])
8115
8899
  Pav_i = AC.Pav(rating=rating, SOC=SOC[-1])
@@ -8132,7 +8916,9 @@ def accDec_time(
8132
8916
  Pelc_i = P_i / AC.eta
8133
8917
  Ibat_i = AC.Ibat(P=Pelc_i, SOC=SOC[-1])
8134
8918
  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
8919
+ Vgbat_i = (
8920
+ AC.Vocbat(SOC=SOC[-1]) - AC.R0bat(SOC=SOC[-1]) * Ibat_i
8921
+ )
8136
8922
 
8137
8923
  # BADA4
8138
8924
  elif AC.BADAFamily.BADA4:
@@ -8151,15 +8937,21 @@ def accDec_time(
8151
8937
  # ensure continuity of configuration change within the segment
8152
8938
  if config:
8153
8939
  config_i = AC.flightEnvelope.checkConfigurationContinuity(
8154
- phase=phase, previousConfig=config[-1], currentConfig=config_i
8940
+ phase=phase,
8941
+ previousConfig=config[-1],
8942
+ currentConfig=config_i,
8155
8943
  )
8156
8944
 
8157
- [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(config=config_i)
8945
+ [HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
8946
+ config=config_i
8947
+ )
8158
8948
 
8159
8949
  # compute lift coefficient
8160
8950
  CL = AC.CL(M=M_i, delta=delta, mass=mass_i, nz=nz)
8161
8951
  # compute drag coefficient
8162
- CD = AC.CD(M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes)
8952
+ CD = AC.CD(
8953
+ M=M_i, CL=CL, HLid=HLid_i, LG=LG_i, speedBrakes=speedBrakes
8954
+ )
8163
8955
  # compute drag force
8164
8956
  Drag = AC.D(M=M_i, delta=delta, CD=CD)
8165
8957
 
@@ -8219,7 +9011,11 @@ def accDec_time(
8219
9011
  else:
8220
9012
  CT = AC.CT(Thrust=THR_i, delta=delta)
8221
9013
  FUEL_i = AC.ff(
8222
- CT=CT, delta=delta, theta=theta, M=M_i, DeltaTemp=DeltaTemp
9014
+ CT=CT,
9015
+ delta=delta,
9016
+ theta=theta,
9017
+ M=M_i,
9018
+ DeltaTemp=DeltaTemp,
8223
9019
  )
8224
9020
  else:
8225
9021
  THR_i = AC.Thrust(
@@ -8293,7 +9089,11 @@ def accDec_time(
8293
9089
  # recompute ROCD if necessary and compute fuel flow accordingly
8294
9090
 
8295
9091
  THR_min = AC.Thrust(
8296
- rating="LIDL", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
9092
+ rating="LIDL",
9093
+ v=TAS_i,
9094
+ h=H_m,
9095
+ config="CR",
9096
+ DeltaTemp=DeltaTemp,
8297
9097
  ) # IDLE Thrust
8298
9098
  FUEL_min = AC.ff(
8299
9099
  flightPhase="Descent",
@@ -8304,7 +9104,11 @@ def accDec_time(
8304
9104
  adapted=False,
8305
9105
  ) # IDLE Fuel Flow
8306
9106
  THR_max = AC.Thrust(
8307
- rating="MCMB", v=TAS_i, h=H_m, config="CR", DeltaTemp=DeltaTemp
9107
+ rating="MCMB",
9108
+ v=TAS_i,
9109
+ h=H_m,
9110
+ config="CR",
9111
+ DeltaTemp=DeltaTemp,
8308
9112
  ) # MCMB Thrust
8309
9113
  FUEL_max = AC.ff(
8310
9114
  flightPhase="Climb",
@@ -8323,7 +9127,11 @@ def accDec_time(
8323
9127
  FUEL_i = FUEL_max
8324
9128
  else:
8325
9129
  FUEL_i = AC.ff(
8326
- v=TAS_i, h=H_m, T=THR_i, config=config_i, adapted=True
9130
+ v=TAS_i,
9131
+ h=H_m,
9132
+ T=THR_i,
9133
+ config=config_i,
9134
+ adapted=True,
8327
9135
  )
8328
9136
  else:
8329
9137
  THR_i = AC.Thrust(
@@ -8386,7 +9194,10 @@ def accDec_time(
8386
9194
  dhdtisu = PC_i / (mass_i * const.g) # [m/s]
8387
9195
  ROCDisu = dhdtisu * 1 / temp_const # [m/s]
8388
9196
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
8389
- elif control.slopetarget is not None or control.ROCDtarget is not None:
9197
+ elif (
9198
+ control.slopetarget is not None
9199
+ or control.ROCDtarget is not None
9200
+ ):
8390
9201
  dhdtisu = dh_dt_i # [m/s]
8391
9202
  ROCDisu = dh_dt_i * 1 / temp_const # [m/s]
8392
9203
  ROCD_i = conv.m2ft(ROCDisu) * 60 # [ft/min]
@@ -8487,7 +9298,10 @@ def accDec_time(
8487
9298
  # BADAH or BADAE
8488
9299
  if AC.BADAFamily.BADAH or AC.BADAFamily.BADAE:
8489
9300
  check.append(
8490
- P_i - Preq_i - mass_i * const.g * dhdtisu - mass_i * TAS_i * dVdtisu_i
9301
+ P_i
9302
+ - Preq_i
9303
+ - mass_i * const.g * dhdtisu
9304
+ - mass_i * TAS_i * dVdtisu_i
8491
9305
  )
8492
9306
 
8493
9307
  # BADA3 or BADA4
@@ -8505,12 +9319,18 @@ def accDec_time(
8505
9319
  [theta, delta, sigma] = atm.atmosphereProperties(
8506
9320
  h=conv.ft2m(Hp_i), DeltaTemp=DeltaTemp
8507
9321
  )
8508
- temp_const = (theta * const.temp_0) / (theta * const.temp_0 - DeltaTemp)
9322
+ temp_const = (theta * const.temp_0) / (
9323
+ theta * const.temp_0 - DeltaTemp
9324
+ )
8509
9325
  if AC.BADAFamily.BADAE:
8510
- gamma_i = degrees(atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i))
9326
+ gamma_i = degrees(
9327
+ atan(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
9328
+ )
8511
9329
  else:
8512
9330
  # 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))
9331
+ gamma_i = degrees(
9332
+ asin(conv.ft2m(ROCD_i) * temp_const / 60 / TAS_i)
9333
+ )
8514
9334
 
8515
9335
  # ground speed can be calcualted as TAS projected on the ground minus wind
8516
9336
  GS_i = cos(radians(gamma_i)) * TAS_i - wS
@@ -8521,7 +9341,9 @@ def accDec_time(
8521
9341
  ROT.append(rateOfTurn)
8522
9342
 
8523
9343
  # integrated data
8524
- if length_loop != 0: # exclude first point: initial t/d/m already known
9344
+ if (
9345
+ length_loop != 0
9346
+ ): # exclude first point: initial t/d/m already known
8525
9347
  if AC.BADAFamily.BADAE:
8526
9348
  SOC.append(SOC_i)
8527
9349
 
@@ -8609,14 +9431,16 @@ def accDec_time(
8609
9431
 
8610
9432
  else:
8611
9433
  # 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,
9434
+ (Lat_i, Lon_i, HDGTrue_i) = (
9435
+ turn.destinationPoint_finalBearing(
9436
+ LAT_init=LAT[-1],
9437
+ LON_init=LON[-1],
9438
+ bearingInit=HDGTrue[-1],
9439
+ TAS=TAS_i,
9440
+ rateOfTurn=rateOfTurn,
9441
+ timeOfTurn=step_time,
9442
+ directionOfTurn=directionOfTurn,
9443
+ )
8620
9444
  )
8621
9445
 
8622
9446
  if magneticDeclinationGrid is not None:
@@ -8654,14 +9478,16 @@ def accDec_time(
8654
9478
 
8655
9479
  else:
8656
9480
  # 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,
9481
+ (Lat_i, Lon_i, HDGTrue_i) = (
9482
+ turn.destinationPoint_finalBearing(
9483
+ LAT_init=LAT[-1],
9484
+ LON_init=LON[-1],
9485
+ bearingInit=HDGTrue[-1],
9486
+ TAS=TAS_i,
9487
+ rateOfTurn=rateOfTurn,
9488
+ timeOfTurn=step_time,
9489
+ directionOfTurn=directionOfTurn,
9490
+ )
8665
9491
  )
8666
9492
 
8667
9493
  if magneticDeclinationGrid is not None: