pyBADA 0.1.0__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 +8731 -0
- pyBADA/__init__.py +0 -0
- pyBADA/aircraft/BADA3/DUMMY/BADA.GPF +113 -0
- pyBADA/aircraft/BADA3/DUMMY/BZJT__.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/BZJT__.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/BZJT__.PTD +139 -0
- pyBADA/aircraft/BADA3/DUMMY/BZJT__.PTF +73 -0
- pyBADA/aircraft/BADA3/DUMMY/GA____.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/GA____.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/GA____.PTD +71 -0
- pyBADA/aircraft/BADA3/DUMMY/GA____.PTF +39 -0
- pyBADA/aircraft/BADA3/DUMMY/J2H___.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/J2H___.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/J2H___.PTD +131 -0
- pyBADA/aircraft/BADA3/DUMMY/J2H___.PTF +69 -0
- pyBADA/aircraft/BADA3/DUMMY/J2M___.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/J2M___.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/J2M___.PTD +123 -0
- pyBADA/aircraft/BADA3/DUMMY/J2M___.PTF +65 -0
- pyBADA/aircraft/BADA3/DUMMY/J4H___.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/J4H___.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/J4H___.PTD +139 -0
- pyBADA/aircraft/BADA3/DUMMY/J4H___.PTF +73 -0
- pyBADA/aircraft/BADA3/DUMMY/ReleaseSummary +35 -0
- pyBADA/aircraft/BADA3/DUMMY/SYNONYM.NEW +155 -0
- pyBADA/aircraft/BADA3/DUMMY/TP2M__.APF +25 -0
- pyBADA/aircraft/BADA3/DUMMY/TP2M__.OPF +61 -0
- pyBADA/aircraft/BADA3/DUMMY/TP2M__.PTD +99 -0
- pyBADA/aircraft/BADA3/DUMMY/TP2M__.PTF +53 -0
- pyBADA/aircraft/BADA4/DUMMY/ACM_BADA4.xsd +556 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.ATF +106 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST.xml +244 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTD +182 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA+20.PTF +41 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTD +182 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-PST/Dummy-PST_ISA.PTF +41 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.ATF +191 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP.xml +540 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTD +218 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA+20.PTF +49 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTD +218 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/Dummy-TBP_ISA.PTF +49 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/LRC.dat +38 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MEC.dat +58 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/MRC.dat +38 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TBP/OPTALT.dat +37 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.ATF +204 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN.xml +648 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTD +281 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA+20.PTF +63 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTD +281 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/Dummy-TWIN_ISA.PTF +63 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/ECON.OPT +37 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/LRC.OPT +38 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MEC.OPT +58 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/MRC.OPT +38 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN/OPTALT.OPT +37 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.ATF +238 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus.xml +737 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTD +281 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA+20.PTF +63 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTD +281 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/Dummy-TWIN-plus_ISA.PTF +63 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/ECON.OPT +37 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/LRC.OPT +36 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MEC.OPT +56 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/MRC.OPT +36 -0
- pyBADA/aircraft/BADA4/DUMMY/Dummy-TWIN-plus/OPTALT.OPT +37 -0
- pyBADA/aircraft/BADA4/DUMMY/GPF.xml +130 -0
- pyBADA/aircraft/BADA4/DUMMY/GPF_BADA4.xsd +75 -0
- pyBADA/aircraft/BADA4/DUMMY/aircraft_model_default.xml +311 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH.ATF +97 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH.xml +82 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH_ISA+20.PTD +632 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH_ISA+20.PTF +71 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH_ISA.PTD +632 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/DUMH_ISA.PTF +71 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/LRC.OPT +142 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/MEC.OPT +142 -0
- pyBADA/aircraft/BADAH/DUMMY/DUMH/MRC.OPT +142 -0
- pyBADA/aircraft.py +414 -0
- pyBADA/atmosphere.py +345 -0
- pyBADA/bada3.py +4566 -0
- pyBADA/bada4.py +5327 -0
- pyBADA/badaE.py +3317 -0
- pyBADA/badaH.py +3632 -0
- pyBADA/configuration.py +98 -0
- pyBADA/constants.py +64 -0
- pyBADA/conversions.py +197 -0
- pyBADA/data/magneticDeclinationGridData.json +247067 -0
- pyBADA/flightTrajectory.py +929 -0
- pyBADA/geodesic.py +760 -0
- pyBADA/magnetic.py +119 -0
- pyBADA/trajectoryPrediction.py +175 -0
- pybada-0.1.0.dist-info/METADATA +57 -0
- pybada-0.1.0.dist-info/RECORD +99 -0
- pybada-0.1.0.dist-info/WHEEL +4 -0
- pybada-0.1.0.dist-info/licenses/AUTHORS +2 -0
- pybada-0.1.0.dist-info/licenses/LICENCE.txt +287 -0
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
pyBADA
|
|
4
|
+
Generic flight trajectory module
|
|
5
|
+
Developped @EUROCONTROL (EIH)
|
|
6
|
+
2024
|
|
7
|
+
"""
|
|
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
|
+
|
|
19
|
+
import os
|
|
20
|
+
import datetime
|
|
21
|
+
import pandas as pd
|
|
22
|
+
import simplekml
|
|
23
|
+
|
|
24
|
+
from pyBADA import conversions as conv
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FlightTrajectory:
|
|
28
|
+
"""This class implements the flight trajectory module and handles
|
|
29
|
+
all the operations on the flight trajectory
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.flightData = {}
|
|
35
|
+
|
|
36
|
+
def createFT(self):
|
|
37
|
+
"""This function creates a flight trajectory and populate it with input data
|
|
38
|
+
|
|
39
|
+
:param AC: aircraft {BADA3/4/H/E}
|
|
40
|
+
:param Hp: altitude
|
|
41
|
+
:param TAS: True Air Speed (TAS)
|
|
42
|
+
:param CAS: Calibrated Air Speed (CAS)
|
|
43
|
+
:param M: Mach speed (M)
|
|
44
|
+
:param ROCD: Rate of Climb/Descent
|
|
45
|
+
:param FUEL: fuel consumption
|
|
46
|
+
:param P: Power
|
|
47
|
+
:param slope: trajectory slope
|
|
48
|
+
:param acc: acceleration
|
|
49
|
+
:param THR: thrust
|
|
50
|
+
:param config: aerodynamic configuration
|
|
51
|
+
:param HLid: High Lift Device - Level of deployement
|
|
52
|
+
:param LG: Landing Gear level of deployment
|
|
53
|
+
:param mass: aircraft mass
|
|
54
|
+
:param LAT: Geographical Latitude
|
|
55
|
+
:param LON: Geographical Longitude
|
|
56
|
+
:param HDG: aircraft heading
|
|
57
|
+
:param time: time flown
|
|
58
|
+
:param dist: distance flown
|
|
59
|
+
:param comment: comment describing the trajectory segment
|
|
60
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
61
|
+
:type Hp: float
|
|
62
|
+
:type TAS: float
|
|
63
|
+
:type CAS: float
|
|
64
|
+
:type M: float
|
|
65
|
+
:type ROCD: float
|
|
66
|
+
:type FUEL: float
|
|
67
|
+
:type P: float
|
|
68
|
+
:type slope: float
|
|
69
|
+
:type acc: float
|
|
70
|
+
:type THR: float
|
|
71
|
+
:type config: string
|
|
72
|
+
:type HLid: float
|
|
73
|
+
:type LG: string
|
|
74
|
+
:type mass: float
|
|
75
|
+
:type LAT: float
|
|
76
|
+
:type LON: float
|
|
77
|
+
:type HDG: float
|
|
78
|
+
:type time: float
|
|
79
|
+
:type dist: float
|
|
80
|
+
:type comment: string
|
|
81
|
+
|
|
82
|
+
:returns: aircraft flight trajectory
|
|
83
|
+
:rtype: dict{list[float]}.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# Define the empty DataFrame with columns
|
|
87
|
+
flightTrajectory = pd.DataFrame(
|
|
88
|
+
columns=[
|
|
89
|
+
"Hp",
|
|
90
|
+
"TAS",
|
|
91
|
+
"CAS",
|
|
92
|
+
"GS",
|
|
93
|
+
"M",
|
|
94
|
+
"ROCD",
|
|
95
|
+
"ESF",
|
|
96
|
+
"FUEL",
|
|
97
|
+
"FUELCONSUMED",
|
|
98
|
+
"Preq",
|
|
99
|
+
"Peng",
|
|
100
|
+
"Pav",
|
|
101
|
+
"slope",
|
|
102
|
+
"acc",
|
|
103
|
+
"THR",
|
|
104
|
+
"DRAG",
|
|
105
|
+
"config",
|
|
106
|
+
"HLid",
|
|
107
|
+
"LG",
|
|
108
|
+
"mass",
|
|
109
|
+
"LAT",
|
|
110
|
+
"LON",
|
|
111
|
+
"HDGTrue",
|
|
112
|
+
"HDGMagnetic",
|
|
113
|
+
"time",
|
|
114
|
+
"dist",
|
|
115
|
+
"comment",
|
|
116
|
+
"BankAngle",
|
|
117
|
+
"ROT",
|
|
118
|
+
]
|
|
119
|
+
)
|
|
120
|
+
return flightTrajectory
|
|
121
|
+
|
|
122
|
+
@staticmethod
|
|
123
|
+
def createFlightTrajectoryDataframe(flight_data):
|
|
124
|
+
"""This function creates a pandas dataframe from the trajectory data in form of a list of data,
|
|
125
|
+
and fill in the missing values with None, to ensure the same size columns
|
|
126
|
+
|
|
127
|
+
:param flight_data: trajectory data
|
|
128
|
+
:type flight_data: dict{list[float]}.
|
|
129
|
+
|
|
130
|
+
:returns: aircraft flight trajectory
|
|
131
|
+
:rtype: pandas dataframe.
|
|
132
|
+
"""
|
|
133
|
+
# Find the maximum length of all lists in the flight data (ignore the Aircraft object)
|
|
134
|
+
max_length = max(
|
|
135
|
+
len(lst) if isinstance(lst, list) else 0
|
|
136
|
+
for key, lst in flight_data.items()
|
|
137
|
+
if key != "Aircraft"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Function to pad lists with None to ensure all lists are of equal length
|
|
141
|
+
def pad_list(lst, max_length):
|
|
142
|
+
return lst + [None] * (max_length - len(lst))
|
|
143
|
+
|
|
144
|
+
# Pad each list to the same length
|
|
145
|
+
for key in flight_data:
|
|
146
|
+
flight_data[key] = (
|
|
147
|
+
pad_list(flight_data[key], max_length)
|
|
148
|
+
if isinstance(flight_data[key], list)
|
|
149
|
+
else [None] * max_length
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Convert the padded data to a DataFrame
|
|
153
|
+
flightTrajectory = pd.DataFrame(flight_data)
|
|
154
|
+
|
|
155
|
+
# Explode all columns that contain lists
|
|
156
|
+
columns_to_explode = [key for key in flight_data]
|
|
157
|
+
|
|
158
|
+
# Explode the DataFrame
|
|
159
|
+
flightTrajectory_exploded = flightTrajectory.explode(columns_to_explode)
|
|
160
|
+
|
|
161
|
+
return flightTrajectory_exploded
|
|
162
|
+
|
|
163
|
+
def getACList(self):
|
|
164
|
+
"""This function return the list of aircraft in the flightTrajectory object
|
|
165
|
+
|
|
166
|
+
:returns: list of aircraft in the current flight trajectory object
|
|
167
|
+
:rtype: list[BadaAircraft].
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
return list(self.flightData.keys())
|
|
171
|
+
|
|
172
|
+
def addFT(self, AC, flightTrajectory):
|
|
173
|
+
"""This function adds the flight trajectory based on the aircraft
|
|
174
|
+
|
|
175
|
+
.. note::this will overwrite the stored data for the same aircraft
|
|
176
|
+
|
|
177
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
178
|
+
:param flightTrajectory: aircraft full flight trajectory
|
|
179
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
180
|
+
:type flightTrajectory: pandas dataframe.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
self.flightData[AC] = flightTrajectory
|
|
184
|
+
|
|
185
|
+
def getFT(self, AC):
|
|
186
|
+
"""This function returns the flight trajectory based on the aircraft
|
|
187
|
+
|
|
188
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
189
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
190
|
+
|
|
191
|
+
:returns: aircraft flight trajectory
|
|
192
|
+
:rtype: pandas dataframe.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
return self.flightData.get(AC)
|
|
196
|
+
|
|
197
|
+
def getAllValues(self, AC, parameter):
|
|
198
|
+
"""This function returns the list of values corresponding to the aircarft trajectory
|
|
199
|
+
and defined parameter name
|
|
200
|
+
|
|
201
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
202
|
+
:param parameter: name of the parameter to search for in the flight trajectory
|
|
203
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
204
|
+
:type parameter: string
|
|
205
|
+
|
|
206
|
+
:returns: value of a selected parameter for the whole trajectory
|
|
207
|
+
:rtype: list[float]
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
values = self.getFT(AC).get(parameter)
|
|
211
|
+
|
|
212
|
+
if values is not None:
|
|
213
|
+
return values.tolist()
|
|
214
|
+
else:
|
|
215
|
+
return []
|
|
216
|
+
|
|
217
|
+
def getFinalValue(self, AC, parameter):
|
|
218
|
+
"""This function returns last value corresponding to the aircarft trajectory
|
|
219
|
+
and defined parameter name
|
|
220
|
+
|
|
221
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
222
|
+
:param parameter: name of the parameter to search for in the flight trajectory
|
|
223
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
224
|
+
:type parameter: list[string]
|
|
225
|
+
|
|
226
|
+
:returns: final value in the list of a selected parameter for the whole trajectory
|
|
227
|
+
:rtype: float or string
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
if isinstance(parameter, list):
|
|
231
|
+
finalValueList = []
|
|
232
|
+
for param in parameter:
|
|
233
|
+
parameterValues = self.getAllValues(AC, param)
|
|
234
|
+
|
|
235
|
+
if not parameterValues:
|
|
236
|
+
finalValueList.append(None)
|
|
237
|
+
else:
|
|
238
|
+
finalValueList.append(parameterValues[-1])
|
|
239
|
+
return finalValueList
|
|
240
|
+
|
|
241
|
+
else:
|
|
242
|
+
parameterValues = self.getAllValues(AC, parameter)
|
|
243
|
+
if not parameterValues:
|
|
244
|
+
return None
|
|
245
|
+
else:
|
|
246
|
+
return self.getAllValues(AC, parameter)[-1]
|
|
247
|
+
|
|
248
|
+
def append(self, AC, flightTrajectoryToAppend):
|
|
249
|
+
"""This function will append data of 2 consecutive flight trajectories and merge them in terms of time and distance
|
|
250
|
+
if the aircraft is not in the list, the trajectory will be added to the flightTrajectory object
|
|
251
|
+
|
|
252
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
253
|
+
:param flightTrajectoryToAppend: second flight trajectory to combine with original one [dict]
|
|
254
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
255
|
+
:type flightTrajectoryToAppend: dict{list[float]}.
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
# retrieve the original trajectory
|
|
259
|
+
flightTrajectory = self.getFT(AC)
|
|
260
|
+
|
|
261
|
+
# Drop columns with all NaN values from both DataFrames before concatenating
|
|
262
|
+
if flightTrajectory is not None:
|
|
263
|
+
flightTrajectory = flightTrajectory.dropna(axis=1, how="all")
|
|
264
|
+
|
|
265
|
+
if flightTrajectoryToAppend is not None:
|
|
266
|
+
flightTrajectoryToAppend = flightTrajectoryToAppend.dropna(
|
|
267
|
+
axis=1, how="all"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# Make a deep copy of flightTrajectoryToAppend to avoid SettingWithCopyWarning
|
|
271
|
+
flightTrajectoryToAppend = flightTrajectoryToAppend.copy()
|
|
272
|
+
|
|
273
|
+
# Handle cumulative columns (time, distance, fuelConsumed)
|
|
274
|
+
cumulative_columns = ["time", "dist", "FUELCONSUMED"]
|
|
275
|
+
if flightTrajectory is not None and not flightTrajectory.empty:
|
|
276
|
+
# For cumulative columns, add the last value of the original to the subsequent values in the appended trajectory
|
|
277
|
+
for col in cumulative_columns:
|
|
278
|
+
if (
|
|
279
|
+
col in flightTrajectory.columns
|
|
280
|
+
and col in flightTrajectoryToAppend.columns
|
|
281
|
+
):
|
|
282
|
+
last_value = flightTrajectory[col].iloc[
|
|
283
|
+
-1
|
|
284
|
+
] # Get last value of original trajectory
|
|
285
|
+
|
|
286
|
+
# Ensure both columns are cast to float64 before performing the addition
|
|
287
|
+
flightTrajectoryToAppend[col] = flightTrajectoryToAppend[
|
|
288
|
+
col
|
|
289
|
+
].astype(float)
|
|
290
|
+
|
|
291
|
+
# Perform the cumulative addition using .loc[]
|
|
292
|
+
flightTrajectoryToAppend.loc[:, col] = flightTrajectoryToAppend[
|
|
293
|
+
col
|
|
294
|
+
] + float(last_value)
|
|
295
|
+
|
|
296
|
+
# Concatenating the two trajectory data
|
|
297
|
+
flightTrajectoryCombined = pd.concat(
|
|
298
|
+
[flightTrajectory, flightTrajectoryToAppend], ignore_index=True
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
# rewrite the original trajectory data
|
|
302
|
+
self.addFT(AC, flightTrajectoryCombined)
|
|
303
|
+
|
|
304
|
+
def cut(self, AC, parameter, threshold, direction="BELOW"):
|
|
305
|
+
"""This function cuts data from aircraft flight trajectory based on input field name and value.
|
|
306
|
+
|
|
307
|
+
.. note::The value should be sorted to work as expected.
|
|
308
|
+
|
|
309
|
+
:param AC: BadaAircraft {BADA3/4/H/E}
|
|
310
|
+
:param parameter: name of the parameter to take into account
|
|
311
|
+
:param threshold: value of the parameter where the cut shall be performed []
|
|
312
|
+
:param direction: cut above or below set threshold value []
|
|
313
|
+
:type AC: {Bada3Aircraft, Bada4Aircraft, BadaEAircraft, BadaHAircraft}.
|
|
314
|
+
:type parameter: string.
|
|
315
|
+
:type threshold: float.
|
|
316
|
+
:type direction: string {BELOW/ABOVE}.
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
flightTrajectory = self.getFT(AC)
|
|
320
|
+
|
|
321
|
+
if direction == "ABOVE":
|
|
322
|
+
flightTrajectoryCut = flightTrajectory[
|
|
323
|
+
flightTrajectory[parameter] < threshold
|
|
324
|
+
]
|
|
325
|
+
elif direction == "BELOW":
|
|
326
|
+
flightTrajectoryCut = flightTrajectory[
|
|
327
|
+
flightTrajectory[parameter] > threshold
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
self.addFT(AC, flightTrajectoryCut)
|
|
331
|
+
|
|
332
|
+
def save2csv(self, saveToPath, separator=","):
|
|
333
|
+
"""
|
|
334
|
+
This function saves the trajectory into a CSV file.
|
|
335
|
+
|
|
336
|
+
:param saveToPath: Path to directory where the file should be stored.
|
|
337
|
+
:param separator: Separator to be used in the CSV file (only applicable for CSV). Default is a comma (',').
|
|
338
|
+
:type saveToPath: string
|
|
339
|
+
:type separator: string
|
|
340
|
+
:returns: None
|
|
341
|
+
"""
|
|
342
|
+
|
|
343
|
+
# Get the current time in a suitable format for filenames
|
|
344
|
+
currentTime = "_".join(
|
|
345
|
+
str(datetime.datetime.now()).split(".")[0].split(" ")
|
|
346
|
+
).replace(":", "-")
|
|
347
|
+
|
|
348
|
+
# Create the full directory path
|
|
349
|
+
filepath = os.path.join(saveToPath, f"export_{currentTime}")
|
|
350
|
+
|
|
351
|
+
# Check if the directory exists, if not create it
|
|
352
|
+
if not os.path.exists(filepath):
|
|
353
|
+
os.makedirs(filepath)
|
|
354
|
+
|
|
355
|
+
# Loop through the aircraft list
|
|
356
|
+
for AC in self.getACList():
|
|
357
|
+
# Get the aircraft ID
|
|
358
|
+
AC_ID = str(id(AC))
|
|
359
|
+
|
|
360
|
+
# Flight Trajectory data
|
|
361
|
+
flightTrajectory = self.getFT(AC)
|
|
362
|
+
|
|
363
|
+
filename = os.path.join(filepath, f"{AC.acName}_ID{AC_ID}.csv")
|
|
364
|
+
|
|
365
|
+
# get custom header based on the BADA Family and some other calculation specificities
|
|
366
|
+
if AC.BADAFamily.BADA3:
|
|
367
|
+
if (
|
|
368
|
+
"LAT" in flightTrajectory.columns
|
|
369
|
+
and "LON" in flightTrajectory.columns
|
|
370
|
+
):
|
|
371
|
+
customHeader = [
|
|
372
|
+
"Hp [ft]",
|
|
373
|
+
"TAS [kt]",
|
|
374
|
+
"CAS [kt]",
|
|
375
|
+
"GS [kt]",
|
|
376
|
+
"M [-]",
|
|
377
|
+
"acc [m/s^2]",
|
|
378
|
+
"ROCD [ft/min]",
|
|
379
|
+
"ESF []",
|
|
380
|
+
"FUEL [kg/s]",
|
|
381
|
+
"FUELCONSUMED [kg]",
|
|
382
|
+
"THR [N]",
|
|
383
|
+
" DRAG [N]",
|
|
384
|
+
"t [s]",
|
|
385
|
+
"d [NM]",
|
|
386
|
+
"slope [deg]",
|
|
387
|
+
"m [kg]",
|
|
388
|
+
"config",
|
|
389
|
+
"LAT [deg]",
|
|
390
|
+
"LON [deg]",
|
|
391
|
+
"HDG True [deg]",
|
|
392
|
+
"HDG Magnetic [deg]",
|
|
393
|
+
"bankAngle [deg]",
|
|
394
|
+
" ROT [deg/s]",
|
|
395
|
+
"COMMENT",
|
|
396
|
+
]
|
|
397
|
+
else:
|
|
398
|
+
customHeader = [
|
|
399
|
+
"Hp [ft]",
|
|
400
|
+
"TAS [kt]",
|
|
401
|
+
"CAS [kt]",
|
|
402
|
+
"GS [kt]",
|
|
403
|
+
"M [-]",
|
|
404
|
+
"acc [m/s^2]",
|
|
405
|
+
"ROCD [ft/min]",
|
|
406
|
+
"ESF []",
|
|
407
|
+
"FUEL [kg/s]",
|
|
408
|
+
"FUELCONSUMED [kg]",
|
|
409
|
+
"THR [N]",
|
|
410
|
+
" DRAG [N]",
|
|
411
|
+
"t [s]",
|
|
412
|
+
"d [NM]",
|
|
413
|
+
"slope [deg]",
|
|
414
|
+
"m [kg]",
|
|
415
|
+
"config",
|
|
416
|
+
"bankAngle [deg]",
|
|
417
|
+
" ROT [deg/s]",
|
|
418
|
+
"COMMENT",
|
|
419
|
+
]
|
|
420
|
+
|
|
421
|
+
elif AC.BADAFamily.BADA4:
|
|
422
|
+
if (
|
|
423
|
+
"LAT" in flightTrajectory.columns
|
|
424
|
+
and "LON" in flightTrajectory.columns
|
|
425
|
+
):
|
|
426
|
+
customHeader = [
|
|
427
|
+
"Hp [ft]",
|
|
428
|
+
"TAS [kt]",
|
|
429
|
+
"CAS [kt]",
|
|
430
|
+
"GS [kt]",
|
|
431
|
+
"M [-]",
|
|
432
|
+
"acc [m/s^2]",
|
|
433
|
+
"ROCD [ft/min]",
|
|
434
|
+
"ESF []",
|
|
435
|
+
"FUEL [kg/s]",
|
|
436
|
+
"FUELCONSUMED [kg]",
|
|
437
|
+
"THR [N]",
|
|
438
|
+
" DRAG [N]",
|
|
439
|
+
"t [s]",
|
|
440
|
+
"d [NM]",
|
|
441
|
+
"slope [deg]",
|
|
442
|
+
"m [kg]",
|
|
443
|
+
"config",
|
|
444
|
+
"HLid",
|
|
445
|
+
"LG",
|
|
446
|
+
"LAT [deg]",
|
|
447
|
+
"LON [deg]",
|
|
448
|
+
"HDG True [deg]",
|
|
449
|
+
"HDG Magnetic [deg]",
|
|
450
|
+
"bankAngle [deg]",
|
|
451
|
+
" ROT [deg/s]",
|
|
452
|
+
"COMMENT",
|
|
453
|
+
]
|
|
454
|
+
else:
|
|
455
|
+
customHeader = [
|
|
456
|
+
"Hp [ft]",
|
|
457
|
+
"TAS [kt]",
|
|
458
|
+
"CAS [kt]",
|
|
459
|
+
"GS [kt]",
|
|
460
|
+
"M [-]",
|
|
461
|
+
"acc [m/s^2]",
|
|
462
|
+
"ROCD [ft/min]",
|
|
463
|
+
"ESF []",
|
|
464
|
+
"FUEL [kg/s]",
|
|
465
|
+
"FUELCONSUMED [kg]",
|
|
466
|
+
"THR [N]",
|
|
467
|
+
" DRAG [N]",
|
|
468
|
+
"t [s]",
|
|
469
|
+
"d [NM]",
|
|
470
|
+
"slope [deg]",
|
|
471
|
+
"m [kg]",
|
|
472
|
+
"config",
|
|
473
|
+
"HLid",
|
|
474
|
+
"LG",
|
|
475
|
+
"bankAngle [deg]",
|
|
476
|
+
" ROT [deg/s]",
|
|
477
|
+
"COMMENT",
|
|
478
|
+
]
|
|
479
|
+
|
|
480
|
+
elif AC.BADAFamily.BADAH:
|
|
481
|
+
if (
|
|
482
|
+
"LAT" in flightTrajectory.columns
|
|
483
|
+
and "LON" in flightTrajectory.columns
|
|
484
|
+
):
|
|
485
|
+
customHeader = [
|
|
486
|
+
"Hp [ft]",
|
|
487
|
+
"TAS [kt]",
|
|
488
|
+
"CAS [kt]",
|
|
489
|
+
"GS [kt]",
|
|
490
|
+
"M [-]",
|
|
491
|
+
"acc [m/s^2]",
|
|
492
|
+
"ROCD [ft/min]",
|
|
493
|
+
"ESF []",
|
|
494
|
+
"FUEL [kg/s]",
|
|
495
|
+
"FUELCONSUMED [kg]",
|
|
496
|
+
"Peng [W]",
|
|
497
|
+
"Preq [W]",
|
|
498
|
+
"Pav [W]",
|
|
499
|
+
"t [s]",
|
|
500
|
+
"d [NM]",
|
|
501
|
+
"slope [deg]",
|
|
502
|
+
"m [kg]",
|
|
503
|
+
"LAT [deg]",
|
|
504
|
+
"LON [deg]",
|
|
505
|
+
"HDG True [deg]",
|
|
506
|
+
"HDG Magnetic [deg]",
|
|
507
|
+
"bankAngle [deg]",
|
|
508
|
+
" ROT [deg/s]",
|
|
509
|
+
"COMMENT",
|
|
510
|
+
]
|
|
511
|
+
else:
|
|
512
|
+
customHeader = [
|
|
513
|
+
"Hp [ft]",
|
|
514
|
+
"TAS [kt]",
|
|
515
|
+
"CAS [kt]",
|
|
516
|
+
"GS [kt]",
|
|
517
|
+
"M [-]",
|
|
518
|
+
"acc [m/s^2]",
|
|
519
|
+
"ROCD [ft/min]",
|
|
520
|
+
"ESF []",
|
|
521
|
+
"FUEL [kg/s]",
|
|
522
|
+
"FUELCONSUMED [kg]",
|
|
523
|
+
"Peng [W]",
|
|
524
|
+
"Preq [W]",
|
|
525
|
+
"Pav [W]",
|
|
526
|
+
"t [s]",
|
|
527
|
+
"d [NM]",
|
|
528
|
+
"slope [deg]",
|
|
529
|
+
"m [kg]",
|
|
530
|
+
"bankAngle [deg]",
|
|
531
|
+
" ROT [deg/s]",
|
|
532
|
+
"COMMENT",
|
|
533
|
+
]
|
|
534
|
+
|
|
535
|
+
elif AC.BADAFamily.BADAE:
|
|
536
|
+
if (
|
|
537
|
+
"LAT" in flightTrajectory.columns
|
|
538
|
+
and "LON" in flightTrajectory.columns
|
|
539
|
+
):
|
|
540
|
+
customHeader = [
|
|
541
|
+
"Hp [ft]",
|
|
542
|
+
"TAS [kt]",
|
|
543
|
+
"CAS [kt]",
|
|
544
|
+
"GS [kt]",
|
|
545
|
+
"M [-]",
|
|
546
|
+
"acc [m/s^2]",
|
|
547
|
+
"ROCD [ft/min]",
|
|
548
|
+
"ESF []",
|
|
549
|
+
"Pmec [W]",
|
|
550
|
+
"Pelc [W]",
|
|
551
|
+
"Pbat, [W]",
|
|
552
|
+
"SOCr [%/h]",
|
|
553
|
+
"SOC [%]",
|
|
554
|
+
"Ibat [A]",
|
|
555
|
+
"Vbat [V];",
|
|
556
|
+
"Vgbat [V]",
|
|
557
|
+
"t [s]",
|
|
558
|
+
"d [NM]",
|
|
559
|
+
"slope [deg]",
|
|
560
|
+
"m [kg]",
|
|
561
|
+
"LAT [deg]",
|
|
562
|
+
"LON [deg]",
|
|
563
|
+
"HDG True [deg]",
|
|
564
|
+
"HDG Magnetic [deg]",
|
|
565
|
+
"bankAngle [deg]",
|
|
566
|
+
" ROT [deg/s]",
|
|
567
|
+
"COMMENT",
|
|
568
|
+
]
|
|
569
|
+
else:
|
|
570
|
+
customHeader = [
|
|
571
|
+
"Hp [ft]",
|
|
572
|
+
"TAS [kt]",
|
|
573
|
+
"CAS [kt]",
|
|
574
|
+
"GS [kt]",
|
|
575
|
+
"M [-]",
|
|
576
|
+
"acc [m/s^2]",
|
|
577
|
+
"ROCD [ft/min]",
|
|
578
|
+
"ESF []",
|
|
579
|
+
"Pmec [W]",
|
|
580
|
+
"Pelc [W]",
|
|
581
|
+
"Pbat, [W]",
|
|
582
|
+
"SOCr [%/h]",
|
|
583
|
+
"SOC [%]",
|
|
584
|
+
"Ibat [A]",
|
|
585
|
+
"Vbat [V];",
|
|
586
|
+
"Vgbat [V]",
|
|
587
|
+
"t [s]",
|
|
588
|
+
"d [NM]",
|
|
589
|
+
"slope [deg]",
|
|
590
|
+
"m [kg]",
|
|
591
|
+
"bankAngle [deg]",
|
|
592
|
+
" ROT [deg/s]",
|
|
593
|
+
"COMMENT",
|
|
594
|
+
]
|
|
595
|
+
|
|
596
|
+
# Save to CSV file with custom header and separator
|
|
597
|
+
flightTrajectory.to_csv(
|
|
598
|
+
filename, sep=separator, index=False, header=customHeader
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
def save2xlsx(self, saveToPath):
|
|
602
|
+
"""
|
|
603
|
+
This function saves the trajectory into a Excel/xlsx file.
|
|
604
|
+
|
|
605
|
+
:param saveToPath: Path to directory where the file should be stored.
|
|
606
|
+
:param separator: Separator to be used in the CSV file (only applicable for CSV). Default is a comma (',').
|
|
607
|
+
:type saveToPath: string
|
|
608
|
+
:type separator: string
|
|
609
|
+
:returns: None
|
|
610
|
+
"""
|
|
611
|
+
|
|
612
|
+
# Get the current time in a suitable format for filenames
|
|
613
|
+
currentTime = "_".join(
|
|
614
|
+
str(datetime.datetime.now()).split(".")[0].split(" ")
|
|
615
|
+
).replace(":", "-")
|
|
616
|
+
|
|
617
|
+
# Create the full directory path
|
|
618
|
+
filepath = os.path.join(saveToPath, f"export_{currentTime}")
|
|
619
|
+
|
|
620
|
+
# Check if the directory exists, if not create it
|
|
621
|
+
if not os.path.exists(filepath):
|
|
622
|
+
os.makedirs(filepath)
|
|
623
|
+
|
|
624
|
+
# Loop through the aircraft list
|
|
625
|
+
for AC in self.getACList():
|
|
626
|
+
# Get the aircraft ID
|
|
627
|
+
AC_ID = str(id(AC))
|
|
628
|
+
|
|
629
|
+
# Flight Trajectory data
|
|
630
|
+
flightTrajectory = self.getFT(AC)
|
|
631
|
+
|
|
632
|
+
filename = os.path.join(filepath, f"{AC.acName}_ID{AC_ID}.xlsx")
|
|
633
|
+
|
|
634
|
+
# get custom header based on the BADA Family and some other calculation specificities
|
|
635
|
+
if AC.BADAFamily.BADA3:
|
|
636
|
+
if (
|
|
637
|
+
"LAT" in flightTrajectory.columns
|
|
638
|
+
and "LON" in flightTrajectory.columns
|
|
639
|
+
):
|
|
640
|
+
customHeader = [
|
|
641
|
+
"Hp [ft]",
|
|
642
|
+
"TAS [kt]",
|
|
643
|
+
"CAS [kt]",
|
|
644
|
+
"GS [kt]",
|
|
645
|
+
"M [-]",
|
|
646
|
+
"acc [m/s^2]",
|
|
647
|
+
"ROCD [ft/min]",
|
|
648
|
+
"ESF []",
|
|
649
|
+
"FUEL [kg/s]",
|
|
650
|
+
"FUELCONSUMED [kg]",
|
|
651
|
+
"THR [N]",
|
|
652
|
+
" DRAG [N]",
|
|
653
|
+
"t [s]",
|
|
654
|
+
"d [NM]",
|
|
655
|
+
"slope [deg]",
|
|
656
|
+
"m [kg]",
|
|
657
|
+
"config",
|
|
658
|
+
"LAT [deg]",
|
|
659
|
+
"LON [deg]",
|
|
660
|
+
"HDG True [deg]",
|
|
661
|
+
"HDG Magnetic [deg]",
|
|
662
|
+
"bankAngle [deg]",
|
|
663
|
+
" ROT [deg/s]",
|
|
664
|
+
"COMMENT",
|
|
665
|
+
]
|
|
666
|
+
else:
|
|
667
|
+
customHeader = [
|
|
668
|
+
"Hp [ft]",
|
|
669
|
+
"TAS [kt]",
|
|
670
|
+
"CAS [kt]",
|
|
671
|
+
"GS [kt]",
|
|
672
|
+
"M [-]",
|
|
673
|
+
"acc [m/s^2]",
|
|
674
|
+
"ROCD [ft/min]",
|
|
675
|
+
"ESF []",
|
|
676
|
+
"FUEL [kg/s]",
|
|
677
|
+
"FUELCONSUMED [kg]",
|
|
678
|
+
"THR [N]",
|
|
679
|
+
" DRAG [N]",
|
|
680
|
+
"t [s]",
|
|
681
|
+
"d [NM]",
|
|
682
|
+
"slope [deg]",
|
|
683
|
+
"m [kg]",
|
|
684
|
+
"config",
|
|
685
|
+
"bankAngle [deg]",
|
|
686
|
+
" ROT [deg/s]",
|
|
687
|
+
"COMMENT",
|
|
688
|
+
]
|
|
689
|
+
|
|
690
|
+
elif AC.BADAFamily.BADA4:
|
|
691
|
+
if (
|
|
692
|
+
"LAT" in flightTrajectory.columns
|
|
693
|
+
and "LON" in flightTrajectory.columns
|
|
694
|
+
):
|
|
695
|
+
customHeader = [
|
|
696
|
+
"Hp [ft]",
|
|
697
|
+
"TAS [kt]",
|
|
698
|
+
"CAS [kt]",
|
|
699
|
+
"GS [kt]",
|
|
700
|
+
"M [-]",
|
|
701
|
+
"acc [m/s^2]",
|
|
702
|
+
"ROCD [ft/min]",
|
|
703
|
+
"ESF []",
|
|
704
|
+
"FUEL [kg/s]",
|
|
705
|
+
"FUELCONSUMED [kg]",
|
|
706
|
+
"THR [N]",
|
|
707
|
+
" DRAG [N]",
|
|
708
|
+
"t [s]",
|
|
709
|
+
"d [NM]",
|
|
710
|
+
"slope [deg]",
|
|
711
|
+
"m [kg]",
|
|
712
|
+
"config",
|
|
713
|
+
"HLid",
|
|
714
|
+
"LG",
|
|
715
|
+
"LAT [deg]",
|
|
716
|
+
"LON [deg]",
|
|
717
|
+
"HDG True [deg]",
|
|
718
|
+
"HDG Magnetic [deg]",
|
|
719
|
+
"bankAngle [deg]",
|
|
720
|
+
" ROT [deg/s]",
|
|
721
|
+
"COMMENT",
|
|
722
|
+
]
|
|
723
|
+
else:
|
|
724
|
+
customHeader = [
|
|
725
|
+
"Hp [ft]",
|
|
726
|
+
"TAS [kt]",
|
|
727
|
+
"CAS [kt]",
|
|
728
|
+
"GS [kt]",
|
|
729
|
+
"M [-]",
|
|
730
|
+
"acc [m/s^2]",
|
|
731
|
+
"ROCD [ft/min]",
|
|
732
|
+
"ESF []",
|
|
733
|
+
"FUEL [kg/s]",
|
|
734
|
+
"FUELCONSUMED [kg]",
|
|
735
|
+
"THR [N]",
|
|
736
|
+
" DRAG [N]",
|
|
737
|
+
"t [s]",
|
|
738
|
+
"d [NM]",
|
|
739
|
+
"slope [deg]",
|
|
740
|
+
"m [kg]",
|
|
741
|
+
"config",
|
|
742
|
+
"HLid",
|
|
743
|
+
"LG",
|
|
744
|
+
"bankAngle [deg]",
|
|
745
|
+
" ROT [deg/s]",
|
|
746
|
+
"COMMENT",
|
|
747
|
+
]
|
|
748
|
+
|
|
749
|
+
elif AC.BADAFamily.BADAH:
|
|
750
|
+
if (
|
|
751
|
+
"LAT" in flightTrajectory.columns
|
|
752
|
+
and "LON" in flightTrajectory.columns
|
|
753
|
+
):
|
|
754
|
+
customHeader = [
|
|
755
|
+
"Hp [ft]",
|
|
756
|
+
"TAS [kt]",
|
|
757
|
+
"CAS [kt]",
|
|
758
|
+
"GS [kt]",
|
|
759
|
+
"M [-]",
|
|
760
|
+
"acc [m/s^2]",
|
|
761
|
+
"ROCD [ft/min]",
|
|
762
|
+
"ESF []",
|
|
763
|
+
"FUEL [kg/s]",
|
|
764
|
+
"FUELCONSUMED [kg]",
|
|
765
|
+
"Peng [W]",
|
|
766
|
+
"Preq [W]",
|
|
767
|
+
"Pav [W]",
|
|
768
|
+
"t [s]",
|
|
769
|
+
"d [NM]",
|
|
770
|
+
"slope [deg]",
|
|
771
|
+
"m [kg]",
|
|
772
|
+
"LAT [deg]",
|
|
773
|
+
"LON [deg]",
|
|
774
|
+
"HDG True [deg]",
|
|
775
|
+
"HDG Magnetic [deg]",
|
|
776
|
+
"bankAngle [deg]",
|
|
777
|
+
" ROT [deg/s]",
|
|
778
|
+
"COMMENT",
|
|
779
|
+
]
|
|
780
|
+
else:
|
|
781
|
+
customHeader = [
|
|
782
|
+
"Hp [ft]",
|
|
783
|
+
"TAS [kt]",
|
|
784
|
+
"CAS [kt]",
|
|
785
|
+
"GS [kt]",
|
|
786
|
+
"M [-]",
|
|
787
|
+
"acc [m/s^2]",
|
|
788
|
+
"ROCD [ft/min]",
|
|
789
|
+
"ESF []",
|
|
790
|
+
"FUEL [kg/s]",
|
|
791
|
+
"FUELCONSUMED [kg]",
|
|
792
|
+
"Peng [W]",
|
|
793
|
+
"Preq [W]",
|
|
794
|
+
"Pav [W]",
|
|
795
|
+
"t [s]",
|
|
796
|
+
"d [NM]",
|
|
797
|
+
"slope [deg]",
|
|
798
|
+
"m [kg]",
|
|
799
|
+
"bankAngle [deg]",
|
|
800
|
+
" ROT [deg/s]",
|
|
801
|
+
"COMMENT",
|
|
802
|
+
]
|
|
803
|
+
|
|
804
|
+
elif AC.BADAFamily.BADAE:
|
|
805
|
+
if (
|
|
806
|
+
"LAT" in flightTrajectory.columns
|
|
807
|
+
and "LON" in flightTrajectory.columns
|
|
808
|
+
):
|
|
809
|
+
customHeader = [
|
|
810
|
+
"Hp [ft]",
|
|
811
|
+
"TAS [kt]",
|
|
812
|
+
"CAS [kt]",
|
|
813
|
+
"GS [kt]",
|
|
814
|
+
"M [-]",
|
|
815
|
+
"acc [m/s^2]",
|
|
816
|
+
"ROCD [ft/min]",
|
|
817
|
+
"ESF []",
|
|
818
|
+
"Pmec [W]",
|
|
819
|
+
"Pelc [W]",
|
|
820
|
+
"Pbat, [W]",
|
|
821
|
+
"SOCr [%/h]",
|
|
822
|
+
"SOC [%]",
|
|
823
|
+
"Ibat [A]",
|
|
824
|
+
"Vbat [V];",
|
|
825
|
+
"Vgbat [V]",
|
|
826
|
+
"t [s]",
|
|
827
|
+
"d [NM]",
|
|
828
|
+
"slope [deg]",
|
|
829
|
+
"m [kg]",
|
|
830
|
+
"LAT [deg]",
|
|
831
|
+
"LON [deg]",
|
|
832
|
+
"HDG True [deg]",
|
|
833
|
+
"HDG Magnetic [deg]",
|
|
834
|
+
"bankAngle [deg]",
|
|
835
|
+
" ROT [deg/s]",
|
|
836
|
+
"COMMENT",
|
|
837
|
+
]
|
|
838
|
+
else:
|
|
839
|
+
customHeader = [
|
|
840
|
+
"Hp [ft]",
|
|
841
|
+
"TAS [kt]",
|
|
842
|
+
"CAS [kt]",
|
|
843
|
+
"GS [kt]",
|
|
844
|
+
"M [-]",
|
|
845
|
+
"acc [m/s^2]",
|
|
846
|
+
"ROCD [ft/min]",
|
|
847
|
+
"ESF []",
|
|
848
|
+
"Pmec [W]",
|
|
849
|
+
"Pelc [W]",
|
|
850
|
+
"Pbat, [W]",
|
|
851
|
+
"SOCr [%/h]",
|
|
852
|
+
"SOC [%]",
|
|
853
|
+
"Ibat [A]",
|
|
854
|
+
"Vbat [V];",
|
|
855
|
+
"Vgbat [V]",
|
|
856
|
+
"t [s]",
|
|
857
|
+
"d [NM]",
|
|
858
|
+
"slope [deg]",
|
|
859
|
+
"m [kg]",
|
|
860
|
+
"bankAngle [deg]",
|
|
861
|
+
" ROT [deg/s]",
|
|
862
|
+
"COMMENT",
|
|
863
|
+
]
|
|
864
|
+
|
|
865
|
+
# Save to xlsx file, since xlsx format doesn’t use a separator
|
|
866
|
+
with pd.ExcelWriter(filename, engine="xlsxwriter") as writer:
|
|
867
|
+
flightTrajectory.to_excel(writer, index=False, header=customHeader)
|
|
868
|
+
|
|
869
|
+
def save2kml(self, saveToPath):
|
|
870
|
+
"""
|
|
871
|
+
This function saves the trajectory into a KML file.
|
|
872
|
+
|
|
873
|
+
:param saveToPath: Path to directory where the file should be stored.
|
|
874
|
+
:param separator: Separator to be used in the CSV file (only applicable for CSV). Default is a comma (',').
|
|
875
|
+
:type saveToPath: string
|
|
876
|
+
:type separator: string
|
|
877
|
+
:returns: None
|
|
878
|
+
"""
|
|
879
|
+
# Create a KML object
|
|
880
|
+
kml = simplekml.Kml()
|
|
881
|
+
|
|
882
|
+
# Get the current time in a suitable format for filenames
|
|
883
|
+
currentTime = "_".join(
|
|
884
|
+
str(datetime.datetime.now()).split(".")[0].split(" ")
|
|
885
|
+
).replace(":", "-")
|
|
886
|
+
|
|
887
|
+
# Create the full directory path
|
|
888
|
+
filepath = os.path.join(saveToPath, f"export_{currentTime}")
|
|
889
|
+
|
|
890
|
+
# Check if the directory exists, if not create it
|
|
891
|
+
if not os.path.exists(filepath):
|
|
892
|
+
os.makedirs(filepath)
|
|
893
|
+
|
|
894
|
+
# Loop through the aircraft list
|
|
895
|
+
for AC in self.getACList():
|
|
896
|
+
# Get the aircraft ID
|
|
897
|
+
AC_ID = str(id(AC))
|
|
898
|
+
|
|
899
|
+
# Flight Trajectory data
|
|
900
|
+
flightTrajectory = self.getFT(AC)
|
|
901
|
+
|
|
902
|
+
if not all(col in flightTrajectory.columns for col in ["LAT", "LON", "Hp"]):
|
|
903
|
+
print(f"Skipping {AC_ID}: Required columns (LAT, LON, Hp) are missing.")
|
|
904
|
+
continue
|
|
905
|
+
|
|
906
|
+
filename = os.path.join(filepath, f"{AC.acName}_ID{AC_ID}.kml")
|
|
907
|
+
|
|
908
|
+
# Create a LineString for each aircraft's trajectory
|
|
909
|
+
linestring = kml.newlinestring(name=f"{AC.acName} Trajectory")
|
|
910
|
+
linestring.coords = [
|
|
911
|
+
(row["LON"], row["LAT"], conv.ft2m(row["Hp"]))
|
|
912
|
+
for _, row in flightTrajectory.iterrows()
|
|
913
|
+
]
|
|
914
|
+
linestring.altitudemode = (
|
|
915
|
+
simplekml.AltitudeMode.absolute
|
|
916
|
+
) # Set altitude mode to absolute
|
|
917
|
+
|
|
918
|
+
# Customize the line style for altitude extrusion and color (Yellow)
|
|
919
|
+
linestring.style.linestyle.color = simplekml.Color.yellow # Yellow line
|
|
920
|
+
linestring.style.linestyle.width = 3 # Line width in pixels
|
|
921
|
+
linestring.extrude = 1 # Enable altitude extrusion
|
|
922
|
+
|
|
923
|
+
# Customize the fill color (extruded space) between the line and the ground
|
|
924
|
+
linestring.style.polystyle.color = simplekml.Color.changealpha(
|
|
925
|
+
"80", simplekml.Color.yellow
|
|
926
|
+
) # 50% transparent yellow
|
|
927
|
+
|
|
928
|
+
# Save the KML file
|
|
929
|
+
kml.save(filename)
|