Skip to content

Commit 3f09cfc

Browse files
committed
New retrieve_runway_list dervices runway data from OurAirports db
1 parent 437777a commit 3f09cfc

6 files changed

Lines changed: 1029 additions & 13 deletions

File tree

GA_Detect.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""A script to process OpenSky ADS-B data in an attempt to detect go-around events at an airport."""
22
from traffic.core import Traffic
33
from datetime import timedelta
4-
import importlib
54
import multiprocessing as mp
65
import metar_parse as MEP
6+
from OS_Airports.RWY import get_runway_list
77
import OS_Funcs as OSF
88
import os
99
import glob
@@ -83,8 +83,7 @@ def main(top_dir, start_n, do_write, do_plot, metars_file, airport,
8383
'DE': 'orange', 'LVL': 'purple', 'NA': 'red'}
8484

8585
metars = MEP.get_metars(metars_file, verbose=verbose)
86-
rwy_list = getattr(importlib.import_module(f'OS_Airports.{airport}'),
87-
'rwy_list')
86+
rwy_list = get_runway_list(airport)
8887

8988
f_data = []
9089
pool = mp.Pool(processes=pool_proc)

OS_Airports/RWY.py

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
import importlib
2+
import os
3+
4+
from numpy import (
5+
arcsin,
6+
arctan2,
7+
cos,
8+
degrees,
9+
pi,
10+
radians,
11+
sin,
12+
)
13+
import pandas
14+
import requests
15+
16+
117
class rwy_data:
218
''' Defines a new runway for an airport. Takes the form:
319
Name: Name of the runway, i.e: '01L'
@@ -15,12 +31,12 @@ class rwy_data:
1531
polynomial fit: y = f0 * x^6 + f1 * x^5 ... f6
1632
'''
1733
def __init__(self, name, mainhdg, heading, rwy, rwy2, gate,
18-
lons1, lonm, lonp1,
19-
lats1, latm, latp1,
20-
hdgs1, hdgm, hdgp1,
21-
gals1, galm, galp1,
22-
alts1, altm, altp1,
23-
rocs1, rocm, rocp1):
34+
lons1=None, lonm=None, lonp1=None,
35+
lats1=None, latm=None, latp1=None,
36+
hdgs1=None, hdgm=None, hdgp1=None,
37+
gals1=None, galm=None, galp1=None,
38+
alts1=None, altm=None, altp1=None,
39+
rocs1=None, rocm=None, rocp1=None):
2440

2541
self.name = name
2642
self.mainhdg = mainhdg
@@ -47,3 +63,87 @@ def __init__(self, name, mainhdg, heading, rwy, rwy2, gate,
4763
self.rocm = rocm
4864
self.rocp1 = rocp1
4965

66+
def __eq__(self, other):
67+
return vars(self) == vars(other)
68+
69+
def __repr__(self):
70+
return (
71+
'rwy_data(' +
72+
', '.join([
73+
f'{key}={val!r}'
74+
for key, val in vars(self).items() if val is not None
75+
]) +
76+
')'
77+
)
78+
79+
80+
def gate(rwy, rwy2, dist=2.9e3, R=6371e3):
81+
φ1, λ1 = radians(rwy[0]), radians(rwy[1])
82+
φ2, λ2 = radians(rwy2[0]), radians(rwy2[1])
83+
Δλ = λ2 - λ1
84+
θ = arctan2(sin(Δλ) * cos(φ2), cos(φ1) * sin(φ2) -
85+
sin(φ1) * cos(φ2) * cos(Δλ)) + pi
86+
φ3 = arcsin(sin(φ1) * cos(dist/R) +
87+
cos(φ1) * sin(dist/R) * cos(θ))
88+
λ3 = λ1 + arctan2(sin(θ) * sin(dist/R) * cos(φ1),
89+
cos(dist/R) - sin(φ1) * sin(φ2))
90+
return [degrees(φ3), degrees(λ3)]
91+
92+
93+
def retrieve_runway_list(name, runways_csv='runways.csv'):
94+
result = []
95+
if not os.path.exists(runways_csv):
96+
text = requests.get('https://ourairports.com/data/runways.csv').text
97+
with open(runways_csv, 'w') as f:
98+
f.write(text)
99+
runways = pandas.read_csv(runways_csv)
100+
runways = runways.query(f'airport_ident == "{name}"')
101+
for idx, row in runways.iterrows():
102+
le_heading = row.le_heading_degT
103+
he_heading = row.he_heading_degT
104+
if le_heading > 180:
105+
le_heading = -(360 - le_heading)
106+
if he_heading > 180:
107+
he_heading = -(360 - he_heading)
108+
result.append(rwy_data(
109+
name=row.le_ident,
110+
mainhdg=row.le_heading_degT,
111+
heading=[
112+
le_heading-10,
113+
le_heading,
114+
le_heading,
115+
le_heading+10,
116+
],
117+
rwy=[row.le_latitude_deg, row.le_longitude_deg],
118+
rwy2=[row.he_latitude_deg, row.he_longitude_deg],
119+
gate=gate(
120+
[row.le_latitude_deg, row.le_longitude_deg],
121+
[row.he_latitude_deg, row.he_longitude_deg],
122+
),
123+
))
124+
result.append(rwy_data(
125+
name=row.he_ident,
126+
mainhdg=row.he_heading_degT,
127+
heading=[
128+
he_heading-10,
129+
he_heading,
130+
he_heading,
131+
he_heading+10,
132+
],
133+
rwy=[row.he_latitude_deg, row.he_longitude_deg],
134+
rwy2=[row.le_latitude_deg, row.le_longitude_deg],
135+
gate=gate(
136+
[row.he_latitude_deg, row.he_longitude_deg],
137+
[row.le_latitude_deg, row.le_longitude_deg],
138+
),
139+
))
140+
return result
141+
142+
143+
def get_runway_list(name):
144+
try:
145+
module = importlib.import_module(f'OS_Airports.{name}')
146+
except ModuleNotFoundError:
147+
return retrieve_runway_list(name)
148+
else:
149+
return getattr(module, 'rwy_list')

OpenSky_Get_Data.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"""
66

77
from datetime import datetime, timedelta, timezone
8-
from importlib import import_module
98
from traffic.data import opensky
109
import multiprocessing as mp
1110
import numpy as np
1211
import pathlib
1312
import click
1413
import os
14+
from OS_Airports.RWY import get_runway_list
1515

1616

1717
# Use these lines if you need debug info
@@ -86,8 +86,8 @@ def getter(init_time, bounds, timer, anam, outdir, subdir):
8686
@click.option('--n-jobs', default=1)
8787
def main(airport, start_dt, end_dt, outdir, subdir, n_jobs):
8888
"""Set up the processing and run."""
89-
airport = import_module('OS_Airports.' + airport)
90-
bounds = get_bounds(airport.rwy_list)
89+
rwy_list = get_runway_list(airport)
90+
bounds = get_bounds(rwy_list)
9191
start_dt = datetime.strptime(start_dt, '%Y-%m-%d').replace(
9292
tzinfo=timezone.utc)
9393
end_dt = datetime.strptime(end_dt, '%Y-%m-%d').replace(
@@ -97,7 +97,7 @@ def main(airport, start_dt, end_dt, outdir, subdir, n_jobs):
9797
pool = mp.Pool(n_jobs)
9898

9999
pool.starmap(getter, [
100-
(start_dt, bounds, hour, airport.icao_name, outdir, subdir)
100+
(start_dt, bounds, hour, airport, outdir, subdir)
101101
for hour in range(hours)
102102
])
103103

0 commit comments

Comments
 (0)