Combining satellite data with tidal modelling using OTPS

Background

Ocean tides are the periodic rise and fall of the ocean caused by the gravitational pull of the moon and sun and the earth’s rotation. Tides in coastal areas can greatly influence how these environments appear in satellite imagery as water levels vary by up to 12 metres (e.g. in northern Australia). To be able to study environmental processes along Australia’s coastline, it is vital to obtain data on tidal conditions at the exact moment each satellite image was acquired.

Description

This notebooks demonstrates how to tidally tag remotely sensed imagery using functions from the dea_coastaltools script so that images can be extracted or analysed by tidal stage (e.g. low, high, ebb, flow). These functions use the OTPS TPXO8 tidal model to calculate the height (relative to mean sea level, i.e. approximately equivalent to the Australian Height Datum or AHD) and stage of the tide at the exact moment each satellite image was acquired. This tidal model was previously used to produce DEA datasets including the Intertidal Extents Model (ITEM), High-Low Tide Composites (HLTC), and the National Intertidal Digital Elevation Model (NIDEM).

The notebook demonstrates how to:

  1. Load an example time series of satellite data

  2. Use the tidal_tag function from dea_coastaltools to model tide heights for each satellite observation

  3. Use tide height data to produce median composites of the coast at low and high tide

  4. Swap a dataset’s dimensions to compute a rolling median along the tide_height dimension

  5. Compute ebb or flow tide phase data to determine whether water levels were rising or falling in each satellite observation

  6. Use the tidal_stats function to evaluate any biases in the tidal conditions observed by a satellite


Getting started

To run this analysis, run all the cells in the notebook, starting with the “Load packages” cell.

Load packages

[1]:
%matplotlib inline

import sys
import datacube
import xarray as xr
import matplotlib.pyplot as plt

sys.path.append('../Scripts')
from dea_plotting import rgb
from dea_plotting import display_map
from dea_datahandling import load_ard
from dea_coastaltools import tidal_tag
from dea_coastaltools import tidal_stats

/g/data/v10/public/modules/dea/20200526/lib/python3.6/site-packages/datacube/storage/masking.py:4: DeprecationWarning: datacube.storage.masking has moved to datacube.utils.masking
  category=DeprecationWarning)

Connect to the datacube

[2]:
dc = datacube.Datacube(app='Tidal_modelling')

Set up data query

First we set up a query to define the area, time period and other parameters required for loading data. In this example, we will load 30 years of Landsat 5, 7 and 8 data for an intertidal beach near West Hill Island south of Mackay in Queensland. We load the 'nbart_red', 'nbart_green', 'nbart_blue' bands so that we can plot the data as true colour imagery.

The dask_chunks parameter allows us to use Dask to lazily load data rather than load data directly into memory, which can take a long time and large amounts of memory. Lazy loading can be a very useful approach for when you need to load large amounts of data without crashing your analysis. In coastal applications, it allows us to load (using either .compute() or by plotting our data) only a small subset of observations from our entire time series (e.g. only low or high tide observations) without having to load the entire dataset into memory first, which can greatly decrease processing times.

For more information about using Dask, refer to the Parallel processing with Dask notebook.

[3]:
# Set up data load query
query = {'x': (149.4, 149.53),
         'y': (-21.71, -21.85),
         'time': ('1988', '2018'),
         'measurements': ['nbart_red', 'nbart_green', 'nbart_blue'],
         'output_crs': 'EPSG:32755',
         'resolution': (-30, 30),
         'group_by': 'solar_day',
         'dask_chunks': {}}

We can preview the area that we will load data for:

[4]:
display_map(x=query['x'], y=query['y'])
/g/data/v10/public/modules/dea-env/20200526/lib/python3.6/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
  return _prepare_from_string(" ".join(pjargs))
/g/data/v10/public/modules/dea-env/20200526/lib/python3.6/site-packages/pyproj/crs/crs.py:294: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
  projstring = _prepare_from_string(" ".join((projstring, projkwargs)))
