Thursday 10 January 2019

Parsing FAA NASR data: NATFIX file


NASR stands for National Airspace System Resource.
For more infromation about NASR, please refer to:https://www.faa.gov/air_traffic/flight_info/aeronav/aero_data/NASR_Subscription/


It is a good idea to a bit dive into 28 day subscription because of two main reasons:
  • it provide a lot of aeronautical data (waypoints, airways, aerodromes)
  • it is a good source of data to practice various python skills such as handling structured files, extracting some data and inserting it into database as well as  GIS skills.
In this post I am going to deal only with one file of the set of data - NATFIX file, that stands for Enroute National Fix Program Significant Points.
Description of this file can be found here: https://nfdc.faa.gov/webContent/28DaySub/2019-01-03/Layout_Data/NATFIX_rf.txt
Note: Remember that structure of the file can varying, depending on which date you choose. So, be aware that this script might not be usable for all data - previous or future subscriptions.

Dictionary that keep NATFIX fields, where keys are NATFIX fields, values are tuples where first element is length of field and second value is start location:


natfix_fields = {'WPT_ID': (5, 3),
                 'LAT_DMS': (7, 9),
                 'LON_DMS': (8, 17),
                 'ARTCC_ID': (4, 27),
                 'STATE_CODE': (2, 32),
                 'ICAO_REGION_CODE': (2, 35),
                 'WPT_TYPE': (7, 38)}

Class for parsing NASR file line:

class NASRLine:
    def __init__(self, raw_line):
        self.raw_line = raw_line
        self.dict_values = {}

    def parse_line(self, fields):
        for key in fields:
            length = fields.get(key)[0]
            start = fields.get(key)[1] - 1
            end = start + length
            self.dict_values[key] = self.raw_line[start:end].strip()

Format of coordinates in NASR files


@staticmethod
    def dmsh_compacted2dd(dms):
        h_suffix = dms[-1]  # Hemisphere suffix
        dms_m = dms[:-1]  # Trim hemisphere suffix
        if h_suffix in H_LAT:
            d = float(dms_m[0:2])
            m = float(dms_m[2:4])
            s = float(dms_m[4:])
        elif h_suffix in H_LON:
            d = float(dms_m[0:3])
            m = float(dms_m[3:5])
            s = float(dms_m[5:])

        dd = d + m / 60 + s / 3600

        if h_suffix in H_MINUS:
            dd = -dd

        return dd

NATFIXLine class:


class NATFIXLine(NASRLine):
    def __init__(self, raw_line):
        NASRLine.__init__(self, raw_line)

Method that parse line and insert it into database:

def insert2postgis(self, cursor):
    self.parse_line(natfix_fields)
    cursor.execute(""" INSERT INTO natfix
                        (wpt_ident,
                        lat_dms,
                        lon_dms,
                        artcc_id,
                        state_code,
                        icao_region_code,
                        wpt_type,
                        geo_location)
                       VALUES
                        (%s, %s, %s, %s, %s, %s, %s, ST_GeomFromText('POINT(%s %s)', 4326));""",
                   (self.dict_values.get('WPT_ID'),
                    self.dict_values.get('LAT_DMS'),
                    self.dict_values.get('LON_DMS'),
                    self.dict_values.get('ARTCC_ID'),
                    self.dict_values.get('STATE_CODE'),
                    self.dict_values.get('ICAO_REGION_CODE'),
                    self.dict_values.get('WPT_TYPE'),
                    self.dmsh_compacted2dd(self.dict_values.get('LON_DMS')),
                    self.dmsh_compacted2dd(self.dict_values.get('LAT_DMS'))))

And finnaly, function that reads NATFIX file and insert conetent into natfix tabel in PostGIS database:


def nasr_natfix2postgis(input_file):
    """ Imports NASR NATFIX.txt file into PostGIS database
    :param input_file: str, NASR NATFIX input file path
    """
    # TO DO: reading header of file
    conn = psycopg2.connect(host="", database="", user="",
                            password="")
    cursor = conn.cursor()
    with open(input_file, 'r') as nasr_file:
        for line in nasr_file:
            if line[0] == 'I':
                natfix_wpt = NATFIXLine(line.strip('\n'))
                natfix_wpt.insert2postgis(cursor)
                conn.commit()
    cursor.close()
    return

The whole source code for script is available here: https://github.com/strpaw/python_examples/blob/master/natfix_tools.py

No comments:

Post a Comment