Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script to get SNOs for two platforms #51

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ dist
build
eggs
parts
bin
var
sdist
develop-eggs
Expand Down
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
exclude: '^$'
fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.2.3
hooks:
- id: flake8
additional_dependencies: [flake8-docstrings, flake8-debugger, flake8-bugbear]
171 changes: 171 additions & 0 deletions bin/get_snos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2014 - 2019 Adam.Dybbroe

# Author(s):

# Adam.Dybbroe <[email protected]>
# Nina Håkansson <[email protected]>
# Erik Johansson <[email protected]>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Getting SNOs for two configurable satellite platforms.

SNO = Simultaneous Nadir Overpass: When two platforms sub-satellite track nadir
views cross each other in space and time. One can set a threshold in time
allowing the times to differ by up to a few minutes.

"""

import sys
from datetime import datetime, timedelta

from pyorbital.orbital import Orbital
from pyorbital.sno_utils import get_config
from pyorbital.sno_utils import get_arc
from pyorbital.sno_utils import get_tle
from pyorbital.sno_utils import get_sno_point
import logging

LOG = logging.getLogger('snos')

handler = logging.StreamHandler(sys.stderr)
handler.setLevel(0)
LOG.setLevel(0)
LOG.addHandler(handler)


def get_arguments():
"""Get the comman line arguments required to run the script."""
import argparse

parser = argparse.ArgumentParser(description='Calculate SNOS between two satellite platforms')
parser.add_argument("-s", "--start-datetime",
required=True,
dest="start_datetime",
type=str,
default=None,
help="The datetime string corresponding to the start time of when SNOS should be calculated")
parser.add_argument("-e", "--end-datetime",
required=True,
dest="end_datetime",
type=str,
default=None,
help="The datetime string corresponding to the end time of when SNOS should be calculated")
parser.add_argument("-t", "--time-window",
required=True,
dest="time_window",
type=str,
default=None,
help=("The time window in number of minutes - the maximum time allowed between " +
"the two SNO observations"))
parser.add_argument("-p", "--platform-name",
required=True,
dest="platform_name",
type=str,
default=None,
help="The name of the satellite platform")
parser.add_argument("-c", "--configfile",
required=True,
dest="configfile",
type=str,
default=None,
help="The path to the configuration file")
parser.add_argument("-l", "--log-file", dest="log",
type=str,
default=None,
help="The file to log to (stdout per default).")

args = parser.parse_args()
return args


def main():
"""Find SNOs for the two platforms within the time period given."""
args = get_arguments()
conf = get_config(args.configfile)

station = {}
station['lon'] = conf['station']['longitude']
station['lat'] = conf['station']['latitude']
station['alt'] = conf['station']['altitude']

ref_platform_name = conf['reference_platform']['name']

tle_dirs = conf['tle-dirs']
tle_file_format = conf['tle-file-format']
platform_id = args.platform_name
minthr = int(args.time_window)
time_start = datetime.strptime(args.start_datetime, "%Y%m%d")
time_end = datetime.strptime(args.end_datetime, "%Y%m%d")

dtime = timedelta(seconds=60 * minthr * 2.0)
timestep = timedelta(seconds=60 * minthr * 1.0)
delta_t = dtime

tobj = time_start
tle_ref_pltfrm = None
tle_cmp_platform = None
tobj_tmp = time_start
while tobj < time_end:
if not tle_ref_pltfrm or abs(tle_ref_pltfrm.epoch.astype(datetime) - tobj) > timedelta(days=1):
tle_ref_pltfrm = get_tle(tle_dirs, tle_file_format, ref_platform_name, tobj)
if (not tle_cmp_platform or
abs(tle_cmp_platform.epoch.astype(datetime) - tobj) > timedelta(days=2)):
tle_cmp_platform = get_tle(tle_dirs, tle_file_format, platform_id, tobj)

ref_pltfrm = Orbital(ref_platform_name,
line1=tle_ref_pltfrm.line1,
line2=tle_ref_pltfrm.line2)
cmp_platform = Orbital(platform_id,
line1=tle_cmp_platform.line1,
line2=tle_cmp_platform.line2)

arc_ref_pltfrm = get_arc(tobj, timestep, ref_pltfrm)
arc_cmp_platform = get_arc(tobj, timestep, cmp_platform)

if arc_ref_pltfrm and arc_cmp_platform:
if arc_ref_pltfrm.intersects(arc_cmp_platform):
# If the two sub-satellite tracks of the overpasses intersects
# get the sub-satellite position and time where they cross,
# and determine if the time deviation is smaller than the require threshold:
sno = get_sno_point(platform_id, cmp_platform, ref_pltfrm,
tobj, delta_t, arc_ref_pltfrm,
arc_cmp_platform, station, minthr)

if sno:
print(" " +
str(sno['maxt_ref_pltfrm'].strftime("%Y-%m-%d %H:%M, ")) +
"%5.1f," % sno['ref_pltfrmsec'] + " "*5 +
str(sno['maxt'].strftime("%Y-%m-%d %H:%M, ")) +
"%5.1f," % sno['sec'] +
# " imager-orbit, %d, " % (sno['orbit_nr'] + 1) +
" %d, " % (sno['orbit_nr'] + 1) +
" "*6 + "%7.2f, %7.2f," % (sno['point'][1], sno['point'][0]) +
" " + "%4.1f," % abs(sno['tdmin']) + " " + str(sno['is_within_antenna_horizon'])
)

else:
LOG.error("Failed getting the track-segments")

tobj = tobj + dtime
if tobj - tobj_tmp > timedelta(days=1):
tobj_tmp = tobj
LOG.debug(tobj_tmp.strftime("%Y-%m-%d"))


if __name__ == "__main__":
main()
30 changes: 30 additions & 0 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
The :mod:`pyorbital` API
=========================

Orbital computations
~~~~~~~~~~~~~~~~~~~~

.. automodule:: pyorbital.orbital
:members:
:undoc-members:

TLE handling
~~~~~~~~~~~~

.. automodule:: pyorbital.tlefile
:members:
:undoc-members:

Astronomical computations
~~~~~~~~~~~~~~~~~~~~~~~~~

.. automodule:: pyorbital.astronomy
:members:
:undoc-members:

Simultaneous Nadir Overpass computations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. automodule:: pyorbital.sno_utils
:members:
:undoc-members:
11 changes: 11 additions & 0 deletions doc/source/astronomy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Computing astronomical parameters
---------------------------------
The astronomy module enables computation of certain parameters of interest for satellite remote sensing for instance the Sun-zenith angle:

>>> from pyorbital import astronomy
>>> from datetime import datetime
>>> utc_time = datetime(2012, 5, 15, 15, 45)
>>> lon, lat = 12, 56
>>> astronomy.sun_zenith_angle(utc_time, lon, lat)
62.685986438071602

126 changes: 18 additions & 108 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,117 +3,27 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

Pyorbital
=========
====================================
Welcome to Pyorbital's documentation
====================================

Pyorbital is a python package to compute orbital parameters for satellites from
TLE files as well as astronomical parameters of interest for satellite remote sensing.
Currently pyorbital only supports low earth orbit satellites.

Installation
------------
Pyorbital comes with a file platforms.txt that maps satellite name to NORAD identifier.
This file needs to be copied to the appropriate satpy etc directory ($PPP_CONFIG_DIR).
It is wise to check it contains your satellites of interest. The NORAD identifier can
be found as the first number of each line in the Two-Line Elements (eg. from celestrak).

TLE files
---------
Pyorbital has a module for parsing NORAD TLE-files

>>> from pyorbital import tlefile
>>> tle = tlefile.read('noaa 18', '/path/to/my/tle_file.txt')
>>> tle.inclination
99.043499999999995

If no path is given pyorbital tries to read the earth observation TLE-files from celestrak.com

Computing satellite position
----------------------------
The orbital module enables computation of satellite position and velocity at a specific time:

>>> from pyorbital.orbital import Orbital
>>> from datetime import datetime
>>> # Use current TLEs from the internet:
>>> orb = Orbital("Suomi NPP")
>>> now = datetime.utcnow()
>>> # Get normalized position and velocity of the satellite:
>>> orb.get_position(now)
(array([-0.20015267, 0.09001458, 1.10686756]),
array([ 0.06148495, 0.03234914, 0.00846805]))
>>> # Get longitude, latitude and altitude of the satellite:
>>> orb.get_lonlatalt(now)
(40.374855865574951, 78.849923885700363, 839.62504115338368)


Use actual TLEs to increase accuracy
------------------------------------

>>> from pyorbital.orbital import Orbital
>>> from datetime import datetime
>>> orb = Orbital("Suomi NPP")
>>> dtobj = datetime(2015,2,7,3,0)
>>> orb.get_lonlatalt(dtobj)
(152.11564698762811, 20.475251739329622, 829.37355785502211)

But since we are interested in knowing the position of the Suomi-NPP more than
two and half years from now (September 26, 2017) we can not rely on the current
TLEs, but rather need a TLE closer to the time of interest:

>>> snpp = Orbital('Suomi NPP', tle_file='/data/lang/satellit/polar/orbital_elements/TLE/201502/tle-20150207.txt')
>>> snpp.get_lonlatalt(dtobj)
(105.37373804512762, 79.160752404540133, 838.94605490133154)

If we take a TLE from one week earlier we get a slightly different result:

>>> snpp = Orbital('Suomi NPP', tle_file='/data/lang/satellit/polar/orbital_elements/TLE/201501/tle-20150131.txt')
>>> snpp.get_lonlatalt(dtobj)
(104.1539184988462, 79.328272480878141, 838.81555967963391)



Computing astronomical parameters
---------------------------------
The astronomy module enables computation of certain parameters of interest for satellite remote sensing for instance the Sun-zenith angle:

>>> from pyorbital import astronomy
>>> from datetime import datetime
>>> utc_time = datetime(2012, 5, 15, 15, 45)
>>> lon, lat = 12, 56
>>> astronomy.sun_zenith_angle(utc_time, lon, lat)
62.685986438071602

API
---

Orbital computations
~~~~~~~~~~~~~~~~~~~~

.. automodule:: pyorbital.orbital
:members:
:undoc-members:

TLE handling
~~~~~~~~~~~~

.. automodule:: pyorbital.tlefile
:members:
:undoc-members:

Astronomical computations
~~~~~~~~~~~~~~~~~~~~~~~~~

.. automodule:: pyorbital.astronomy
:members:
:undoc-members:


.. Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. toctree::
:maxdepth: 2

install
tlefiles
sat_position
astronomy
snos
api

Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

Loading