/g/data/v10/public/modules/dea-env/20200526/lib/python3.6/site-packages/pyproj/crs/crs.py:53: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
  return _prepare_from_string(" ".join(pjargs))
/g/data/v10/public/modules/dea-env/20200526/lib/python3.6/site-packages/pyproj/crs/crs.py:294: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
  projstring = _prepare_from_string(" ".join((projstring, projkwargs)))
[4]:

Load satellite time-series

To obtain some satellite data to analyse, we use the load_ard import a time series of Landsat 5, 7 and 8 observations as an xarray.Dataset. The input data does not need to be from Landsat: any remotely-sensed imagery with timestamps and spatial coordinates provide enough data to run the tidal model.

[5]:
# Load available data from all three Landsat satellites
ds = load_ard(dc=dc,
              products=['ga_ls5t_ard_3', 'ga_ls7e_ard_3', 'ga_ls8c_ard_3'],
              ls7_slc_off=False,
              **query)

# Print output data
print(ds)
Loading ga_ls5t_ard_3 data
    Applying pixel quality/cloud mask
    Applying invalid data mask
Loading ga_ls7e_ard_3 data
    Ignoring SLC-off observations for ls7
    Applying pixel quality/cloud mask
    Applying invalid data mask
Loading ga_ls8c_ard_3 data
    Applying pixel quality/cloud mask
    Applying invalid data mask
Combining and sorting data
    Returning 945 observations as a dask array
<xarray.Dataset>
Dimensions:      (time: 945, x: 458, y: 525)
Coordinates:
    spatial_ref  int32 32755
  * x            (x) float64 7.48e+05 7.481e+05 ... 7.617e+05 7.617e+05
  * y            (y) float64 7.597e+06 7.597e+06 ... 7.582e+06 7.582e+06
  * time         (time) datetime64[ns] 1988-01-06T23:27:58.301764 ... 2018-12-26T23:58:56.635504
