Eotvos correction#

The Eotvos correction is a necessary correction to apply for any gravity surveys conducted on a moving platform, such as a ship or airplane. The correction accounts for the relative motion between the vehicle and the Earth’s surface, which generates an additional centrifugal force known as the Eotvos effect. We offer several methods of computing the correction, which we show here, generally from simpliest to most complex.

[1]:
# %load_ext autoreload
# %autoreload 2

import pandas as pd
import plotly.io as pio
import verde as vd

import airbornegeo

pio.renderers.default = "notebook"

Load data#

This is a subset of the BAS AGAP survey over Antarctica’s Gamburtsev Subglacial Mountains. The file is downloaded and subset in the notebook AGAP_gravity_survey. It has a pre-computed Eotvos correction, which we will compare our computed values to.

[ ]:
data_df = pd.read_csv("data/AGAP_gravity_survey.csv")
survey = airbornegeo.Survey(
    data_df,
    line_column="line",
    time_column="unixtime",
    latitude_column="Lat",
    longitude_column="Lon",
)
data_df = survey.data
print(data_df.columns)
data_df.head()
[ ]:
survey.along_track_distance()
data_df = survey.data
[4]:
# get only the raw columns
# we will perform the corrections ourselves and compare to their values
data_df = data_df[
    [
        "EotvosCor",
        "Lon",
        "Lat",
        "Height_WGS1984",
        "easting",
        "northing",
        "unixtime",
        "line",
        "distance_along_line",
    ]
]
data_df.head()
[4]:
EotvosCor Lon Lat Height_WGS1984 easting northing unixtime line distance_along_line
0 68.15 77.252450 -80.583923 4156.1 1.000024e+06 226237.330771 1.229507e+09 1 0.000000
1 68.37 77.252672 -80.583377 4156.0 1.000083e+06 226246.631269 1.229507e+09 1 59.842447
2 68.37 77.252901 -80.582831 4156.1 1.000142e+06 226255.809132 1.229507e+09 1 119.693401
3 68.16 77.253131 -80.582285 4156.4 1.000201e+06 226264.969079 1.229507e+09 1 179.545645
4 68.12 77.253358 -80.581740 4156.6 1.000260e+06 226274.156809 1.229507e+09 1 239.285174

Eotvos correction following Glicken 1962#

The most simple method of calculating the Eotvos correction is the Glicken 1962 formula, which depends on only the latitudes, the track angle, and the ground speed. This approximation ignores the effects of aircraft altitude, and the flattening of the ellipsoid. It does this by assuming heights are neglible compared to the radius of the Earth, and the change in Earth radius with latitude (flatenning) is also negligible, so the mean radius of the Earth is used. This results in a simple formula of

E = 7.503 V \cos\phi \sin\tau + 0.00415V^2

where \(V\) is the ground speed of the aircraft, \(\phi\) is the geodetic latitude, and \(\tau\) is the track angle.

The track angle is similar to the aircraft’s heading. The heading is the angle the nose of the plane points, which due to wind, can differ from the angle the path of the plane makes. This is in degrees clockwise from geographic (true) north.

By setting ellipsoid=True in the below function, we calculate the track using the WGS84 ellipsoid, instead of using a simplified spheric model of the Earth. It is more accurate, but a bit slower to compute.

[ ]:
survey.track(ellipsoid=False)
data_df = survey.data
[6]:
ax = data_df.plot.scatter(
    "easting",
    "northing",
    c="track",
    s=0.2,
)
ax.set_aspect("equal")
_images/eotvos_correction_9_0.png

The Glicken formulation also requiresthe ground speed of the aircraft. The below function ground_speed calculates the relative distance between successive rows in the dataframe. This assumes the dataframe is sorted by line, and then by time. From the relative distance, it then calculate the ground speed of the aircraft.

[ ]:
survey.ground_speed()
data_df = survey.data
[8]:
ax = data_df.plot.scatter(
    "easting",
    "northing",
    c="ground_speed",
    s=0.2,
)
ax.set_aspect("equal")
_images/eotvos_correction_12_0.png
[9]:
data_df["eotvos_correction_glicken"] = airbornegeo.eotvos_correction(
    data_df,
    method="glicken",
    latitude_column="Lat",
    track_column="track",
    ground_speed_column="ground_speed",
)
data_df.head()
[9]:
EotvosCor Lon Lat Height_WGS1984 easting northing unixtime line distance_along_line track ground_speed eotvos_correction_glicken
0 68.15 77.252450 -80.583923 4156.1 1.000024e+06 226237.330771 1.229507e+09 1 0.000000 3.805916 59.842447 65.686957
1 68.37 77.252672 -80.583377 4156.0 1.000083e+06 226246.631269 1.229507e+09 1 59.842447 3.925778 59.846701 65.994238
2 68.37 77.252901 -80.582831 4156.1 1.000142e+06 226255.809132 1.229507e+09 1 119.693401 3.943093 59.851599 66.047865
3 68.16 77.253131 -80.582285 4156.4 1.000201e+06 226264.969079 1.229507e+09 1 179.545645 3.899163 59.795886 65.825500
4 68.12 77.253358 -80.581740 4156.6 1.000260e+06 226274.156809 1.229507e+09 1 239.285174 3.933634 59.740782 65.799305
[10]:
ax = data_df.plot.scatter(
    "easting",
    "northing",
    c="eotvos_correction_glicken",
    s=0.2,
)
ax.set_aspect("equal")
_images/eotvos_correction_14_0.png
[11]:
df = data_df[data_df.line == 4]
ylim = vd.minmax(df.EotvosCor)
ax = df.plot.line(
    "distance_along_line",
    "EotvosCor",
    style="bp",
    ms=0.6,
    label="Published values",
    title=f"Line {df.line.unique()[0]}",
    ylim=ylim,
)
ax = df.plot.line(
    "distance_along_line",
    "eotvos_correction_glicken",
    style="rp",
    ms=0.6,
    title=f"Line {df.line.unique()[0]}",
    label="Calculated values",
    ax=ax,
    ylim=ylim,
)
ax.set_ylabel("Eotvos correction (mGal)")
[11]:
Text(0, 0.5, 'Eotvos correction (mGal)')
_images/eotvos_correction_15_1.png

