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.
- pyBADA/TCL.py +1623 -797
- pyBADA/aircraft/BADA4/DUMMY/ACM_BADA4.xsd +3 -1
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.ATF +33 -33
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.xml +3 -1
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTD +30 -30
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTF +14 -14
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTD +30 -30
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTF +14 -14
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.ATF +143 -143
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.xml +83 -81
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTD +153 -153
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTF +21 -21
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTD +153 -153
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTF +21 -21
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.OPT +36 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.OPT +56 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.OPT +36 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/{OPTALT.dat → OPTALT.OPT} +5 -5
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.ATF +158 -158
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.xml +123 -121
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTD +216 -216
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTF +28 -28
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTD +216 -216
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTF +28 -28
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/ECON.OPT +25 -25
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/LRC.OPT +22 -24
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MEC.OPT +42 -44
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MRC.OPT +22 -24
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/OPTALT.OPT +20 -20
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.ATF +181 -181
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.xml +190 -188
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTD +216 -216
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTF +25 -25
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTD +204 -204
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTF +25 -25
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/ECON.OPT +25 -25
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/LRC.OPT +22 -22
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MEC.OPT +42 -42
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MRC.OPT +22 -22
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/OPTALT.OPT +20 -20
- pyBADA/aircraft.py +201 -216
- pyBADA/atmosphere.py +117 -87
- pyBADA/bada3.py +1412 -843
- pyBADA/bada4.py +1678 -988
- pyBADA/badaH.py +1129 -619
- pyBADA/configuration.py +142 -24
- pyBADA/constants.py +0 -9
- pyBADA/conversions.py +0 -10
- pyBADA/flightTrajectory.py +154 -151
- pyBADA/geodesic.py +278 -179
- pyBADA/magnetic.py +54 -16
- pyBADA/trajectoryPrediction.py +27 -26
- {pybada-0.1.0.dist-info → pybada-0.1.2.dist-info}/METADATA +22 -9
- pybada-0.1.2.dist-info/RECORD +97 -0
- {pybada-0.1.0.dist-info → pybada-0.1.2.dist-info}/WHEEL +1 -1
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.dat +0 -38
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.dat +0 -58
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.dat +0 -38
- pyBADA/aircraft/BADA4/DUMMY/aircraft_model_default.xml +0 -311
- pyBADA/badaE.py +0 -3317
- pybada-0.1.0.dist-info/RECORD +0 -99
- {pybada-0.1.0.dist-info → pybada-0.1.2.dist-info}/licenses/AUTHORS +0 -0
- {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
|
-
"""
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
:param
|
|
82
|
-
:param
|
|
83
|
-
:param
|
|
84
|
-
:param
|
|
85
|
-
:param
|
|
86
|
-
:param
|
|
87
|
-
:param
|
|
88
|
-
:param
|
|
89
|
-
:param
|
|
90
|
-
:param
|
|
91
|
-
:param
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
:param
|
|
97
|
-
:param
|
|
98
|
-
:param
|
|
99
|
-
:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
:
|
|
105
|
-
:
|
|
106
|
-
:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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(
|
|
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(
|
|
219
|
+
m_iter = kwargs.get(
|
|
220
|
+
"m_iter", 1
|
|
221
|
+
) # number of iterations for integration loop[-]
|
|
195
222
|
else:
|
|
196
|
-
m_iter = kwargs.get(
|
|
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(
|
|
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(
|
|
361
|
+
rateOfTurn = AC.rateOfTurn_bankAngle(
|
|
362
|
+
TAS=TAS_i, bankAngle=bankAngle
|
|
363
|
+
)
|
|
331
364
|
else:
|
|
332
365
|
# rateOfTurn is defined
|
|
333
|
-
bankAngle = AC.bankAngle(
|
|
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(
|
|
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",
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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(
|
|
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
|
-
"""
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
:param
|
|
1134
|
-
:param
|
|
1135
|
-
:param
|
|
1136
|
-
:param
|
|
1137
|
-
:param
|
|
1138
|
-
:param
|
|
1139
|
-
:param
|
|
1140
|
-
:param
|
|
1141
|
-
:param
|
|
1142
|
-
:param
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
:param
|
|
1148
|
-
:
|
|
1149
|
-
:
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
:
|
|
1155
|
-
:
|
|
1156
|
-
:
|
|
1157
|
-
:
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
:
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
1365
|
-
|
|
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,
|
|
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(
|
|
1497
|
+
rateOfTurn = AC.rateOfTurn_bankAngle(
|
|
1498
|
+
TAS=TAS_i, bankAngle=bankAngle
|
|
1499
|
+
)
|
|
1381
1500
|
else:
|
|
1382
1501
|
# rateOfTurn is defined
|
|
1383
|
-
bankAngle = AC.bankAngle(
|
|
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(
|
|
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,
|
|
1548
|
+
phase=phase,
|
|
1549
|
+
previousConfig=config[-1],
|
|
1550
|
+
currentConfig=config_i,
|
|
1426
1551
|
)
|
|
1427
1552
|
|
|
1428
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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)
|
|
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)
|
|
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 =
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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,
|
|
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",
|
|
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",
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
:param
|
|
2048
|
-
:param
|
|
2049
|
-
:param
|
|
2050
|
-
:param
|
|
2051
|
-
:param
|
|
2052
|
-
:param
|
|
2053
|
-
:param
|
|
2054
|
-
:param
|
|
2055
|
-
:param
|
|
2056
|
-
:param
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
:param
|
|
2062
|
-
:
|
|
2063
|
-
:
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
:
|
|
2069
|
-
:
|
|
2070
|
-
:
|
|
2071
|
-
:
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
:
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
2273
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
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,
|
|
2547
|
+
phase=phase,
|
|
2548
|
+
previousConfig=config[-1],
|
|
2549
|
+
currentConfig=config_i,
|
|
2332
2550
|
)
|
|
2333
2551
|
|
|
2334
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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)
|
|
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)
|
|
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 =
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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,
|
|
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",
|
|
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",
|
|
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) / (
|
|
2945
|
+
temp_const = (theta * const.temp_0) / (
|
|
2946
|
+
theta * const.temp_0 - DeltaTemp
|
|
2947
|
+
)
|
|
2692
2948
|
if AC.BADAFamily.BADAE:
|
|
2693
|
-
gamma_i = degrees(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
:param
|
|
2944
|
-
:param
|
|
2945
|
-
:param
|
|
2946
|
-
:param
|
|
2947
|
-
:param
|
|
2948
|
-
:param
|
|
2949
|
-
:param
|
|
2950
|
-
:param
|
|
2951
|
-
:param
|
|
2952
|
-
:param
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
:param
|
|
2958
|
-
:param
|
|
2959
|
-
:
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
:
|
|
2965
|
-
:
|
|
2966
|
-
:
|
|
2967
|
-
:
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
:
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
3170
|
-
|
|
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(
|
|
3483
|
+
rateOfTurn = AC.rateOfTurn_bankAngle(
|
|
3484
|
+
TAS=TAS_i, bankAngle=bankAngle
|
|
3485
|
+
)
|
|
3181
3486
|
else:
|
|
3182
3487
|
# rateOfTurn is defined
|
|
3183
|
-
bankAngle = AC.bankAngle(
|
|
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,
|
|
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(
|
|
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,
|
|
3548
|
+
phase=phase,
|
|
3549
|
+
previousConfig=config[-1],
|
|
3550
|
+
currentConfig=config_i,
|
|
3237
3551
|
)
|
|
3238
3552
|
|
|
3239
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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)
|
|
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)
|
|
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 =
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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,
|
|
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",
|
|
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",
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
:param
|
|
3853
|
-
:param
|
|
3854
|
-
:param
|
|
3855
|
-
:param
|
|
3856
|
-
:param
|
|
3857
|
-
:param
|
|
3858
|
-
:param
|
|
3859
|
-
:param
|
|
3860
|
-
:param
|
|
3861
|
-
:param
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
:param
|
|
3867
|
-
:param
|
|
3868
|
-
:param
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
:
|
|
3874
|
-
:
|
|
3875
|
-
:
|
|
3876
|
-
:
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
:
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
4079
|
-
|
|
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(
|
|
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,
|
|
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 =
|
|
4508
|
+
ROCDisu = (
|
|
4509
|
+
tan(conv.deg2rad(slopetarget)) * TAS_i * (1 / temp_const)
|
|
4510
|
+
)
|
|
4110
4511
|
else:
|
|
4111
|
-
ROCDisu =
|
|
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(
|
|
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,
|
|
4549
|
+
phase=phase,
|
|
4550
|
+
previousConfig=config[-1],
|
|
4551
|
+
currentConfig=config_i,
|
|
4145
4552
|
)
|
|
4146
4553
|
|
|
4147
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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)
|
|
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)
|
|
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 =
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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,
|
|
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",
|
|
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",
|
|
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) / (
|
|
4948
|
+
temp_const = (theta * const.temp_0) / (
|
|
4949
|
+
theta * const.temp_0 - DeltaTemp
|
|
4950
|
+
)
|
|
4506
4951
|
if AC.BADAFamily.BADAE:
|
|
4507
|
-
gamma_i = degrees(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
:param
|
|
4759
|
-
:param
|
|
4760
|
-
:param
|
|
4761
|
-
:param
|
|
4762
|
-
:param
|
|
4763
|
-
:param
|
|
4764
|
-
:param
|
|
4765
|
-
:param
|
|
4766
|
-
:param
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
:param
|
|
4772
|
-
:param
|
|
4773
|
-
:param
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
:
|
|
4779
|
-
:
|
|
4780
|
-
:
|
|
4781
|
-
:
|
|
4782
|
-
:
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
:
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
5008
|
-
|
|
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(
|
|
5514
|
+
rateOfTurn = AC.rateOfTurn_bankAngle(
|
|
5515
|
+
TAS=TAS_i, bankAngle=bankAngle
|
|
5516
|
+
)
|
|
5019
5517
|
else:
|
|
5020
5518
|
# rateOfTurn is defined
|
|
5021
|
-
bankAngle = AC.bankAngle(
|
|
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,
|
|
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 =
|
|
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 =
|
|
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,
|
|
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(
|
|
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,
|
|
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,
|
|
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(
|
|
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,
|
|
5679
|
+
phase=phase,
|
|
5680
|
+
previousConfig=config[-1],
|
|
5681
|
+
currentConfig=config_i,
|
|
5159
5682
|
)
|
|
5160
5683
|
|
|
5161
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
:param
|
|
5595
|
-
:param
|
|
5596
|
-
:param
|
|
5597
|
-
:param
|
|
5598
|
-
:param
|
|
5599
|
-
:param
|
|
5600
|
-
:param
|
|
5601
|
-
:param
|
|
5602
|
-
:param
|
|
5603
|
-
:param
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
:param
|
|
5609
|
-
:param
|
|
5610
|
-
:param
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
:
|
|
5616
|
-
:
|
|
5617
|
-
:
|
|
5618
|
-
:
|
|
5619
|
-
:
|
|
5620
|
-
:
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
:
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
5847
|
-
|
|
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(
|
|
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,
|
|
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(
|
|
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 =
|
|
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,
|
|
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,
|
|
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(
|
|
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,
|
|
6593
|
+
phase=phase,
|
|
6594
|
+
previousConfig=config[-1],
|
|
6595
|
+
currentConfig=config_i,
|
|
5992
6596
|
)
|
|
5993
6597
|
|
|
5994
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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,
|
|
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) / (
|
|
6781
|
+
temp_const = (theta * const.temp_0) / (
|
|
6782
|
+
theta * const.temp_0 - DeltaTemp
|
|
6783
|
+
)
|
|
6171
6784
|
if AC.BADAFamily.BADAE:
|
|
6172
|
-
gamma_i = degrees(
|
|
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(
|
|
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,
|
|
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
|
-
"""
|
|
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
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
:param
|
|
6427
|
-
:param
|
|
6428
|
-
:param
|
|
6429
|
-
:param
|
|
6430
|
-
:param
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
:param
|
|
6438
|
-
:param
|
|
6439
|
-
:param
|
|
6440
|
-
:param
|
|
6441
|
-
:param
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
:param
|
|
6447
|
-
:param
|
|
6448
|
-
:param
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
:
|
|
6454
|
-
:
|
|
6455
|
-
:
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
:
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
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(
|
|
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(
|
|
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 (
|
|
6704
|
-
control.
|
|
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(
|
|
6810
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
6870
|
-
|
|
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
|
-
(
|
|
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
|
-
(
|
|
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 =
|
|
6933
|
-
|
|
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(
|
|
6937
|
-
|
|
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 =
|
|
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,
|
|
7663
|
+
phase=phase,
|
|
7664
|
+
previousConfig=config[-1],
|
|
7665
|
+
currentConfig=config_i,
|
|
6980
7666
|
)
|
|
6981
7667
|
|
|
6982
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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,
|
|
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,
|
|
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",
|
|
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",
|
|
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,
|
|
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
|
|
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
|
|
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) / (
|
|
8046
|
+
temp_const = (theta * const.temp_0) / (
|
|
8047
|
+
theta * const.temp_0 - DeltaTemp
|
|
8048
|
+
)
|
|
7331
8049
|
if AC.BADAFamily.BADAE:
|
|
7332
|
-
gamma_i = degrees(
|
|
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(
|
|
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) =
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
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) =
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
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
|
-
"""
|
|
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
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
:param
|
|
7596
|
-
:param length:
|
|
7597
|
-
:param
|
|
7598
|
-
:param v_init:
|
|
7599
|
-
:param speedEvol: speed
|
|
7600
|
-
:param phase:
|
|
7601
|
-
:param control:
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
:param Hp_init:
|
|
7608
|
-
:param m_init:
|
|
7609
|
-
:param DeltaTemp:
|
|
7610
|
-
:param wS: longitudinal
|
|
7611
|
-
:param turnMetrics:
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
:param
|
|
7617
|
-
:param
|
|
7618
|
-
:param
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
:
|
|
7624
|
-
:
|
|
7625
|
-
:
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
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(
|
|
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(
|
|
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 (
|
|
7865
|
-
control.
|
|
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(
|
|
7985
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
8046
|
-
|
|
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
|
-
(
|
|
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
|
-
(
|
|
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 =
|
|
8108
|
-
|
|
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(
|
|
8112
|
-
|
|
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 =
|
|
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,
|
|
8940
|
+
phase=phase,
|
|
8941
|
+
previousConfig=config[-1],
|
|
8942
|
+
currentConfig=config_i,
|
|
8155
8943
|
)
|
|
8156
8944
|
|
|
8157
|
-
[HLid_i, LG_i] = AC.flightEnvelope.getAeroConfig(
|
|
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(
|
|
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,
|
|
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",
|
|
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",
|
|
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,
|
|
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
|
|
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
|
|
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) / (
|
|
9322
|
+
temp_const = (theta * const.temp_0) / (
|
|
9323
|
+
theta * const.temp_0 - DeltaTemp
|
|
9324
|
+
)
|
|
8509
9325
|
if AC.BADAFamily.BADAE:
|
|
8510
|
-
gamma_i = degrees(
|
|
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(
|
|
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
|
|
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) =
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
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) =
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
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:
|