Template
add programs
This commit is contained in:
Executable
+144
@@ -0,0 +1,144 @@
|
|||||||
|
"""
|
||||||
|
This program converts an EFIS file to csv
|
||||||
|
|
||||||
|
example:
|
||||||
|
MacPro:programs ken$ python efis2csv.py ../N72KH\ Data/flights/19oct2018/N72KH_EFIS_19oct2018/LOG000N_F.TXT
|
||||||
|
which prints the csv format to standard out
|
||||||
|
|
||||||
|
MacPro:programs ken$ python efis2csv.py ../N72KH\ Data/flights/19oct2018/N72KH_EFIS_19oct2018/LOG000N_F.TXT > ../N72KH\ Data/flights/19oct2018/N72KH_EFIS_19oct2018/LOG000N_F.csv
|
||||||
|
which pipes standard out to LOG000N_F.csv
|
||||||
|
|
||||||
|
or run from flights/
|
||||||
|
MacPro:flights ken$ python ../../programs/efis2csv.py 10oct2018/N72KH_EFIS_10oct2018/LOG000N_F.TXT > 10oct2018/N72KH_EFIS_10oct2018/LOG000N_F.csv
|
||||||
|
|
||||||
|
|
||||||
|
Dynon EFIS data description:
|
||||||
|
index, width, description, comment
|
||||||
|
|
||||||
|
1, 2, Hour, 00 to 23, current hour according to EFIS-D10As internal clock
|
||||||
|
3, 2, Minute, 00 to 59, current minute according to EFIS-D10As internal clock
|
||||||
|
5, 2, Second, 00 to 59, current second according to EFIS-D10As internal clock
|
||||||
|
7, 2, Fractions, 00 to 63, counter for 1/64 second. Data output frequency.
|
||||||
|
9, 1, Pitch Sign, + or - (positive means plane is pitched up)
|
||||||
|
10, 3, Pitch, 000 to 900, pitch up or down from level flight in 1/10 degrees (900 = 90o)
|
||||||
|
13, 1, Roll Sign, + or - (positive means plane is banked right)
|
||||||
|
14, 4, Roll, 0000 to 1800, roll left or right from level flight in 1/10 degrees (1800 = 180o)
|
||||||
|
18, 3, Yaw, 000 to 359 in degrees (000 = North, 090 = East, 180 = South, 270 = West)
|
||||||
|
21, 4, Airspeed, 0000 to 9999, airspeed in units of 1/10 m/s (1555 = 155.5 m/s)
|
||||||
|
25, 1, Altitude Sign, + or - (positive means altitude is above sea-level)
|
||||||
|
26, 4, Altitude, 0000 to 9999, altitude in units of meters
|
||||||
|
30, 1, Turn Rate Sign, + or - (positive means plane is turning right)
|
||||||
|
31, 3, Turn Rate, 000 to 999, 1/10 degrees/second rate of yaw change
|
||||||
|
34, 1, Lateral Gs Sign, + or - (positive means plane is experiencing leftward lateral acceleration)
|
||||||
|
35, 2, Lateral Gs, 00 to 99, lateral Gs in units of 1/100 G (99 = 0.99 Gs)
|
||||||
|
37, 1, Vertical Gs Sign, + or - (positive means plane is experiencing upward vertical acceleration)
|
||||||
|
38, 2, Vertical Gs, 00 to 99, vertical Gs in units of 1/10 G (99 = 9.9 Gs)
|
||||||
|
40, 2, Angle of Attack, 00 to 99, percentage of stall angle.
|
||||||
|
42, 6, Status Bitmask, An internal-use status bitmask containing 24 bits
|
||||||
|
48, 2, Product ID, Ascii-hex Dynon product ID: 01=EFIS-D10A, 10=EFIS-D10, 03=EMS-D10
|
||||||
|
50, 2, Checksum, The ascii-hex 2 byte sum of all 49 preceding bytes
|
||||||
|
52, 2, CR/LF, Carriage Return, Linefeed = 0x0D, 0x0A
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
|
||||||
|
"""
|
||||||
|
open file and read a byte at a time into a buffer
|
||||||
|
when two headers have been found, process bytes inbetween
|
||||||
|
then copy second header into the beginning of a new buffer and throw away old buffer
|
||||||
|
lines are only valid if surrounded by headers, otherwise they may be incomplete
|
||||||
|
"""
|
||||||
|
|
||||||
|
def calculate(buf):
|
||||||
|
"""
|
||||||
|
one buffer of data.
|
||||||
|
"""
|
||||||
|
feetpermeter=3.2808399
|
||||||
|
mps2mph=2.2369363
|
||||||
|
hrs=int(buf[0:2])
|
||||||
|
min=int(buf[2:4])
|
||||||
|
sec=int(buf[4:6])
|
||||||
|
alti=int(buf[25:29])*feetpermeter
|
||||||
|
altsign=buf[24]
|
||||||
|
if altsign=='-': alti=alti*-1
|
||||||
|
airspeed=(int(buf[20:24])/10.0)*mps2mph
|
||||||
|
|
||||||
|
values = (hrs,min,sec,\
|
||||||
|
alti,airspeed)
|
||||||
|
#return values
|
||||||
|
|
||||||
|
|
||||||
|
def efistime(buf):
|
||||||
|
hrs=int(buf[0:2])
|
||||||
|
min=int(buf[2:4])
|
||||||
|
sec=int(buf[4:6])
|
||||||
|
return(hrs,min,sec)
|
||||||
|
|
||||||
|
def alti(buf):
|
||||||
|
feetpermeter=3.2808399
|
||||||
|
alti=int(buf[25:29])*feetpermeter
|
||||||
|
altsign=buf[24]
|
||||||
|
if altsign=='-': alti=alti*-1
|
||||||
|
return(alti)
|
||||||
|
|
||||||
|
def pitch(buf):
|
||||||
|
pit=int(buf[9:12])/10.0
|
||||||
|
pitsign=buf[8]
|
||||||
|
if pitsign=='-': pit=pit*-1
|
||||||
|
return(pit)
|
||||||
|
|
||||||
|
def roll(buf):
|
||||||
|
roll=int(buf[13:17])/10.0
|
||||||
|
rollsign=buf[12]
|
||||||
|
if rollsign=='-': roll=roll*-1
|
||||||
|
return(roll)
|
||||||
|
|
||||||
|
def yaw(buf):
|
||||||
|
yaw=int(buf[17:20])
|
||||||
|
return(yaw)
|
||||||
|
|
||||||
|
def airspeed(buf):
|
||||||
|
mps2mph=2.2369363
|
||||||
|
return((int(buf[20:24])/10.0)*mps2mph)
|
||||||
|
|
||||||
|
def aoa(buf):
|
||||||
|
return(int(buf[39:41]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def output_values(h,m,s,alti,airspeed,aoa,pitch,roll,yaw):
|
||||||
|
print(("%02d:%02d:%02d, " # h,m,s
|
||||||
|
"%d, %d, %d, " # alti,airspeed, aoa
|
||||||
|
"%4.1f, %4.1f, %d") % (h,m,s,alti,airspeed,aoa,pitch,roll,yaw))
|
||||||
|
|
||||||
|
|
||||||
|
def read_data(name):
|
||||||
|
with open(name, "r") as f:
|
||||||
|
buf1=[] # start with buffer clear
|
||||||
|
l1=f.readline()
|
||||||
|
while l1 != "": # not EOF
|
||||||
|
#print(l1)
|
||||||
|
if (len(l1)==52): # was 53 with openlog
|
||||||
|
b=l1
|
||||||
|
output_values(efistime(b)[0],efistime(b)[1],efistime(b)[2],alti(b),airspeed(b),aoa(b),pitch(b),roll(b),yaw(b))
|
||||||
|
l1=f.readline()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='EFIS csv converter',
|
||||||
|
epilog="./%(prog)s [options] > outputfile.csv to save the result")
|
||||||
|
parser.add_argument('fname',
|
||||||
|
help='file name to convert with path')
|
||||||
|
args = parser.parse_args()
|
||||||
|
data=read_data(args.fname)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
d=main()
|
||||||
|
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
# %pylab makes the following imports::
|
||||||
|
#
|
||||||
|
#import numpy
|
||||||
|
#import matplotlib
|
||||||
|
#from matplotlib import pylab, mlab, pyplot
|
||||||
|
#np = numpy
|
||||||
|
#plt = pyplot
|
||||||
|
#
|
||||||
|
#from IPython.display import display
|
||||||
|
#from IPython.core.pylabtools import figsize, getfigs
|
||||||
|
#
|
||||||
|
#from pylab import *
|
||||||
|
#from numpy import *
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from matplotlib.dates import date2num, DateFormatter
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as mplT
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
# GLOBAL start value sv:
|
||||||
|
sv=0
|
||||||
|
|
||||||
|
|
||||||
|
def get_df(datafile):
|
||||||
|
global sv
|
||||||
|
df=pd.read_csv(datafile, names=['TIME','ALTI','AIRSP','AOA','PITCH','ROLL','YAW'])
|
||||||
|
|
||||||
|
# convert time data to datetime format
|
||||||
|
df['TIME']=pd.to_datetime(df['TIME'], format='%H:%M:%S')
|
||||||
|
|
||||||
|
sv=1
|
||||||
|
# ignore data before clock is set from EFIS
|
||||||
|
# this IS the EFIS
|
||||||
|
'''
|
||||||
|
for i in range(1,len(df)):
|
||||||
|
if ((df['TIME'][i]-df['TIME'][i-1]).value > 1000000000):
|
||||||
|
sv=i
|
||||||
|
print("start %d" %(sv))
|
||||||
|
break
|
||||||
|
'''
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_elapsed(df):
|
||||||
|
st=df['TIME'][sv] # start time
|
||||||
|
et=[] # elapsed time
|
||||||
|
|
||||||
|
# add elapsed time column
|
||||||
|
for i in range(0,len(df)):
|
||||||
|
et.append(df['TIME'][i]-st)
|
||||||
|
df2=pd.DataFrame(et)
|
||||||
|
df2.columns=['ELAPSED']
|
||||||
|
#s=pd.Series([val.time() for val in df['TIME']])
|
||||||
|
#df2.merge(s.to_frame(), left_index=True, right_index=True)
|
||||||
|
ndf=df.join(df2)
|
||||||
|
|
||||||
|
# make flight duration (elapsed time) the index
|
||||||
|
#ndf.index=ndf['ELAPSED']
|
||||||
|
#del ndf['ELAPSED'] # delete the column
|
||||||
|
ndf = ndf.set_index('ELAPSED')
|
||||||
|
#ndf = ndf.set_index('TIME')
|
||||||
|
#ndf.drop(['TIME'], axis=1, inplace=True)
|
||||||
|
|
||||||
|
return ndf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def log_number(date):
|
||||||
|
"""get number of logs on date and return size + name"""
|
||||||
|
result=[]
|
||||||
|
rv=subprocess.check_output("python "+"flight_index.py "+date, shell=True)
|
||||||
|
rvl=rv.decode('utf-8').split('\n')
|
||||||
|
for i in range(0,len(rvl)-1):
|
||||||
|
result.append(rvl[i].lstrip(" ").split(" "))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check_newday(df):
|
||||||
|
"""returns boolean and the index of the last time before 00:00:00"""
|
||||||
|
newday=False
|
||||||
|
idx=0
|
||||||
|
# quick check if we need to search for the idx
|
||||||
|
r=df['TIME'][sv]-df['TIME'][len(df)-1]
|
||||||
|
if (r.days == -1):
|
||||||
|
return newday,0
|
||||||
|
# skip ['TIME'][0] since includes index name...
|
||||||
|
for i in range(1,len(df)-1):
|
||||||
|
td=date2num(df['TIME'][i+1])-date2num(df['TIME'][i])
|
||||||
|
if td < 0:
|
||||||
|
print("day wrap @ ", end=' ')
|
||||||
|
print(i)
|
||||||
|
idx=i
|
||||||
|
newday=True
|
||||||
|
return newday,idx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def fix_newday(df,idx):
|
||||||
|
# fix new day in-line so we don't parameterize or globalize the df
|
||||||
|
t1=df['TIME'][:idx+1]
|
||||||
|
t2=df['TIME'][idx+1:]
|
||||||
|
t2a=pd.DataFrame([x+datetime.timedelta(days=1) for x in t2])
|
||||||
|
t2as=t2a.iloc[:,0] # get series
|
||||||
|
t2as.name='TIME'
|
||||||
|
t2as.index=t2.index
|
||||||
|
tn=t1.append(t2as)
|
||||||
|
df.loc[:,'TIME']=tn
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def flighttime(df):
|
||||||
|
print("flight time = ", ( df['TIME'][len(df)-1] - df['TIME'][sv]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def x_format(df):
|
||||||
|
"""sets x axis time format based on flight time"""
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
formatter=mplT.FuncFormatter(lambda s, x: time.strftime('%H:%M:%S', time.gmtime(s)))
|
||||||
|
else:
|
||||||
|
formatter=mplT.FuncFormatter(lambda s, x: time.strftime('%M:%S', time.gmtime(s)))
|
||||||
|
return formatter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
##################################################################################
|
||||||
|
###
|
||||||
|
### Useful plots...
|
||||||
|
###
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_ALTSPD(df):
|
||||||
|
fig,axes = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
df.plot(y='ALTI', ax=axes[0])
|
||||||
|
df.plot(y='AIRSP', ax=axes[1])
|
||||||
|
ax=plt.gca()
|
||||||
|
tick_labels=ax.xaxis.major.formatter.seq
|
||||||
|
ax.xaxis.major.formatter.seq = [label.split()[-1] if label else "" for label in tick_labels]
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
|
||||||
|
|
||||||
|
def plot_ALTI(df):
|
||||||
|
# RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
#df.plot(ax=ax, y="RPM", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.plot(t,df['ALTI'][sv:],'-',label="ALTI")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('Feet')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_AIRSP(df):
|
||||||
|
# RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
#df.plot(ax=ax, y="RPM", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.plot(t,df['AIRSP'][sv:],'-',label="AIRSP")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('Kts')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_ROLL(df):
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
|
||||||
|
ax.plot(t,df['ROLL'][sv:],'-',label="ROLL")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('Degree')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_AOA(df):
|
||||||
|
# RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
#df.plot(ax=ax, y="RPM", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.plot(t,df['AOA'][sv:],'-',label="AOA")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('Deg')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
|
||||||
|
|
||||||
|
def plot_PITCH(df):
|
||||||
|
# RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
#df.plot(ax=ax, y="RPM", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.plot(t,df['PITCH'][sv:],'-',label="PITCH")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('Deg')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
|
||||||
Executable
+146
@@ -0,0 +1,146 @@
|
|||||||
|
"""
|
||||||
|
This program converts an EMS file to csv
|
||||||
|
|
||||||
|
index, width, description, comment
|
||||||
|
|
||||||
|
0, 2, Hour, 00 to 23, zulu hour
|
||||||
|
2, 2, Minute, 00 to 59, zulu minutes
|
||||||
|
4, 2, Second, 00 to 59, zulu seconds
|
||||||
|
6, 2, Fractions, 00 to 63, counter for 1/64 second. Data output frequency.
|
||||||
|
8, 4, manifold pressure, inHg * 100
|
||||||
|
12, 3, oil temp, deg F
|
||||||
|
15, 3, oil pressure, psi
|
||||||
|
18, 3, fuel pressure, psi * 10
|
||||||
|
21, 3, voltage, volts * 10
|
||||||
|
24, 3, current, amps
|
||||||
|
27, 3, rpm, rpm/10
|
||||||
|
30, 3, fuel flow, gph * 10
|
||||||
|
33, 4, fuel remaining, gallons * 10
|
||||||
|
37, 3, fuel left tank, gallons * 10
|
||||||
|
40, 3, fuel right tank, gallons * 10
|
||||||
|
43, 8, GP-1
|
||||||
|
51, 8, GP-2
|
||||||
|
59, 8, GP-3
|
||||||
|
67, 4, GP thremocouple
|
||||||
|
71, 4, EGT_1
|
||||||
|
75, 4, EGT_2
|
||||||
|
79, 4, EGT_3
|
||||||
|
83, 4, EGT_4
|
||||||
|
87, 4, EGT_5
|
||||||
|
91, 4, EGT_6
|
||||||
|
95, 3, CHT_1
|
||||||
|
98, 3, CHT_2
|
||||||
|
101, 3, CHT_3
|
||||||
|
104, 3, CHT_4
|
||||||
|
107, 3, CHT_5
|
||||||
|
110, 3, CHT_6
|
||||||
|
113, 1, contact-1
|
||||||
|
114, 1, contact-2
|
||||||
|
115, 2, Product ID, Ascii-hex Dynon product ID: 01=EFIS-D10A, 10=EFIS-D10, 03=EMS-D10
|
||||||
|
117, 2, Checksum, The ascii-hex 2 byte sum of all 49 preceding bytes
|
||||||
|
119, 2, CR/LF, Carriage Return, Linefeed = 0x0D, 0x0A
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
|
||||||
|
"""
|
||||||
|
open file and read a byte at a time into a buffer
|
||||||
|
when two headers have been found, process bytes inbetween
|
||||||
|
then copy second header into the beginning of a new buffer and throw away old buffer
|
||||||
|
lines are only valid if surrounded by headers, otherwise they may be incomplete
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def emstime(buf):
|
||||||
|
hrs=int(buf[0:2])
|
||||||
|
min=int(buf[2:4])
|
||||||
|
sec=int(buf[4:6])
|
||||||
|
return(hrs,min,sec)
|
||||||
|
|
||||||
|
def manp(buf):
|
||||||
|
return(int(buf[8:12])/100.0)
|
||||||
|
|
||||||
|
def oilt(buf):
|
||||||
|
return(int(buf[12:15]))
|
||||||
|
|
||||||
|
def oilp(buf):
|
||||||
|
return(int(buf[15:18]))
|
||||||
|
|
||||||
|
def fuelp(buf):
|
||||||
|
return(int(buf[18:21])/10.0)
|
||||||
|
|
||||||
|
def volts(buf):
|
||||||
|
return(int(buf[21:24])/10.0)
|
||||||
|
|
||||||
|
def amps(buf):
|
||||||
|
return(int(buf[24:27]))
|
||||||
|
|
||||||
|
def rpm(buf):
|
||||||
|
return(int(buf[27:30])*10.0)
|
||||||
|
|
||||||
|
def fflow(buf):
|
||||||
|
return(int(buf[30:33])/10.0)
|
||||||
|
|
||||||
|
def frem(buf):
|
||||||
|
return(int(buf[33:37])/10.0)
|
||||||
|
|
||||||
|
def ful(buf):
|
||||||
|
return(int(buf[37:40])/10.0)
|
||||||
|
|
||||||
|
def fur(buf):
|
||||||
|
return(int(buf[40:43])/10.0)
|
||||||
|
|
||||||
|
def egt(buf):
|
||||||
|
e1=int(buf[71:75])
|
||||||
|
e2=int(buf[75:79])
|
||||||
|
e3=int(buf[79:83])
|
||||||
|
e4=int(buf[83:87])
|
||||||
|
return(e1,e2,e3,e4)
|
||||||
|
|
||||||
|
def cht(buf):
|
||||||
|
c1=int(buf[95:98])
|
||||||
|
c2=int(buf[98:101])
|
||||||
|
c3=int(buf[101:104])
|
||||||
|
c4=int(buf[104:107])
|
||||||
|
return(c1,c2,c3,c4)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def output_values(h,m,s,manp,oilt,oilp,fuelp,volts,amps,rpm,fflow,frem,ful,fur,egt1,egt2,egt3,egt4,cht1,cht2,cht3,cht4):
|
||||||
|
print(("%02d:%02d:%02d, " # h,m,s
|
||||||
|
"%4.2f, %d, %d, %3.1f, %3.1f, %d, " # manp,oilt,oilp,fuelp,volts,amps
|
||||||
|
"%d, %3.1f, %3.1f, %3.1f, %3.1f, " # rpm,fflow,frem,ful,fur
|
||||||
|
"%d, %d, %d, %d, " # egt[1..4]
|
||||||
|
"%d, %d, %d, %d") % (h,m,s,manp,oilt,oilp,fuelp,volts,amps,rpm,fflow,frem,ful,fur,egt1,egt2,egt3,egt4,cht1,cht2,cht3,cht4))
|
||||||
|
|
||||||
|
|
||||||
|
def read_data(name):
|
||||||
|
with open(name, "r") as f:
|
||||||
|
buf1=[] # start with buffer clear
|
||||||
|
l1=f.readline()
|
||||||
|
while l1 != "": # not EOF
|
||||||
|
#print(len(l1))
|
||||||
|
#print(l1)
|
||||||
|
if (len(l1)==120): # was 121 with openlog
|
||||||
|
b=l1
|
||||||
|
output_values(emstime(b)[0],emstime(b)[1],emstime(b)[2],manp(b),oilt(b),oilp(b),fuelp(b),volts(b),amps(b),rpm(b),fflow(b),frem(b),ful(b),fur(b),egt(b)[0],egt(b)[1],egt(b)[2],egt(b)[3],cht(b)[0],cht(b)[1],cht(b)[2],cht(b)[3])
|
||||||
|
l1=f.readline()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='EMS csv converter',
|
||||||
|
epilog="./%(prog)s [options] > outputfile.csv to save the result")
|
||||||
|
parser.add_argument('fname',
|
||||||
|
help='file name to convert with path')
|
||||||
|
args = parser.parse_args()
|
||||||
|
data=read_data(args.fname)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
d=main()
|
||||||
Executable
+454
@@ -0,0 +1,454 @@
|
|||||||
|
# %pylab makes the following imports::
|
||||||
|
#
|
||||||
|
#import numpy
|
||||||
|
#import matplotlib
|
||||||
|
#from matplotlib import pylab, mlab, pyplot
|
||||||
|
#np = numpy
|
||||||
|
#plt = pyplot
|
||||||
|
#
|
||||||
|
#from IPython.display import display
|
||||||
|
#from IPython.core.pylabtools import figsize, getfigs
|
||||||
|
#
|
||||||
|
#from pylab import *
|
||||||
|
#from numpy import *
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from matplotlib.dates import date2num, DateFormatter
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.ticker as mplT
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# GLOBAL SAVEPLOTS
|
||||||
|
SAVEPLOTS = False
|
||||||
|
SAVEPATH = "."
|
||||||
|
|
||||||
|
# GLOBAL start value sv:
|
||||||
|
sv=0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_df(datafile):
|
||||||
|
"""read csv datafile; return dataframe"""
|
||||||
|
|
||||||
|
global sv
|
||||||
|
|
||||||
|
df=pd.read_csv(datafile, comment="#", names=['TIME','MP','OILT','OILP', 'FUELP','VBAT','IBAT','RPM','FFLOW','Frem','FL','FR','EGT1','EGT2','EGT3','EGT4','CHT1','CHT2','CHT3','CHT4'])
|
||||||
|
|
||||||
|
# convert time data to datetime format
|
||||||
|
df['TIME']=pd.to_datetime(df['TIME'], format='%H:%M:%S')
|
||||||
|
|
||||||
|
sv=1
|
||||||
|
# ignore data before clock is set from EFIS
|
||||||
|
# set GLOBAL sv
|
||||||
|
for i in range(1,len(df)):
|
||||||
|
if ((df['TIME'][i]-df['TIME'][i-1]).value > 1000000000):
|
||||||
|
sv=i
|
||||||
|
print("start %d" %(sv))
|
||||||
|
break
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_elapsed(df):
|
||||||
|
st=df['TIME'][sv] # start time
|
||||||
|
et=[] # elapsed time
|
||||||
|
|
||||||
|
# add elapsed time column
|
||||||
|
for i in range(0,len(df)):
|
||||||
|
et.append(df['TIME'][i]-st)
|
||||||
|
df2=pd.DataFrame(et)
|
||||||
|
df2.columns=['ELAPSED']
|
||||||
|
#s=pd.Series([val.time() for val in df['TIME']])
|
||||||
|
#df2.merge(s.to_frame(), left_index=True, right_index=True)
|
||||||
|
ndf=df.join(df2)
|
||||||
|
|
||||||
|
# make flight duration (elapsed time) the index
|
||||||
|
#ndf.index=ndf['ELAPSED']
|
||||||
|
#del ndf['ELAPSED'] # delete the column
|
||||||
|
ndf = ndf.set_index('ELAPSED')
|
||||||
|
#ndf = ndf.set_index('TIME')
|
||||||
|
#ndf.drop(['TIME'], axis=1, inplace=True)
|
||||||
|
|
||||||
|
return ndf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def log_number(date):
|
||||||
|
"""get number of logs on date and return size + name"""
|
||||||
|
result=[]
|
||||||
|
rv=subprocess.check_output("python "+"flight_index.py "+date, shell=True)
|
||||||
|
rvl=rv.split('\n')
|
||||||
|
for i in range(0,len(rvl)-1):
|
||||||
|
result.append(rvl[i].lstrip(" ").split(" "))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check_newday(df):
|
||||||
|
"""returns boolean and the index of the last time before 00:00:00"""
|
||||||
|
newday=False
|
||||||
|
idx=0
|
||||||
|
# quick check if we need to search for the idx
|
||||||
|
r=df['TIME'][sv]-df['TIME'][len(df)-1]
|
||||||
|
if (r.days == -1):
|
||||||
|
return newday,0
|
||||||
|
# skip ['TIME'][0] since includes index name...
|
||||||
|
for i in range(1,len(df)-1):
|
||||||
|
td=date2num(df['TIME'][i+1])-date2num(df['TIME'][i])
|
||||||
|
if td < 0:
|
||||||
|
print("day wrap @ ", end=' ')
|
||||||
|
print(i)
|
||||||
|
idx=i
|
||||||
|
newday=True
|
||||||
|
return newday,idx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def fix_newday(df,idx):
|
||||||
|
# fix new day in-line so we don't parameterize or globalize the df
|
||||||
|
t1=df['TIME'][:idx+1]
|
||||||
|
t2=df['TIME'][idx+1:]
|
||||||
|
t2a=pd.DataFrame([x+datetime.timedelta(days=1) for x in t2])
|
||||||
|
t2as=t2a.iloc[:,0] # get series
|
||||||
|
t2as.name='TIME'
|
||||||
|
t2as.index=t2.index
|
||||||
|
tn=t1.append(t2as)
|
||||||
|
df.loc[:,'TIME']=tn
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def flighttime(df):
|
||||||
|
"""returns flight time of current dataframe"""
|
||||||
|
#print "flight time = ", ( df['TIME'][len(df)-1] - df['TIME'][sv])
|
||||||
|
# use elapsed time to avoid day change
|
||||||
|
print("flight time = ", ( df.index[len(df)-1] - df.index[sv]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def x_format(df):
|
||||||
|
"""sets x axis time format based on flight time"""
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
formatter=mplT.FuncFormatter(lambda s, x: time.strftime('%H:%M:%S', time.gmtime(s)))
|
||||||
|
else:
|
||||||
|
formatter=mplT.FuncFormatter(lambda s, x: time.strftime('%M:%S', time.gmtime(s)))
|
||||||
|
return formatter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
##################################################################################
|
||||||
|
###
|
||||||
|
### Useful plots...
|
||||||
|
###
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def plot_all_df(df):
|
||||||
|
df[sv:].plot(rot=30)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_EGT(df):
|
||||||
|
# Zulu time
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
ax.xaxis_date()
|
||||||
|
ax.xaxis.set_major_formatter(DateFormatter('%H:%M'))
|
||||||
|
x=df['TIME'][sv:]
|
||||||
|
|
||||||
|
t=list(map(date2num, x))
|
||||||
|
|
||||||
|
y1=df['EGT1'][sv:]
|
||||||
|
y2=df['EGT2'][sv:]
|
||||||
|
y3=df['EGT3'][sv:]
|
||||||
|
y4=df['EGT4'][sv:]
|
||||||
|
|
||||||
|
ax.plot_date(t,y1,'-',label="EGT1")
|
||||||
|
ax.plot_date(t,y2,'-',label="EGT2")
|
||||||
|
ax.plot_date(t,y3,'-',label="EGT3")
|
||||||
|
ax.plot_date(t,y4,'-',label="EGT4")
|
||||||
|
|
||||||
|
plt.legend(loc='lower center')
|
||||||
|
plt.xlabel("Time")
|
||||||
|
plt.ylabel("Temp (F)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_EGT.png")
|
||||||
|
|
||||||
|
|
||||||
|
def plot_EGTdt(df):
|
||||||
|
# Elapsed time
|
||||||
|
# index set to 'ELAPSED'
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
|
||||||
|
y1=df['EGT1'][sv:]
|
||||||
|
y2=df['EGT2'][sv:]
|
||||||
|
y3=df['EGT3'][sv:]
|
||||||
|
y4=df['EGT4'][sv:]
|
||||||
|
|
||||||
|
ax.plot(t,y1,'-',label="EGT1")
|
||||||
|
ax.plot(t,y2,'-',label="EGT2")
|
||||||
|
ax.plot(t,y3,'-',label="EGT3")
|
||||||
|
ax.plot(t,y4,'-',label="EGT4")
|
||||||
|
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
plt.legend(loc='lower center')
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elapsed Time (MM:SS)")
|
||||||
|
plt.ylabel("Temp (F)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_EGTe.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_CHT(df):
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
ax.xaxis_date()
|
||||||
|
ax.xaxis.set_major_formatter(DateFormatter('%H:%M'))
|
||||||
|
x=df['TIME'][sv:]
|
||||||
|
t=list(map(date2num, x))
|
||||||
|
|
||||||
|
y1=df['CHT1'][sv:]
|
||||||
|
y2=df['CHT2'][sv:]
|
||||||
|
y3=df['CHT3'][sv:]
|
||||||
|
y4=df['CHT4'][sv:]
|
||||||
|
|
||||||
|
ax.plot(t,y1,'-',label="CHT1")
|
||||||
|
ax.plot(t,y2,'-',label="CHT2")
|
||||||
|
ax.plot(t,y3,'-',label="CHT3")
|
||||||
|
ax.plot(t,y4,'-',label="CHT4")
|
||||||
|
|
||||||
|
plt.legend(loc='lower center')
|
||||||
|
plt.xlabel("Time")
|
||||||
|
plt.ylabel("Temp (F)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_CHT.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_CHTdt(df):
|
||||||
|
# Elapsed time
|
||||||
|
# index set to 'ELAPSED'
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
|
||||||
|
y1=df['CHT1'][sv:]
|
||||||
|
y2=df['CHT2'][sv:]
|
||||||
|
y3=df['CHT3'][sv:]
|
||||||
|
y4=df['CHT4'][sv:]
|
||||||
|
|
||||||
|
ax.plot(t,y1,'-',label="CHT1")
|
||||||
|
ax.plot(t,y2,'-',label="CHT2")
|
||||||
|
ax.plot(t,y3,'-',label="CHT3")
|
||||||
|
ax.plot(t,y4,'-',label="CHT4")
|
||||||
|
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
plt.legend(loc='lower center')
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elapsed Time (MM:SS)")
|
||||||
|
plt.ylabel("Temp (F)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_CHTe.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_OIL(df):
|
||||||
|
fig,axs = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
df.plot(y='RPM', xlim=(sv+50,len(df)), ax=axs[0])
|
||||||
|
df.plot(y='OILP', xlim=(sv+50,len(df)), ax=axs[1])
|
||||||
|
plt.ylabel("PSI")
|
||||||
|
ax=plt.gca()
|
||||||
|
tick_labels=ax.xaxis.major.formatter.seq
|
||||||
|
ax.xaxis.major.formatter.seq = [label.split()[-1] if label else "" for label in tick_labels]
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
plt.xlabel("Time (MM:SS)")
|
||||||
|
axs[0].set_title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_OIL.png")
|
||||||
|
|
||||||
|
"""
|
||||||
|
def plot_BAT(df):
|
||||||
|
# VBAT, IBAT
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
ax.xaxis_date()
|
||||||
|
ax.xaxis.set_major_formatter(DateFormatter('%H:%M'))
|
||||||
|
x=df['TIME'][sv:]
|
||||||
|
t=list(map(date2num, x))
|
||||||
|
|
||||||
|
df.plot(ax=ax, y="VBAT", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.set_ylabel('Volts')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax2=ax.twinx()
|
||||||
|
df.plot(ax=ax2, y="IBAT", xlim=(sv+50,len(df)), color='g')
|
||||||
|
ax2.set_ylabel("Amps")
|
||||||
|
ax2.legend(loc='lower right')
|
||||||
|
ax=plt.gca()
|
||||||
|
#tick_labels=ax.xaxis.major.formatter.seq
|
||||||
|
#ax.xaxis.major.formatter.seq = [label.split()[-1] if label else "" for label in tick_labels]
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
plt.xlabel("Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_BAT.png")
|
||||||
|
"""
|
||||||
|
|
||||||
|
def plot_BAT(df):
|
||||||
|
# VBAT, IBAT
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
|
||||||
|
fig,axs = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
#axs[1].xaxis_date()
|
||||||
|
axs[1].xaxis.set_major_formatter(DateFormatter('%H:%M'))
|
||||||
|
df.plot(ax=axs[0],y='VBAT', xlim=(sv,len(df)))
|
||||||
|
axs[0].set_ylabel("Volts")
|
||||||
|
axs[0].set_ylim(10.0,14.0)
|
||||||
|
axs[0].grid()
|
||||||
|
#axs[0].legend(loc='lower center')
|
||||||
|
#
|
||||||
|
df.plot(ax=axs[1],y='IBAT', xlim=(sv,len(df)))
|
||||||
|
axs[1].set_ylabel("Amps")
|
||||||
|
axs[1].set_ylim(-25.0,25)
|
||||||
|
axs[1].grid()
|
||||||
|
#
|
||||||
|
ax=plt.gca()
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elapsed Time (MM:SS)")
|
||||||
|
axs[0].set_title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_VI.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_FUEL(df):
|
||||||
|
# FL, FR
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
|
||||||
|
fig,axs = plt.subplots(nrows=2, ncols=1, sharex=True)
|
||||||
|
#axs[1].xaxis_date()
|
||||||
|
axs[1].xaxis.set_major_formatter(DateFormatter('%H:%M'))
|
||||||
|
axs[0].plot(t,df['FL'][sv:],'-',label="FuelLeft")
|
||||||
|
axs[1].plot(t,df['FR'][sv:],'-',label="FuelRight")
|
||||||
|
axs[0].set_ylim(0,18)
|
||||||
|
axs[1].set_ylim(0,18)
|
||||||
|
axs[0].set_ylabel("Gal")
|
||||||
|
axs[1].set_ylabel("Gal")
|
||||||
|
axs[0].legend(loc='lower center')
|
||||||
|
axs[1].legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elapsed Time (MM:SS)")
|
||||||
|
axs[0].set_title(FLIGHTDATE)
|
||||||
|
axs[0].grid()
|
||||||
|
axs[1].grid()
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_FuelLR.png")
|
||||||
|
|
||||||
|
# FFLOW, Frem
|
||||||
|
# see https://matplotlib.org/2.0.2/examples/color/named_colors.html
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
ax.plot(t,df["Frem"][sv:],'-',label="Frem", color='b')
|
||||||
|
ax.set_ylabel('Gal')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
|
||||||
|
ax2=ax.twinx()
|
||||||
|
ax2.plot(t,df["FFLOW"][sv:],'-',label="FFLOW", color='g')
|
||||||
|
ax2.set_ylabel("GPH")
|
||||||
|
ax2.legend(loc='lower right')
|
||||||
|
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
ax2.xaxis.set_major_formatter(x_format(df))
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
ax.set_xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
ax2.set_xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
ax.set_xlabel("Elapsed Time (MM:SS)")
|
||||||
|
ax2.set_xlabel("Elapsed Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
ax.grid(axis='y',color='lightblue')
|
||||||
|
ax2.grid(axis='y',color='lightgreen')
|
||||||
|
ax.grid(axis='x')
|
||||||
|
ax2.grid(axis='x')
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_Fuel.png")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_PWR(df):
|
||||||
|
# MP, RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
df.plot(ax=ax, y="MP", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.set_ylabel('PSI')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax2=ax.twinx()
|
||||||
|
df.plot(ax=ax2, y="RPM", xlim=(sv+50,len(df)), color='g')
|
||||||
|
ax2.set_ylabel("rpm")
|
||||||
|
ax2.legend(loc='lower right')
|
||||||
|
ax=plt.gca()
|
||||||
|
tick_labels=ax.xaxis.major.formatter.seq
|
||||||
|
ax.xaxis.major.formatter.seq = [label.split()[-1] if label else "" for label in tick_labels]
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
plt.xlabel("Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_PWR.png")
|
||||||
|
|
||||||
|
|
||||||
|
def plot_RPM(df):
|
||||||
|
# RPM
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
t=df.index.seconds[sv:]
|
||||||
|
#df.plot(ax=ax, y="RPM", xlim=(sv+50,len(df)), color='b')
|
||||||
|
ax.plot(t,df['RPM'][sv:],'-',label="RPM")
|
||||||
|
ax.xaxis.set_major_formatter(x_format(df))
|
||||||
|
|
||||||
|
ax.set_ylabel('RPM')
|
||||||
|
ax.legend(loc='lower center')
|
||||||
|
ax=plt.gca()
|
||||||
|
plt.xticks(rotation=30)
|
||||||
|
if df.index[-1] > pd.Timedelta("01:00:00"):
|
||||||
|
plt.xlabel("Elapsed Time (HH:MM:SS)")
|
||||||
|
else:
|
||||||
|
plt.xlabel("Elasped Time (MM:SS)")
|
||||||
|
plt.title(FLIGHTDATE)
|
||||||
|
if SAVEPLOTS: savefig(SAVEPATH+FLIGHTDATE+"/"+FLIGHTDATE+"_PWR.png")
|
||||||
|
|
||||||
|
|
||||||
|
def plot_ALL(df):
|
||||||
|
plot_PWR(df)
|
||||||
|
plot_FUEL(df)
|
||||||
|
plot_OIL(df)
|
||||||
|
plot_BAT(df)
|
||||||
|
plot_CHT(df)
|
||||||
|
plot_EGT(df)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# $1 is .csv input $2 is .kml output
|
||||||
|
gpsbabel -t -i unicsv -f "$1" -x transform,trk=wpt -o kml,floating=1 -F "$2"
|
||||||
|
#echo "$1"
|
||||||
|
#echo "$2"
|
||||||
|
|
||||||
Executable
+183
@@ -0,0 +1,183 @@
|
|||||||
|
# IPython log file
|
||||||
|
"""
|
||||||
|
This program converts a Garmin aviation GPS log to csv
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
FIXME:
|
||||||
|
need to handle FlightPlan data. see 30oct2017 LOG005N_G.TXT
|
||||||
|
search KBFL
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
"""
|
||||||
|
start with simple lat/lon & altitude
|
||||||
|
|
||||||
|
STX (0x02 ^B)
|
||||||
|
type-1 sentence
|
||||||
|
type-2 sentence(s)
|
||||||
|
ETX (0x03 ^C)
|
||||||
|
|
||||||
|
type-1
|
||||||
|
------
|
||||||
|
|
||||||
|
id-char (alphabetic)
|
||||||
|
dd..dd data 1-10 chars
|
||||||
|
CR
|
||||||
|
LF
|
||||||
|
|
||||||
|
id=z
|
||||||
|
aaaaa altitude in feet
|
||||||
|
xcsv format ALT_FEET
|
||||||
|
|
||||||
|
id=A
|
||||||
|
s dd mmhh latitude: s{N,S} deg min hundredths of min
|
||||||
|
min to decimal = mmhh/60
|
||||||
|
xcsv format: N=+,S=- deg.min
|
||||||
|
xcsv format LAT_DIRDECIMAL
|
||||||
|
|
||||||
|
id=B
|
||||||
|
s ddd mmhh longitude: s{E,W} deg min hundredths of min
|
||||||
|
min to decimal = mmhh/60
|
||||||
|
xcsv format: E=+,W=- deg.min
|
||||||
|
xcsv format LON_DIRDECIMAL
|
||||||
|
|
||||||
|
id=C
|
||||||
|
ddd track in degrees
|
||||||
|
|
||||||
|
id=D
|
||||||
|
sss ground speed in knots
|
||||||
|
xcsv format PATH_SPEED_KNOTS
|
||||||
|
unicsv format in m/s
|
||||||
|
1mps = 1.94384617178935 knot
|
||||||
|
1knot = 0.5144440mps
|
||||||
|
|
||||||
|
|
||||||
|
type-2
|
||||||
|
------
|
||||||
|
|
||||||
|
id 3 chars: w nn nn{01..31}
|
||||||
|
seq
|
||||||
|
wpt
|
||||||
|
lat
|
||||||
|
lon
|
||||||
|
mvar
|
||||||
|
CR
|
||||||
|
LF
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
drop chars until first ETX
|
||||||
|
keep chars STX until ETX
|
||||||
|
trim STX and ETX
|
||||||
|
read lines searching for id
|
||||||
|
|
||||||
|
example:
|
||||||
|
z-0000
|
||||||
|
AN 37 3053
|
||||||
|
BW 122 1492
|
||||||
|
C346
|
||||||
|
D000
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def openfile(fname):
|
||||||
|
f=open(fname, "r")
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def format_data(buf):
|
||||||
|
"""process 1 record"""
|
||||||
|
s=''.join(buf)
|
||||||
|
ss=s.replace('\r','').split("\n")
|
||||||
|
# don't process when A- B- = missing lat/lon
|
||||||
|
if s.find("A-") > 0 or s.find("B-") > 0: return
|
||||||
|
for i in range(0,len(ss)):
|
||||||
|
if ss[i][0]=='z':
|
||||||
|
#print ss[i][1:]+", ",
|
||||||
|
s2=ss[i][1:]
|
||||||
|
try:
|
||||||
|
int(s2)
|
||||||
|
isint=True
|
||||||
|
except ValueError:
|
||||||
|
isint=False
|
||||||
|
if isint == True: print(s2+", ", end=' ')
|
||||||
|
if ss[i][0]=='A':
|
||||||
|
s1=ss[i][1:].split()
|
||||||
|
if s1[0]=='N': sign=1
|
||||||
|
else: sign=-1
|
||||||
|
try:
|
||||||
|
s2=sign*(int(s1[1])+(int(s1[2])/100.0)/60.0)
|
||||||
|
print("%0.5f"%(s2)+", ", end=' ')
|
||||||
|
except:
|
||||||
|
#print "ERROR!!"
|
||||||
|
#print s1
|
||||||
|
pass
|
||||||
|
if ss[i][0]=='B':
|
||||||
|
s1=ss[i][1:].split()
|
||||||
|
if s1[0]=='E': sign=1
|
||||||
|
else: sign=-1
|
||||||
|
try:
|
||||||
|
s2=sign*(int(s1[1])+(int(s1[2])/100.0)/60.0)
|
||||||
|
print("%0.5f"%(s2)+", ", end=' ')
|
||||||
|
except:
|
||||||
|
#print "ERROR!!"
|
||||||
|
#print s1
|
||||||
|
pass
|
||||||
|
if ss[i][0]=='D':
|
||||||
|
try:
|
||||||
|
s1=int(ss[i][1:])*0.5144440
|
||||||
|
print("%0.2f"%(s1)+", ", end=' ')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def read_data(f):
|
||||||
|
"""read gps records"""
|
||||||
|
rec_num=0
|
||||||
|
# search for begin record in GPS.TXT using vim with :/^v^b
|
||||||
|
# skip to the end of record
|
||||||
|
# in case we started logging in the middle of a record
|
||||||
|
byte=f.read(1)
|
||||||
|
if byte == '' : return
|
||||||
|
while (ord(byte) != 3): # ETX (0x03 ^C)
|
||||||
|
byte=f.read(1)
|
||||||
|
if byte == '' : return
|
||||||
|
# now process records until the end of file
|
||||||
|
byte=f.read(1)
|
||||||
|
while byte != '':
|
||||||
|
buf1=[] # start with buffer clear
|
||||||
|
while ord(byte) != 3: # ETX (0x03 ^C)
|
||||||
|
#print "%02X " % ord(byte),
|
||||||
|
byte = f.read(1)
|
||||||
|
if byte == '': break
|
||||||
|
buf1.append(byte)
|
||||||
|
else: # ETX, so process this record
|
||||||
|
rec_num+=1
|
||||||
|
byte = f.read(1)
|
||||||
|
#print buf1
|
||||||
|
format_data(buf1)
|
||||||
|
print(" ") # essentially new line for the record
|
||||||
|
#print rec_num
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Garmin Aviaiton GPS format converter')
|
||||||
|
parser.add_argument('file',
|
||||||
|
help='name of file to convert')
|
||||||
|
args = parser.parse_args()
|
||||||
|
fh=openfile(args.file)
|
||||||
|
#print "ALT_FEET, LAT_DIRDECIMAL, LON_DIRDECIMAL, PATH_SPEED_KNOTS"
|
||||||
|
print("altfeet, lat, lon, speed")
|
||||||
|
data=read_data(fh)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# IPython log file
|
||||||
|
"""
|
||||||
|
This program splits a combo log into separate log files
|
||||||
|
The combo log has a header on each sentence.
|
||||||
|
E: for EMS
|
||||||
|
F: for EFIS
|
||||||
|
G: for GPS
|
||||||
|
|
||||||
|
There appears to be a bug with the MBed GPS logger where the end of record
|
||||||
|
^C is dropped.
|
||||||
|
|
||||||
|
The MBed logger also uses \r as line end
|
||||||
|
use
|
||||||
|
LC_CTYPE=C tr -s '\r' '\n' < Log001n.txt > tmp
|
||||||
|
so we can process with readline()
|
||||||
|
EFIS and EMS have \r line ends
|
||||||
|
GPS has \r\n line ends
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def process_data(fname):
|
||||||
|
EOF=False
|
||||||
|
f=open(fname, encoding='utf-8', errors='ignore')
|
||||||
|
fname=os.path.splitext(fname)[0]
|
||||||
|
#fe=open(fname+"_F.txt", "w") # E <-> F label reversed in MBED!! or miswired @ MBED!!
|
||||||
|
#ff=open(fname+"_E.txt", "w")
|
||||||
|
fe=open(fname+"_E.txt", "w") # Teensy
|
||||||
|
ff=open(fname+"_F.txt", "w")
|
||||||
|
fg=open(fname+"_G.txt", "w")
|
||||||
|
while not EOF:
|
||||||
|
s=f.readline()
|
||||||
|
if s=="":
|
||||||
|
EOF=True
|
||||||
|
break
|
||||||
|
if s[:2] == "G:":
|
||||||
|
"""multiple lines... """
|
||||||
|
fg.write(s[2:])
|
||||||
|
while not EOF:
|
||||||
|
s=f.readline()
|
||||||
|
if s=="":
|
||||||
|
EOF=True
|
||||||
|
break
|
||||||
|
if (s[:2] != "E:") and (s[:2] != "F:"):
|
||||||
|
fg.write(s)
|
||||||
|
else:
|
||||||
|
fg.write(chr(3))
|
||||||
|
break # done with GPS record
|
||||||
|
if s[:2] == "E:": fe.write(s[2:])
|
||||||
|
if s[:2] == "F:": ff.write(s[2:])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Log Splitter: creates separate log files for each device')
|
||||||
|
parser.add_argument('file',
|
||||||
|
help='name of file to convert')
|
||||||
|
args = parser.parse_args()
|
||||||
|
process_data(args.file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Executable
+87
@@ -0,0 +1,87 @@
|
|||||||
|
"""
|
||||||
|
run from Airplane_Data_logger/programs/
|
||||||
|
|
||||||
|
processes all LOG0*.TXT files
|
||||||
|
~/Documents/Projects/Airplane_Data_Logger/N72KH Data/flights/-date-/
|
||||||
|
~/Documents/Projects/Airplane_Data_Logger/programs/
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def prepare(date):
|
||||||
|
print("splitting logs")
|
||||||
|
sp="../N72KH Data/flights/%s/N72KH_combined_%s/" %(date,date) # combined log
|
||||||
|
fl=glob.glob(sp+"L*")
|
||||||
|
for f in fl: # file in filelist
|
||||||
|
os.rename(f, f.upper())
|
||||||
|
fn=os.path.splitext(f.upper())[0] # fn = filename
|
||||||
|
# tr bsd command = translate characters \r -> \n
|
||||||
|
c="LC_CTYPE=C tr -s '\r' '\n' < '%s' > '%s'" % (f.upper(),fn+"N.TXT")
|
||||||
|
os.system(c)
|
||||||
|
# run log_splitter.py on the translated file (fn+"N")
|
||||||
|
c="python ./log_splitter.py '%s.TXT'" % (fn+"N")
|
||||||
|
os.system(c)
|
||||||
|
# NOW MOVE TO CORRECT DIRECTORY
|
||||||
|
pi=[i for i, c in enumerate(f) if c =='/']
|
||||||
|
c="mv '%sN_E.TXT' '%s/N72KH_EMS_%s/'" % (fn,f[:pi[-2]],date)
|
||||||
|
os.system(c)
|
||||||
|
c="mv '%sN_F.TXT' '%s/N72KH_EFIS_%s/'" % (fn,f[:pi[-2]],date)
|
||||||
|
os.system(c)
|
||||||
|
c="mv '%sN_G.TXT' '%s/N72KH_GPS_%s/'" % (fn,f[:pi[-2]],date)
|
||||||
|
os.system(c)
|
||||||
|
|
||||||
|
def process(date,logs):
|
||||||
|
if logs=='all' or logs=='ems':
|
||||||
|
print("processing EMS")
|
||||||
|
#sp="../N72KH Data/flights/%s/N72KH_EIS_%s/" %(date,date) # GRT EIS
|
||||||
|
sp="../N72KH Data/flights/%s/N72KH_EMS_%s/" %(date,date) # Dynon EMS
|
||||||
|
fl=glob.glob(sp+"LOG0*.TXT")
|
||||||
|
for f in fl:
|
||||||
|
fn=f.split("/")[-1].split(".")[0] # filename
|
||||||
|
# s="python ./eis_bin2csv.py '%s%s.TXT' > '%s%s.csv'" % (sp,fn,sp,fn) # GRT EIS
|
||||||
|
s="python ./ems2csv.py '%s%s.TXT' > '%s%s.csv'" % (sp,fn,sp,fn) # Dynon EMS
|
||||||
|
os.system(s)
|
||||||
|
|
||||||
|
if logs=='all' or logs=='efis':
|
||||||
|
print("processing EFIS")
|
||||||
|
sp="../N72KH Data/flights/%s/N72KH_EFIS_%s/" %(date,date)
|
||||||
|
fl=glob.glob(sp+"LOG0*.TXT")
|
||||||
|
for f in fl:
|
||||||
|
fn=f.split("/")[-1].split(".")[0] # filename
|
||||||
|
s="python ./efis2csv.py '%s%s.TXT' > '%s%s.csv'" % (sp,fn,sp,fn)
|
||||||
|
os.system(s)
|
||||||
|
|
||||||
|
if logs=='all' or logs=='gps':
|
||||||
|
print("processing GPS")
|
||||||
|
sp="../N72KH Data/flights/%s/N72KH_GPS_%s/" %(date,date) # path
|
||||||
|
fl=glob.glob(sp+"LOG0*.TXT") # file list
|
||||||
|
for f in fl:
|
||||||
|
fn=f.split("/")[-1].split(".")[0] # filename
|
||||||
|
s="python ./gps_formatter.py '%s%s.TXT' > '%s%s.csv'" % (sp,fn,sp,fn)
|
||||||
|
os.system(s)
|
||||||
|
s="./gps_convert.sh \"%s%s.csv\" \"%s%s.kml\"" % (sp,fn,sp,fn)
|
||||||
|
#print s
|
||||||
|
os.system(s)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Process all log files')
|
||||||
|
parser.add_argument('date',
|
||||||
|
help='folder date (e.g. 2nov2017)')
|
||||||
|
parser.add_argument('logname', nargs='?', default='all',
|
||||||
|
help='{gps | ems | efis | all}')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
prepare(args.date)
|
||||||
|
process(args.date,args.logname)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user