Eotvos correction following Harlan 1968#

Another common method to compute the correction is from Harlan 1968. The paper offers several equations, but first we will follow equation 15.

Equation 15:#

This formulation requires the aircraft latitude, longtide, time (to calculate time derivatives) and height.

E = \frac{V_N^2}{a} [ 1 + \frac{h}{a} + f (2-3\sin^{2}\phi) ] + \frac{V_E^2}{a} [ 1 + \frac{h}{a} - f \sin^{2}\phi) ] + 2 V_E \omega \cos \phi (1 + \frac{h}{a})

where \(V_N\), \(V_E\), \(h\), and \(\phi\), $ are the aircraft’s eastward and northward velocities, height, and geodetic latitude, and \(a\), \(f\), and \(\omega\) are the ellipsoid’s semimajor axis, flattening, and rotation rate.

V_N = r' \dot{\phi_{c}} sec(D)
V_E = r' \dot{l} cos(\phi_{c})

where \(r'\) is the ellipsoid’s geocentric radius at the latitude of the aircraft, \(l\) is the aircraft’s longitude, \(\phi_{c}\) is the geocentric radius of the aircraft, \(\dot{\phi_{c}}\) is the first time derivative of the geocentric radius of the aircraft, and \(D\) is the deviation between the aircraft’s geodetic latitude and geocentric latitude.

Compared to the Glicken formulation, it is more exact since it accounts for aircraft height as well as the flattening of the ellipsoid. However it still makes a few assumptions which simplify the calculations. These include a simplification for the deviation between geocentric and geodetic latitudes, and thus the time derivatives of this deviation, as well as a simplification of the geocentric radius, and thus the time derivatives of the geocentric radius.

[12]:
data_df["eotvos_correction_harlan"] = airbornegeo.eotvos_correction(
    data_df,
    method="harlan",
    latitude_column="Lat",
    longitude_column="Lon",
    time_column="unixtime",
    height_column="Height_WGS1984",
    groupby_column="line",
)
data_df.head()
[12]:
EotvosCor Lon Lat Height_WGS1984 easting northing unixtime line distance_along_line track ground_speed eotvos_correction_glicken eotvos_correction_harlan
0 68.15 77.252450 -80.583923 4156.1 1.000024e+06 226237.330771 1.229507e+09 1 0.000000 3.805916 59.842447 65.686957 68.079899
1 68.37 77.252672 -80.583377 4156.0 1.000083e+06 226246.631269 1.229507e+09 1 59.842447 3.925778 59.846701 65.994238 68.241925
2 68.37 77.252901 -80.582831 4156.1 1.000142e+06 226255.809132 1.229507e+09 1 119.693401 3.943093 59.851599 66.047865 68.427131
3 68.16 77.253131 -80.582285 4156.4 1.000201e+06 226264.969079 1.229507e+09 1 179.545645 3.899163 59.795886 65.825500 68.275851
4 68.12 77.253358 -80.581740 4156.6 1.000260e+06 226274.156809 1.229507e+09 1 239.285174 3.933634 59.740782 65.799305 68.147679
[13]:
ax = data_df.plot.scatter(
    "easting",
    "northing",
    c="eotvos_correction_harlan",
    s=0.2,
)
ax.set_aspect("equal")
_images/eotvos_correction_18_0.png
[14]:
df = data_df[data_df.line == 4]
ylim = vd.minmax(df.EotvosCor)
ax = df.plot.line(
    "distance_along_line",
    "EotvosCor",
    style="bp",
    ms=0.6,
    label="Published values",
    title=f"Line {df.line.unique()[0]}",
    ylim=ylim,
)
ax = df.plot.line(
    "distance_along_line",
    "eotvos_correction_harlan",
    style="rp",
    ms=0.6,
    title=f"Line {df.line.unique()[0]}",
    label="Calculated values",
    ax=ax,
    ylim=ylim,
)
ax.set_ylabel("Eotvos correction (mGal)")
[14]:
Text(0, 0.5, 'Eotvos correction (mGal)')
_images/eotvos_correction_19_1.png