Data variables:
    nbart_red    (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_green  (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_blue   (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
Attributes:
    crs:           EPSG:32755
    grid_mapping:  spatial_ref

Model tide heights for each observation

We use the tidal_tag function from dea_coastaltools to associate each satellite observation in our timeseries with a tide height relative to mean sea level (i.e. approximately equivalent to the Australian Height Datum or AHD). This function uses the time and date of acquisition and the geographic location of each satellite observation as inputs to the OSU Tidal Prediction Software (OTPS) tidal model. From Sagar et al. 2015:

The OTPS TPX08 tidal model consists of a multi-resolution bathymetric grid solution, with a 1/6° solution in the global open ocean, and a 1/30° local resolution solution to improve modelling in complex shallow water environments. The OTPS model is based on a system of linear partial differential equations, called Laplace’s tidal equations, parametrised with nine harmonic tidal constituents. The model is fitted to track-averaged TOPEX/Poseidon altimeter data collected from 1992 to 2016 and Jason-1 (Poseidon 2) altimeter data from 2002 to 2013, enabling estimation of the tidal height and harmonic constituents at discrete temporal epochs and spatial locations.

[6]:
# Model tide heights
ds_tidal = tidal_tag(ds)

# Print output data
print(ds_tidal)

Setting tide modelling location from dataset centroid: 149.47, -21.78
<xarray.Dataset>
Dimensions:      (time: 945, x: 458, y: 525)
Coordinates:
    spatial_ref  int32 32755
  * x            (x) float64 7.48e+05 7.481e+05 ... 7.617e+05 7.617e+05
  * y            (y) float64 7.597e+06 7.597e+06 ... 7.582e+06 7.582e+06
  * time         (time) datetime64[ns] 1988-01-06T23:27:58.301764 ... 2018-12-26T23:58:56.635504
Data variables:
    nbart_red    (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_green  (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_blue   (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    tide_height  (time) float64 -0.832 1.259 -1.818 ... -0.742 1.367 -1.684
Attributes:
    crs:           EPSG:32755
    grid_mapping:  spatial_ref

The function will automatically select a tide modelling location based on the dataset centroid. It will then output modelled tide heights as a new tide_height variable in the xarray.Dataset (the variable should appear under Data variables above).

We can easily plot this new variable to inspect the range of tide heights observed by the satellites in our timeseries. In this example, our observed tide heights range from approximately -3.0 to 4.0 m relative to Mean Sea Level:

[7]:
ds_tidal.tide_height.plot(linewidth=0.5)
[7]:
[<matplotlib.lines.Line2D at 0x7efeb0612f28>]
../../_images/notebooks_Frequently_used_code_Tidal_modelling_16_1.png

Example tide height analysis

To demonstrate how tidally tagged images can be used to produce composites of high and low tide imagery, we can compute the lowest 5% and highest 5% percent of tide heights, and use these to filter our observations. We can then combine and plot these filtered observations to visualise what the landscape looks like at low and high tide:

[8]:
# Calculate the lowest and highest 5% of tides
lowest_5, highest_5 = ds_tidal.tide_height.quantile([0.05, 0.95]).values

# Filter our data to low and high tide observations
filtered_low = ds_tidal.where(ds_tidal.tide_height <= lowest_5, drop=True)
filtered_high = ds_tidal.where(ds_tidal.tide_height >= highest_5, drop=True)

# Take the simple median of each set of low and high tide observations to
# produce a composite (alternatively, observations could be combined
# using a geomedian to keep band relationships consistent)
median_low = filtered_low.median(dim='time', keep_attrs=True)
median_high = filtered_high.median(dim='time', keep_attrs=True)

# Combine low and high tide medians into a single dataset and give
# each layer a meaningful name
ds_highlow = xr.concat([median_low, median_high], dim='tide_height')
ds_highlow['tide_height'] = ['Low tide', 'High tide']

# Plot low and high tide medians side-by-side
rgb(ds_highlow, col='tide_height')
../../_images/notebooks_Frequently_used_code_Tidal_modelling_18_0.png

Swapping dimensions

The tidal_tag function allows you to use tide heights as the primary dimension in the dataset, rather than time. Setting swap_dims=True will swap the time dimension in the original xarray.Dataset to the new tide_height variable.

[9]:
# Model tide heights
ds_tidal = tidal_tag(ds, swap_dims=True)

# Print output data
print(ds_tidal)
Setting tide modelling location from dataset centroid: 149.47, -21.78
<xarray.Dataset>
Dimensions:      (tide_height: 945, x: 458, y: 525)
Coordinates:
    spatial_ref  int32 32755
  * x            (x) float64 7.48e+05 7.481e+05 ... 7.617e+05 7.617e+05
  * y            (y) float64 7.597e+06 7.597e+06 ... 7.582e+06 7.582e+06
  * tide_height  (tide_height) float64 -2.292 -2.262 -2.128 ... 3.233 3.253
Data variables:
    nbart_red    (tide_height, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_green  (tide_height, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_blue   (tide_height, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
Attributes:
    crs:           EPSG:32755
    grid_mapping:  spatial_ref

The dataset now contains three dimensions: tide_height, x and y. This can make it easier to analyse the data with respect to tide, e.g. computing a rolling median by tide height (e.g. along the tide_height dimension):

[10]:
# First we need to update the chunks used by Dask to allow us to do a
# rolling median without having to load all our data into memory first
ds_rechunked = ds_tidal.chunk(chunks={'tide_height': 15})

# Compute a rolling median that will go through every satellite
# observation, and take the median of that timestep and its 15 neighbours
ds_rolling = ds_rechunked.rolling(tide_height=15,
                                  center=True,
                                  min_periods=1).median()

# Plot the lowest, 500th and highest tide rolling median image
rgb(ds_rolling, index_dim='tide_height', index=[0, 500, -1])
../../_images/notebooks_Frequently_used_code_Tidal_modelling_22_0.png

Modelling ebb and flow tidal phases

The tidal_tag function also allows us to determine whether each satellite observation was taken while the tide was rising/incoming (flow tide) or falling/outgoing (ebb tide) by setting ebb_flow=True. This is achieved by comparing tide heights 15 minutes before the before and after the observed satellite observation.

Ebb and flow data can provide valuable contextual information for interpreting satellite imagery, particularly in tidal flat or mangrove forest environments where water may remain in the landscape for considerable time after the tidal peak.

[11]:
# Model tide heights
ds_tidal = tidal_tag(ds, ebb_flow=True)

# Print output data
print(ds_tidal)
Setting tide modelling location from dataset centroid: 149.47, -21.78
Modelling tidal phase (e.g. ebb or flow)
<xarray.Dataset>
Dimensions:      (time: 945, x: 458, y: 525)
Coordinates:
    spatial_ref  int32 32755
  * x            (x) float64 7.48e+05 7.481e+05 ... 7.617e+05 7.617e+05
  * y            (y) float64 7.597e+06 7.597e+06 ... 7.582e+06 7.582e+06
  * time         (time) datetime64[ns] 1988-01-06T23:27:58.301764 ... 2018-12-26T23:58:56.635504
Data variables:
    nbart_red    (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_green  (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    nbart_blue   (time, y, x) float32 dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
    tide_height  (time) float64 -0.832 1.259 -1.818 ... -0.742 1.367 -1.684
    ebb_flow     (time) <U4 'Flow' 'Ebb' 'Flow' 'Flow' ... 'Flow' 'Ebb' 'Flow'
Attributes:
    crs:           EPSG:32755
    grid_mapping:  spatial_ref

We now have data giving us the both the tide height and tidal phase (‘ebb’ or ‘flow’) for every satellite image:

[12]:
ds_tidal[['time', 'tide_height', 'ebb_flow']].to_dataframe()
[12]:
tide_height ebb_flow spatial_ref
time
1988-01-06 23:27:58.301764 -0.832 Flow 32755
1988-01-13 23:34:17.335745 1.259 Ebb 32755
1988-01-22 23:28:16.039754 -1.818 Flow 32755
1988-01-29 23:34:35.316447 2.346 Flow 32755
1988-02-14 23:34:51.644339 2.956 Flow 32755
... ... ... ...
2018-11-24 23:58:59.776266 0.144 Flow 32755
2018-12-02 00:05:09.575190 1.078 Ebb 32755
2018-12-10 23:58:56.697928 -0.742 Flow 32755
2018-12-18 00:05:07.146347 1.367 Ebb 32755
2018-12-26 23:58:56.635504 -1.684 Flow 32755

945 rows × 3 columns

We could for example use this data to filter our observations to keep ebbing phase observations only:

[13]:
ds_tidal.where(ds_tidal.ebb_flow == 'Ebb', drop=True)
[13]:
Show/Hide data repr Show/Hide attributes
xarray.Dataset
    • time: 399
    • x: 458
    • y: 525
    • spatial_ref
      ()
      int32
      32755
      spatial_ref :
      PROJCS["WGS 84 / UTM zone 55S",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",147],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",10000000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32755"]]
      grid_mapping_name :
      transverse_mercator
      array(32755, dtype=int32)
    • x
      (x)
      float64
      7.48e+05 7.481e+05 ... 7.617e+05
      units :
      metre
      resolution :
      30.0
      crs :
      EPSG:32755
      array([748035., 748065., 748095., ..., 761685., 761715., 761745.])
    • y
      (y)
      float64
      7.597e+06 7.597e+06 ... 7.582e+06
      units :
      metre
      resolution :
      -30.0
      crs :
      EPSG:32755
      array([7597335., 7597305., 7597275., ..., 7581675., 7581645., 7581615.])
    • time
      (time)
      datetime64[ns]
      1988-01-13T23:34:17.335745 ... 2018-12-18T00:05:07.146347
      array(['1988-01-13T23:34:17.335745000', '1988-03-26T23:29:05.011953000',
             '1988-04-11T23:29:09.382617000', ..., '2018-11-16T00:05:11.027813000',
             '2018-12-02T00:05:09.575190000', '2018-12-18T00:05:07.146347000'],
            dtype='datetime64[ns]')
    • nbart_red
      (time, y, x)
      float32
      dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
      units :
      1
      crs :
      EPSG:32755
      grid_mapping :
      spatial_ref
      Array Chunk
      Bytes 383.76 MB 961.80 kB
      Shape (399, 525, 458) (1, 525, 458)
      Count 14986 Tasks 399 Chunks
      Type float32 numpy.ndarray
      458 525 399
    • nbart_green
      (time, y, x)
      float32
      dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
      units :
      1
      crs :
      EPSG:32755
      grid_mapping :
      spatial_ref
      Array Chunk
      Bytes 383.76 MB 961.80 kB
      Shape (399, 525, 458) (1, 525, 458)
      Count 14986 Tasks 399 Chunks
      Type float32 numpy.ndarray
      458 525 399
    • nbart_blue
      (time, y, x)
      float32
      dask.array<chunksize=(1, 525, 458), meta=np.ndarray>
      units :
      1
      crs :
      EPSG:32755
      grid_mapping :
      spatial_ref
      Array Chunk
      Bytes 383.76 MB 961.80 kB
      Shape (399, 525, 458) (1, 525, 458)
      Count 14986 Tasks 399 Chunks
      Type float32 numpy.ndarray
      458 525 399
    • tide_height
      (time)
      float64
      1.259 1.399 2.177 ... 1.078 1.367
      array([ 1.259,  1.399,  2.177, -1.266, -1.203, -0.418,  0.448,  0.432,
             -0.963, -0.76 ,  0.776, -1.161, -0.336,  1.588,  1.951, -1.362,
              0.207,  0.521, -0.857, -0.513,  1.702, -1.525, -1.482, -0.347,
              0.121,  0.747, -0.754, -0.195,  1.548,  1.798,  1.031,  1.756,
             -1.067, -0.325,  0.289,  1.557, -0.259, -1.179,  0.1  ,  1.755,
              1.855, -1.369, -1.015,  0.507,  0.926, -0.972, -0.535,  0.3  ,
              1.156, -1.898, -0.049,  0.117, -0.723,  1.943, -1.446, -0.878,
              0.71 ,  0.89 ,  1.917,  2.568, -0.919, -0.735,  0.339,  1.129,
             -1.92 , -1.169, -0.712,  2.015,  0.823,  0.872,  1.929, -1.569,
              2.369, -0.914,  1.204, -1.838, -0.927,  0.426,  0.583, -0.764,
             -0.596,  1.074,  1.842, -1.442, -0.446,  0.954, -0.822, -1.668,
              0.697,  0.969, -0.623, -0.409,  1.367, -0.752,  0.853, -1.575,
             -0.44 ,  0.477,  1.094, -0.863, -0.423,  1.354, -1.646, -1.448,
             -0.285,  0.343,  0.923,  1.905,  1.737, -0.771,  0.676,  0.723,
             -1.417, -0.291,  0.263,  1.263,  2.625, -1.033, -0.319,  1.358,
              1.461, -0.249,  0.006,  0.924, -1.604,  0.691,  0.798,  0.157,
              1.478,  2.665, -1.307, -0.115,  1.516, -1.819, -1.293, -0.164,
             -0.163, -1.595, -1.062, -0.402, -0.336,  0.239,  1.026,  2.234,
             -1.203, -1.145, -0.844,  0.1  ,  0.998,  2.096, -0.704,  0.136,
              0.79 ,  2.115,  2.047,  0.435,  0.347,  1.325, -0.837, -0.307,
              0.578, -0.666,  0.949,  1.041,  2.219, -0.491,  0.085,  0.976,
              2.038, -1.428,  1.785, -1.444,  0.366,  0.292, -0.597, -0.285,
              0.923,  2.311,  2.358, -1.239, -0.47 ,  1.033,  1.142, -1.323,
             -0.286, -0.011, -1.476,  1.531, -1.595, -0.752,  0.354, -0.248,
              1.252,  2.38 , -0.278, -1.195, -0.183, -1.965, -1.127, -0.629,
              0.048,  1.434,  1.698, -0.854,  0.658,  0.826,  0.034,  0.864,
              2.267,  2.219, -0.614,  0.438,  1.296,  1.728, -1.042, -0.714,
              0.286,  1.654,  1.895, -0.708,  0.823, -0.587, -0.095,  1.011,
              2.126,  1.891, -1.379, -0.677,  0.294,  1.595, -0.876, -0.687,
              1.863,  0.888,  2.276, -0.173,  1.066, -1.396, -1.59 , -0.801,
             -0.108,  1.246,  1.596, -0.724, -0.624,  0.93 ,  0.586,  1.005,
              2.404,  2.749,  0.991,  1.292, -1.594,  1.358, -1.738,  1.452,
             -1.301,  1.265,  2.56 , -1.156, -0.358,  0.554,  1.789, -0.211,
              1.943, -1.454,  2.602, -1.16 , -0.693,  0.807,  0.782, -2.044,
             -1.605, -0.597,  0.877, -0.576, -1.589,  1.593,  2.436, -2.104,
             -0.403,  2.408,  1.876, -1.076,  0.336,  2.184, -1.327, -1.258,
             -0.339,  0.773,  0.917, -1.255, -0.191, -0.065,  1.69 , -0.088,
              0.148,  1.583, -1.48 , -1.374, -0.012,  0.733,  1.432, -0.946,
             -0.163,  2.124,  2.411, -1.002, -0.82 ,  1.422, -1.689, -0.879,
             -0.258,  0.257,  1.506,  1.489, -1.456, -1.204,  0.31 ,  0.816,
              1.766, -0.766, -0.187,  0.658,  2.261,  2.375, -1.018, -0.708,
              0.922,  1.291,  1.939, -1.619, -0.796, -0.458,  0.384,  1.491,
              1.448, -1.425, -0.983,  0.606,  0.894,  2.045, -0.596, -0.254,
              0.925,  2.317,  2.347, -1.059, -0.555,  1.063,  1.172,  1.933,
             -1.539, -0.731, -0.626,  0.514,  1.436,  1.461, -1.382, -0.731,
              0.843,  1.003, -0.451, -0.293,  1.174,  2.317,  2.337, -1.097,
             -0.371,  1.13 ,  1.101, -2.014,  1.911, -1.474, -0.699, -0.716,
              0.65 ,  1.356, -1.313, -0.468,  1.004,  1.163, -0.347, -0.257,
              1.405,  2.277, -1.301, -1.113, -0.179, -2.088, -1.433, -0.734,
             -0.71 ,  0.787,  1.291, -1.221, -0.203,  1.078,  1.367])
    • ebb_flow
      (time)
      object
      'Ebb' 'Ebb' 'Ebb' ... 'Ebb' 'Ebb'
      array(['Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb', 'Ebb',
             'Ebb', 'Ebb', 'Ebb'], dtype=object)
  • crs :
    EPSG:32755
    grid_mapping :
    spatial_ref

Evaluating observed vs. all modelled tide heights

The complex behaviour of tides mean that a sun synchronous sensor like Landsat does not observe the full range of the tidal cycle at all locations. Biases in the proportion of the tidal range observed by satellites can prevent us from obtaining data on areas of the coastline exposed or inundated at the extremes of the tidal range. This can risk gaining misleading insights into the true extent of the area of the coastline affected by tides, and make it difficult to compare high or low tide images fairly in different locations.

The tidal_stats function can assist in evaluating how the range of tides observed by satellites compare to the full tidal range. It works by using the OTPS tidal model to model tide heights at a regular interval (every two hours by default) across the entire time period covered by the input satelliter timeseries dataset. This is then compared against the tide heights in observed by the satellite and used to calculate a range of statistics and a plot that summarises potential biases in the data.

For a more detailed discussion of the issue of tidal bias in sun-synchronous satellite observations of the coastline, refer to the ‘Limitations and future work’ section in Bishop-Taylor et al. 2018.

[14]:
out_stats = tidal_stats(ds)
Setting tide modelling location from dataset centroid: 149.47, -21.78

82% of the full 6.80 m modelled tidal range is observed at this location.
The lowest 13% and highest 6% of tides are never observed.

Observed tides do not increase or decrease significantly over the ~32 year period.
All tides do not increase or decrease significantly over the ~32 year period.
../../_images/notebooks_Frequently_used_code_Tidal_modelling_30_1.png

The function also outputs a pandas.Series object containing a set of statistics that compare the observed vs. full modelled tidal ranges. These statistics include:

  • tidepost_lat: latitude used for modelling tide heights

  • tidepost_lon: longitude used for modelling tide heights

  • observed_min_m: minimum tide height observed by the satellite (in metre units)

  • all_min_m: minimum tide height from full modelled tidal range (in metre units)

  • observed_max_m: maximum tide height observed by the satellite (in metre units)

  • all_max_m: maximum tide height from full modelled tidal range (in metre units)

  • observed_range_m: tidal range observed by the satellite (in metre units)

  • all_range_m: full modelled tidal range (in metre units)

  • spread_m: proportion of the full modelled tidal range observed by the satellite (see Bishop-Taylor et al. 2018)

  • low_tide_offset: proportion of the lowest tides never observed by the satellite (see Bishop-Taylor et al. 2018)

  • high_tide_offset: proportion of the highest tides never observed by the satellite (see Bishop-Taylor et al. 2018)

  • observed_slope: slope of any relationship between observed tide heights and time

  • all_slope: slope of any relationship between all modelled tide heights and time

  • observed_pval: significance/p-value of any relationship between observed tide heights and time

  • all_pval: significance/p-value of any relationship between all modelled tide heights and time

[15]:
print(out_stats)
tidepost_lat        -21.780
tidepost_lon        149.465
observed_mean_m       0.263
all_mean_m           -0.000
observed_min_m       -2.292
all_min_m            -3.171
observed_max_m        3.253
all_max_m             3.629
observed_range_m      5.545
all_range_m           6.800
spread                0.815
low_tide_offset       0.129
high_tide_offset      0.055
observed_slope        0.003
all_slope            -0.000
observed_pval         0.597
all_pval              0.388
dtype: float64

Additional information

License: The code in this notebook is licensed under the Apache License, Version 2.0. Digital Earth Australia data is licensed under the Creative Commons by Attribution 4.0 license.

Contact: If you need assistance, please post a question on the Open Data Cube Slack channel or on the GIS Stack Exchange using the open-data-cube tag (you can view previously asked questions here). If you would like to report an issue with this notebook, you can file one on Github.

Last modified: June 2020

Compatible datacube version:

[16]:
print(datacube.__version__)
1.8.0

Tags

Browse all available tags on the DEA User Guide’s Tags Index

Tags: sandbox compatible, NCI compatible, landsat 5, landsat 7, landsat 8, dea_coastaltools, dea_datahandling, dea_plotting, display_map, load_ard, rgb, tidal_tag, tidal_stats, tide modelling, intertidal, Dask, lazy loading, rolling window