Source code for eaarl.io.ins
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
'''Handling for ins trajectory file'''
# Boilerplate for cross-compatibility of Python 2/3
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future.builtins import * # pylint: disable=wildcard-import
import future.standard_library
future.standard_library.install_aliases()
import numpy as np
import pandas as pd
import tables
from ..util.utm import from_latlon
[docs]def read(filename):
'''Read INS data from a given HDF5 or CSV file
Returns : pandas.DataFrame
Returns a DataFrame with the file's data.
'''
try:
with tables.open_file(filename, 'r') as f:
h5data = f.root.ins.read()
return pd.DataFrame(h5data)
except tables.exceptions.HDF5ExtError:
return pd.read_csv(filename)
def _unwrap(degrees):
'''Updates angles to avoid big jumps
For example, [359, 1] becomes [359, 361].'''
return np.rad2deg(np.unwrap(np.deg2rad(degrees)))
[docs]def apply_corrections(ins, gps_time_offset=0):
'''Update INS data with relevant corrections
The timestamp in an INS file can originally be in seconds-of-the-week
format. This converts it to seconds-of-the-mission-day format.
The heading is also "unwrapped" so the angle values avoid big jumps. For
example, the sequence [359, 1] will become [359, 361]. This speeds up
interpolation.
Parameters
ins : pandas.DataFrame
A DataFrame containing the INS data
gps_time_offset : numeric
GPS time offset to apply to the data to convert it to UTC time.
Returns : pandas.DataFrame
Returns the modified ins DataFrame.
'''
day_start = int(ins.sod[0] / 86400) * 86400
ins['sod'] -= day_start
ins['sod'] += gps_time_offset
ins[ins.sod < 0]['sod'] += 604800
ins['heading'] = _unwrap(ins.heading)
return ins
[docs]def add_to_frame(frame, sod, ins, ops=None, prefix='ins_', zone=None):
r'''Adds interpolated INS data to a frame
Adds the following fields to the given dataframe:
* ins_lon - longitude of GPS antenna in degrees
* ins_lat - latitude of GPS antenna in degrees
* ins_alt - altitude of GPS antenna in meters
* ins_roll - roll of INS in degrees
* ins_pitch - pitch of INS in degrees
* ins_heading - heading of INS in degrees
* ins_east - UTM easting of GPS antenna in meters
* ins_north - UTM northing of GPS antenna in meters
* ins_zone - UTM zone for ins_east and ins_north
Parameters
frame : pandas.DataFrame
A pandas DataFrame that will have fields added to it
sod : np.array or pandas.Series
Seconds-of-the-day time values that correspond to the records in
the frame
ins : pandas.DataFrame
INS data to interpolate from
ops : dict
The ops data for the flight
prefix : string, default "ins\_"
Allows you to change the prefix used for the added fields.
zone : number or None
Allows you to specify a UTM zone that should be used when deriving
the northing and easting values
Returns : pandas.DataFrame
Returns the DataFrame that was passed to it, which now contains added
fields.
'''
ops = ops or {}
def _interp(field):
return np.interp(sod, ins.sod, field, left=np.nan, right=np.nan)
fields = ['lon', 'lat', 'alt', 'roll', 'pitch', 'heading']
for field in fields:
frame[prefix + field] = _interp(ins[field])
if 'dmars_invert' in ops and ops['dmars_invert']:
frame[prefix + 'roll'] *= -1
frame[prefix + 'pitch'] *= -1
frame[prefix + 'heading'] += 180
# If any of the requested sod values are outside the bounds of the INS,
# then the corresponding values will be nan. The UTM conversion in
# from_latlon fails if any values are nan, so avoid passing them to it.
valid = ~np.isnan(frame[prefix + 'lon']) & ~np.isnan(frame[prefix + 'lat'])
frame[prefix + 'east'] = np.nan
frame[prefix + 'north'] = np.nan
frame[prefix + 'zone'] = np.nan
(
frame.loc[valid, prefix + 'east'], frame.loc[valid, prefix + 'north'],
frame.loc[valid, prefix + 'zone'], _
) = from_latlon(frame[prefix + 'lat'][valid],
frame[prefix + 'lon'][valid], zone)
return frame