[pyorbital] 01/02: Imported Upstream version 0.3.2
Antonio Valentino
a_valentino-guest at moszumanska.debian.org
Sun Jun 22 08:56:47 UTC 2014
This is an automated email from the git hooks/post-receive script.
a_valentino-guest pushed a commit to branch master
in repository pyorbital.
commit f8a2e436492cdbe445efca076b60cc4eb39630e9
Author: Antonio Valentino <antonio.valentino at tiscali.it>
Date: Sun Jun 22 08:55:45 2014 +0000
Imported Upstream version 0.3.2
---
.gitignore | 42 ++
.travis.yml | 17 +
LICENSE.txt | 674 ++++++++++++++++++++++++
MANIFEST.in | 5 +
README | 5 +
doc/Makefile | 130 +++++
doc/source/conf.py | 219 ++++++++
doc/source/index.rst | 84 +++
pyorbital/__init__.py | 0
pyorbital/astronomy.py | 200 ++++++++
pyorbital/geoloc.py | 296 +++++++++++
pyorbital/geoloc_example.py | 79 +++
pyorbital/geoloc_instrument_definitions.py | 187 +++++++
pyorbital/orbital.py | 789 +++++++++++++++++++++++++++++
pyorbital/tests/SGP4-VER.TLE | 110 ++++
pyorbital/tests/__init__.py | 46 ++
pyorbital/tests/aiaa_results | 548 ++++++++++++++++++++
pyorbital/tests/test_aiaa.py | 147 ++++++
pyorbital/tests/test_astronomy.py | 65 +++
pyorbital/tests/test_geoloc.py | 170 +++++++
pyorbital/tests/test_orbital.py | 110 ++++
pyorbital/tests/test_tlefile.py | 102 ++++
pyorbital/tlefile.py | 162 ++++++
pyorbital/version.py | 30 ++
setup.py | 48 ++
25 files changed, 4265 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e5bea2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,42 @@
+*.py[~cod]
+
+# emacs
+*~
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+__pycache__
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# rope
+.ropeproject
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e312646
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,17 @@
+language: python
+python:
+- '2.6'
+- '2.7'
+install:
+- pip install .
+- pip install coveralls
+script: coverage run --source=pyorbital setup.py test
+after_success: coveralls
+deploy:
+ provider: pypi
+ user: Martin.Raspaud
+ password:
+ secure: P3WiHVzDAJyZmiIfSF3PhY7Xqp3P3pSHhogla8u3KOw4Sy5Ye6IWwMX1+pupAyhdXgo8ZgGT4+wOn9dBejaLEA0RGIRLMHXd1QxP9BbPD5te/k5aTpzHILx786g5R6G4yw/8s/sftQC6lJT+0jJd2OJjQJsnNUJJTG8OC2uwq3Y=
+ on:
+ tags: true
+ repo: mraspaud/pyorbital
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..367a290
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
+include doc/Makefile
+recursive-include doc/source *
+include LICENSE.txt
+include MANIFEST.in
+include README
diff --git a/README b/README
new file mode 100644
index 0000000..50d19b8
--- /dev/null
+++ b/README
@@ -0,0 +1,5 @@
+This is pyorbital, python package for computing orbital parameters from tle
+files, and making diverse astronomical computations.
+
+It is part of the pytroll project:
+http://pytroll.org
\ No newline at end of file
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..a8a1618
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyorbital.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyorbital.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/pyorbital"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyorbital"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..5a15784
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,219 @@
+# -*- coding: utf-8 -*-
+#
+# pyorbital documentation build configuration file, created by
+# sphinx-quickstart on Mon Oct 3 08:48:29 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('../../'))
+sys.path.insert(0, os.path.abspath('../../pyorbital'))
+from pyorbital.version import __version__, __major__, __minor__
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pyorbital'
+copyright = u'2012-2014, The Pytroll crew'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = "v" + ".".join([__major__, __minor__])
+# The full version, including alpha/beta/rc tags.
+release = __version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pyorbitaldoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'pyorbital.tex', u'pyorbital Documentation',
+ u'The Pytroll crew', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'pyorbital', u'pyorbital Documentation',
+ [u'The Pytroll crew'], 1)
+]
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..a330d7d
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,84 @@
+.. pyorbital documentation master file, created by
+ sphinx-quickstart on Mon Oct 3 08:48:29 2011.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Pyorbital
+=========
+
+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.
+
+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 postion
+---------------------------
+The orbital module enables computation of satellite position and velocity at a specific time:
+
+ >>> from pyorbital.orbital import Orbital
+ >>> from datetime import datetime
+ >>> orb = Orbital("noaa 18")
+ >>> now = datetime.utcnow()
+ >>> # Get normalized position and velocity of the satellite:
+ >>> orb.get_position(now)
+ ([0.57529384846822862, 0.77384005228105424, 0.59301408257897559],
+ [0.031846489698768146, 0.021287993461926374, -0.05854106186659274])
+ >>> # Get longitude, latitude and altitude of the satellite:
+ >>> orb.get_lonlatalt(now)
+ (-1.1625895579622014, 0.55402132517640568, 847.89381184656702)
+
+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`
+
diff --git a/pyorbital/__init__.py b/pyorbital/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyorbital/astronomy.py b/pyorbital/astronomy.py
new file mode 100644
index 0000000..3f76efb
--- /dev/null
+++ b/pyorbital/astronomy.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011, 2013
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Astronomy module.
+Parts taken from http://www.geoastro.de/elevaz/basics/index.htm
+"""
+
+import datetime
+import numpy as np
+
+
+F = 1 / 298.257223563 # Earth flattening WGS-84
+A = 6378.137 # WGS84 Equatorial radius
+MFACTOR = 7.292115E-5
+
+def jdays2000(utc_time):
+ """Get the days since year 2000.
+ """
+ return _days(utc_time - datetime.datetime(2000, 1, 1, 12, 0))
+
+
+def jdays(utc_time):
+ """Get the julian day of *utc_time*.
+ """
+ return jdays2000(utc_time) + 2451545
+
+def _fdays(dt):
+ """Get the days (floating point) from *d_t*.
+ """
+ return (dt.days +
+ (dt.seconds +
+ dt.microseconds / (1000000.0)) / (24 * 3600.0))
+
+_vdays = np.vectorize(_fdays)
+
+def _days(dt):
+ """Get the days (floating point) from *d_t*.
+ """
+ try:
+ return _fdays(dt)
+ except AttributeError:
+ return _vdays(dt)
+
+
+def gmst(utc_time):
+ """Greenwich mean sidereal utc_time, in radians.
+
+ As defined in the AIAA 2006 implementation:
+ http://www.celestrak.com/publications/AIAA/2006-6753/
+ """
+ ut1 = jdays2000(utc_time) / 36525.0
+ theta = 67310.54841 + ut1 * (876600 * 3600 + 8640184.812866 + ut1 *
+ (0.093104 - ut1 * 6.2 * 10e-6))
+ return np.deg2rad(theta / 240.0) % (2 * np.pi)
+
+
+def _lmst(utc_time, longitude):
+ """Local mean sidereal time, computed from *utc_time* and *longitude*.
+ In radians.
+ """
+ return gmst(utc_time) + longitude
+
+
+def sun_ecliptic_longitude(utc_time):
+ """Ecliptic longitude of the sun at *utc_time*.
+ """
+ jdate = jdays2000(utc_time) / 36525.0
+ # mean anomaly, rad
+ m_a = np.deg2rad(357.52910 +
+ 35999.05030*jdate -
+ 0.0001559*jdate*jdate -
+ 0.00000048*jdate*jdate*jdate)
+ # mean longitude, deg
+ l_0 = 280.46645 + 36000.76983*jdate + 0.0003032*jdate*jdate
+ d_l = ((1.914600 - 0.004817*jdate - 0.000014*jdate*jdate)*np.sin(m_a) +
+ (0.019993 - 0.000101*jdate)*np.sin(2*m_a) + 0.000290*np.sin(3*m_a))
+ # true longitude, deg
+ l__ = l_0 + d_l
+ return np.deg2rad(l__)
+
+def sun_ra_dec(utc_time):
+ """Right ascension and declination of the sun at *utc_time*.
+ """
+ jdate = jdays2000(utc_time) / 36525.0
+ eps = np.deg2rad(23.0 + 26.0/60.0 + 21.448/3600.0 -
+ (46.8150*jdate + 0.00059*jdate*jdate -
+ 0.001813*jdate*jdate*jdate) / 3600)
+ eclon = sun_ecliptic_longitude(utc_time)
+ x__ = np.cos(eclon)
+ y__ = np.cos(eps) * np.sin(eclon)
+ z__ = np.sin(eps) * np.sin(eclon)
+ r__ = np.sqrt(1.0 - z__ * z__)
+ # sun declination
+ declination = np.arctan2(z__, r__)
+ # right ascension
+ right_ascension = 2 * np.arctan2(y__, (x__ + r__))
+ return right_ascension, declination
+
+def _local_hour_angle(utc_time, longitude, right_ascension):
+ """Hour angle at *utc_time* for the given *longitude* and
+ *right_ascension*
+ longitude in radians
+ """
+ return _lmst(utc_time, longitude) - right_ascension
+
+def get_alt_az(utc_time, lon, lat):
+ """Return sun altitude and azimuth from *utc_time*, *lon*, and *lat*.
+ lon,lat in degrees
+ What is the unit of the returned angles and heights!? FIXME!
+ """
+ lon = np.deg2rad(lon)
+ lat = np.deg2rad(lat)
+
+ ra_, dec = sun_ra_dec(utc_time)
+ h__ = _local_hour_angle(utc_time, lon, ra_)
+ return (np.arcsin(np.sin(lat)*np.sin(dec) +
+ np.cos(lat) * np.cos(dec) * np.cos(h__)),
+ np.arctan2(-np.sin(h__), (np.cos(lat)*np.tan(dec) -
+ np.sin(lat)*np.cos(h__))))
+
+def cos_zen(utc_time, lon, lat):
+ """Cosine of the sun-zenith angle for *lon*, *lat* at *utc_time*.
+ utc_time: datetime.datetime instance of the UTC time
+ lon and lat in degrees.
+ """
+ lon = np.deg2rad(lon)
+ lat = np.deg2rad(lat)
+
+ r_a, dec = sun_ra_dec(utc_time)
+ h__ = _local_hour_angle(utc_time, lon, r_a)
+ return (np.sin(lat)*np.sin(dec) + np.cos(lat) * np.cos(dec) * np.cos(h__))
+
+def sun_zenith_angle(utc_time, lon, lat):
+ """Sun-zenith angle for *lon*, *lat* at *utc_time*.
+ lon,lat in degrees.
+ The angle returned is given in degrees
+ """
+ return np.rad2deg(np.arccos(cos_zen(utc_time, lon, lat)))
+
+def sun_earth_distance_correction(utc_time):
+ """Calculate the sun earth distance correction, relative to 1 AU.
+ """
+ year = 365.256363004
+ # This is computed from
+ # http://curious.astro.cornell.edu/question.php?number=582
+ # AU = 149597870700.0
+ # a = 149598261000.0
+ # theta = (jdays2000(utc_time) - 2) * (2 * np.pi) / year
+ # e = 0.01671123
+ # r = a*(1-e*e)/(1+e * np.cos(theta))
+ # corr_me = (r / AU) ** 2
+
+ # from known software.
+ corr = 1 - 0.0334 * np.cos(2 * np.pi * (jdays2000(utc_time) - 2) / year)
+
+ return corr
+
+def observer_position(time, lon, lat, alt):
+ """Calculate observer ECI position.
+
+ http://celestrak.com/columns/v02n03/
+ """
+
+ lon = np.deg2rad(lon)
+ lat = np.deg2rad(lat)
+
+ theta = (gmst(time) + lon) % (2 * np.pi)
+ c = 1 / np.sqrt(1 + F * (F - 2) * np.sin(lat)**2)
+ sq = c * (1 - F)**2
+
+ achcp = (A * c + alt) * np.cos(lat)
+ x = achcp * np.cos(theta) # kilometers
+ y = achcp * np.sin(theta)
+ z = (A * sq + alt) * np.sin(lat)
+
+ vx = -MFACTOR*y # kilometers/second
+ vy = MFACTOR*x
+ vz = 0
+
+ return (x, y, z), (vx, vy, vz)
+
diff --git a/pyorbital/geoloc.py b/pyorbital/geoloc.py
new file mode 100644
index 0000000..c543e6a
--- /dev/null
+++ b/pyorbital/geoloc.py
@@ -0,0 +1,296 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011, 2012, 2013, 2014.
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Module to compute geolocalization of a satellite scene.
+"""
+
+# TODO:
+# - Attitude correction
+# - project on an ellipsoid instead of a sphere
+# - optimize !!!
+# - test !!!
+
+import numpy as np
+from numpy import cos, sin, sqrt
+from datetime import timedelta
+from pyorbital.orbital import Orbital
+
+a = 6378.137 # km
+b = 6356.75231414 # km, GRS80
+#b = 6356.752314245 # km, WGS84
+
+def geodetic_lat(point, a=a, b=b):
+
+ x, y, z = point
+ r = np.sqrt(x*x + y*y)
+ geoc_lat = np.arctan2(z, r)
+
+ geod_lat = geoc_lat
+ e2 = (a*a - b*b) / (a*a)
+ while True:
+ phi = geod_lat
+ C = 1 / sqrt(1 - e2 * sin(phi)**2)
+ geod_lat = np.arctan2(z + a*C*e2 * sin(phi), r)
+ if np.allclose(geod_lat, phi):
+ return geod_lat
+
+
+def subpoint(query_point, a=a, b=b):
+ """Get the point on the ellipsoid under the *query_point*.
+ """
+ x, y, z = query_point
+ r = sqrt(x*x + y*y)
+
+ lat = geodetic_lat(query_point)
+ lon = np.arctan2(y, x)
+ e2_ = (a*a - b*b) / (a*a)
+ n__ = a / sqrt(1 - e2_ * sin(lat)**2)
+ nx_ = n__ * cos(lat) * cos(lon)
+ ny_ = n__ * cos(lat) * sin(lon)
+ nz_ = (1-e2_) * n__ * sin(lat)
+
+ return np.vstack([nx_, ny_, nz_])
+
+
+class ScanGeometry(object):
+ """Description of the geometry of an instrument.
+
+ *fovs* is the x and y viewing angles of the instrument. y is zero if the we
+ talk about scanlines of course. *times* is the time of viewing of each
+ angle relative to the start of the scanning, so it should have the same
+ size as the *fovs*. *attitude* is the attitude correction to apply.
+ """
+
+ def __init__(self,
+ fovs,
+ times,
+ attitude=(0, 0, 0)):
+ self.fovs = np.array(fovs)
+ self._times = np.array(times)
+ self.attitude = attitude
+
+ def vectors(self, pos, vel, roll=0.0, pitch=0.0, yaw=0.0):
+ """Get unit vectors pointing to the different pixels.
+
+ *pos* and *vel* are column vectors, or matrices of column
+ vectors. Returns vectors as stacked rows.
+ """
+ # TODO: yaw steering mode !
+
+
+ # Fake nadir: This is the intersection point between the satellite
+ # looking down at the centre of the ellipsoid and the surface of the
+ # ellipsoid. Nadir on the other hand is the point which vertical goes
+ # through the satellite...
+ #nadir = -pos / vnorm(pos)
+
+ nadir = subpoint(-pos)
+ nadir /= vnorm(nadir)
+
+ # x is along track (roll)
+ x = vel / vnorm(vel)
+
+ # y is cross track (pitch)
+ y = np.cross(nadir, vel, 0, 0, 0)
+ y /= vnorm(y)
+
+ # rotate first around x
+ x_rotated = qrotate(nadir, x, self.fovs[:, 0] + roll)
+ # then around y
+ xy_rotated = qrotate(x_rotated, y, self.fovs[:, 1] + pitch)
+ # then around z
+ return qrotate(xy_rotated, nadir, yaw)
+
+ def times(self, start_of_scan):
+ tds = [timedelta(seconds=i) for i in self._times]
+ return np.array(tds) + start_of_scan
+
+class Quaternion(object):
+
+ def __init__(self, scalar, vector):
+ self.__x, self.__y, self.__z = vector
+ self.__w = scalar
+
+ def rotation_matrix(self):
+ x, y, z, w = self.__x, self.__y, self.__z, self.__w
+ zero = np.zeros_like(x)
+ return np.array(
+ ((w**2 + x**2 - y**2 - z**2,
+ 2*x*y + 2*z*w,
+ 2*x*z - 2*y*w,
+ zero),
+ (2*x*y - 2*z*w,
+ w**2 - x**2 + y**2 - z**2,
+ 2*y*z + 2*x*w,
+ zero),
+ (2*x*z + 2*y*w,
+ 2*y*z - 2*x*w,
+ w**2 - x**2 - y**2 + z**2,
+ zero),
+ (zero, zero, zero, w**2 + x**2 + y**2 + z**2)))
+
+def qrotate(vector, axis, angle):
+ """Rotate *vector* around *axis* by *angle* (in radians).
+
+ *vector* is a matrix of column vectors, as is *axis*.
+ This function uses quaternion rotation.
+ """
+ n_axis = axis / vnorm(axis)
+ sin_angle = np.expand_dims(sin(angle/2), 0)
+ if np.rank(n_axis)==1:
+ n_axis = np.expand_dims(n_axis, 1)
+ p__ = np.dot(n_axis, sin_angle)[:, np.newaxis]
+ else:
+ p__ = n_axis * sin_angle
+
+ q__ = Quaternion(cos(angle/2), p__)
+ return np.einsum("kj, ikj->ij",
+ vector,
+ q__.rotation_matrix()[:3, :3])
+
+
+
+### DIRTY STUFF. Needed the get_lonlatalt function to work on pos directly if
+### we want to print out lonlats in the end.
+from pyorbital import astronomy
+from pyorbital.orbital import *
+
+def get_lonlatalt(pos, utc_time):
+ """Calculate sublon, sublat and altitude of satellite, considering the
+ earth an ellipsoid.
+
+ http://celestrak.com/columns/v02n03/
+ """
+ (pos_x, pos_y, pos_z) = pos / XKMPER
+ lon = ((np.arctan2(pos_y * XKMPER, pos_x * XKMPER) - astronomy.gmst(utc_time))
+ % (2 * np.pi))
+
+ lon = np.where(lon > np.pi, lon - np.pi * 2, lon)
+ lon = np.where(lon <= -np.pi, lon + np.pi *2, lon)
+
+ r = np.sqrt(pos_x ** 2 + pos_y ** 2)
+ lat = np.arctan2(pos_z, r)
+ e2 = F * (2 - F)
+
+ while True:
+ lat2 = lat
+ c = 1/(np.sqrt(1 - e2 * (np.sin(lat2) ** 2)))
+ lat = np.arctan2(pos_z + c * e2 *np.sin(lat2), r)
+ if np.all(abs(lat - lat2) < 1e-10):
+ break
+ alt = r / np.cos(lat)- c
+ alt *= A
+ return np.rad2deg(lon), np.rad2deg(lat), alt
+
+### END OF DIRTY STUFF
+def compute_pixels((tle1, tle2), sgeom, times, rpy=(0.0, 0.0, 0.0)):
+ """Compute cartesian coordinates of the pixels in instrument scan.
+ """
+ orb = Orbital("mysatellite", line1=tle1, line2=tle2)
+
+ # get position and velocity for each time of each pixel
+ pos, vel = orb.get_position(times, normalize=False)
+
+ # now, get the vectors pointing to each pixel
+ vectors = sgeom.vectors(pos, vel, *rpy)
+
+ ## compute intersection of lines (directed by vectors and passing through
+ ## (0, 0, 0)) and ellipsoid. Derived from:
+ ## http://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
+
+
+ # do the computation between line and ellipsoid (WGS 84)
+ # NB: AAPP uses GRS 80...
+ centre = -pos
+ a__ = 6378.137 # km
+ #b__ = 6356.75231414 # km, GRS80
+ b__ = 6356.752314245 # km, WGS84
+ radius = np.array([[1/a__, 1/a__, 1/b__]]).T
+ xr_ = vectors * radius
+ cr_ = centre * radius
+ ldotc = np.einsum("ij,ij->j", xr_, cr_)
+ lsq = np.einsum("ij,ij->j", xr_, xr_)
+ csq = np.einsum("ij,ij->j", cr_, cr_)
+
+ d1_ = (ldotc - np.sqrt(ldotc ** 2 - csq * lsq + lsq)) / lsq
+
+
+ # return the actual pixel positions
+ return vectors * d1_ - centre
+
+
+def norm(v):
+ return np.sqrt(np.dot(v, v.conj()))
+
+def mnorm(m, axis=None):
+ """norm of a matrix of vectors stacked along the *axis* dimension.
+ """
+ if axis is None:
+ axis = np.rank(m) - 1
+ return np.sqrt((m**2).sum(axis))
+
+def vnorm(m):
+ """norms of a matrix of column vectors.
+ """
+ return np.sqrt((m**2).sum(0))
+def hnorm(m):
+ """norms of a matrix of row vectors.
+ """
+ return np.sqrt((m**2).sum(1))
+
+if __name__ == '__main__':
+ #NOAA 18 (from the 2011-10-12, 16:55 utc)
+ #1 28654U 05018A 11284.35271227 .00000478 00000-0 28778-3 0 9246
+ #2 28654 99.0096 235.8581 0014859 135.4286 224.8087 14.11526826329313
+
+
+ noaa18_tle1 = "1 28654U 05018A 11284.35271227 .00000478 00000-0 28778-3 0 9246"
+ noaa18_tle2 = "2 28654 99.0096 235.8581 0014859 135.4286 224.8087 14.11526826329313"
+
+ from datetime import datetime
+ t = datetime(2011, 10, 12, 13, 45)
+
+ ## edge and centre of an avhrr scanline
+ #sgeom = ScanGeometry([(-0.9664123687741623, 0),
+ # (0, 0)],
+ # [0, 0.0, ])
+ #print compute_pixels((noaa18_tle1, noaa18_tle2), sgeom, t)
+
+
+ ## avhrr swath
+ scanline_nb = 1
+
+ # building the avhrr angles, 2048 pixels from +55.37 to -55.37 degrees
+ avhrr = np.vstack(((np.arange(2048) - 1023.5) / 1024 * np.deg2rad(-55.37),
+ np.zeros((2048,)))).transpose()
+ avhrr = np.tile(avhrr, [scanline_nb, 1])
+ # building the corresponding times array
+ offset = np.arange(scanline_nb) * 0.1667
+ times = (np.tile(np.arange(2048) * 0.000025 + 0.0025415, [scanline_nb, 1])
+ + np.expand_dims(offset, 1))
+ # build the scan geometry object
+ sgeom = ScanGeometry(avhrr, times.ravel())
+
+ # print the lonlats for the pixel positions
+ s_times = sgeom.times(t)
+ pixels_pos = compute_pixels((noaa18_tle1, noaa18_tle2), sgeom, s_times)
+ print get_lonlatalt(pixels_pos, s_times)
diff --git a/pyorbital/geoloc_example.py b/pyorbital/geoloc_example.py
new file mode 100644
index 0000000..1200374
--- /dev/null
+++ b/pyorbital/geoloc_example.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Simple usage for geoloc.
+"""
+
+import numpy as np
+from datetime import datetime
+from pyorbital.geoloc import ScanGeometry, compute_pixels, get_lonlatalt
+
+tle1 = "1 33591U 09005A 12345.45213434 .00000391 00000-0 24004-3 0 6113"
+tle2 = "2 33591 098.8821 283.2036 0013384 242.4835 117.4960 14.11432063197875"
+
+t = datetime(2012, 12, 12, 4, 16, 1, 575000)
+
+scanline_nb = 351
+
+# we take only every 40th point for plotting clarity
+scan_points = np.arange(24, 2048, 40)
+
+
+# build the avhrr instrument (scan angles)
+avhrr = np.vstack(((scan_points - 1023.5) / 1024 * np.deg2rad(-55.37),
+ np.zeros((len(scan_points),)))).transpose()
+avhrr = np.tile(avhrr, [scanline_nb, 1])
+
+# building the corresponding times array
+offset = np.arange(scanline_nb) * 0.1666667
+times = (np.tile(scan_points * 0.000025 + 0.0025415, [scanline_nb, 1])
+ + np.expand_dims(offset, 1))
+
+# build the scan geometry object
+sgeom = ScanGeometry(avhrr, times.ravel())
+
+# roll, pitch, yaw in radians
+rpy = (0, 0, 0)
+
+# print the lonlats for the pixel positions
+s_times = sgeom.times(t)
+pixels_pos = compute_pixels((tle1, tle2), sgeom, s_times, rpy)
+pos_time = get_lonlatalt(pixels_pos, s_times)
+
+print pos_time
+
+
+# Plot the result
+from mpl_toolkits.basemap import Basemap
+import matplotlib.pyplot as plt
+
+m = Basemap(projection='stere', llcrnrlat=24, urcrnrlat=70, llcrnrlon=-25, urcrnrlon=120, lat_ts=58, lat_0=58, lon_0=14, resolution='l')
+
+
+# convert and plot the predicted pixels in red
+x, y = m(pos_time[0], pos_time[1])
+p1 = m.plot(x,y, marker='+', color='red', markerfacecolor='red', markeredgecolor='red', markersize=1, markevery=1, zorder=4, linewidth=0.0)
+m.fillcontinents(color='0.85', lake_color=None, zorder=3)
+m.drawparallels(np.arange(-90.,90.,5.), labels=[1,0,1,0],fontsize=10, dashes=[1, 0], color=[0.8,0.8,0.8], zorder=1)
+m.drawmeridians(np.arange(-180.,180.,5.), labels=[0,1,0,1],fontsize=10, dashes=[1, 0], color=[0.8,0.8,0.8], zorder=2)
+
+plt.show()
diff --git a/pyorbital/geoloc_instrument_definitions.py b/pyorbital/geoloc_instrument_definitions.py
new file mode 100644
index 0000000..c7070c4
--- /dev/null
+++ b/pyorbital/geoloc_instrument_definitions.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013, 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+# Mikhail Itkin <itkin.m at gmail.com>
+
+# 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/>.
+
+"""Some instrument definitions to use with geoloc.
+
+To define an instrument, one must first define the scan angles (in radians)
+around x (along-track vector) and y (cross-track vector). the y scan angles are
+just 0 in the case of scanline based instruments (like avhrr), but can be
+different if the instrument is forward and/or backward scanning (e.g. viirs or
+modis).
+
+For the instrument to be defined completely, one must also provide the
+observation times (in seconds, respective to the nominal scan time) for the
+different pixels.
+
+Both scan angles and scan times are then combined into a ScanGeometry object.
+"""
+
+import numpy as np
+from pyorbital.geoloc import ScanGeometry
+
+# number of instrument scans to use.
+scans_nb = 10
+
+################################################################
+#
+# AVHRR
+#
+################################################################
+
+def avhrr(scans_nb, scan_points, scan_angle=55.37, decimate=1):
+ """Definition of the avhrr instrument.
+
+ Source: NOAA KLM User's Guide, Appendix J
+ http://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/html/j/app-j.htm
+ """
+ # build the avhrr instrument (scan angles)
+ avhrr_inst = np.vstack(((scan_points / 1023.5 - 1)
+ * np.deg2rad(-scan_angle),
+ np.zeros((len(scan_points),)))).transpose()
+ avhrr_inst = np.tile(avhrr_inst, [scans_nb, 1])
+
+ # building the corresponding times array
+ offset = np.arange(scans_nb) * decimate / 6.0
+ #times = (np.tile(scan_points * 0.000025 + 0.0025415, [scans_nb, 1])
+ # + np.expand_dims(offset, 1))
+ times = (np.tile(scan_points * 0.000025, [scans_nb, 1])
+ + np.expand_dims(offset, 1))
+
+ return ScanGeometry(avhrr_inst, times.ravel())
+
+################################################################
+#### avhrr, all pixels
+
+# we take all pixels
+scan_points = np.arange(2048)
+
+# build the scan geometry object
+avhrr_all_geom = avhrr(scans_nb, scan_points)
+
+################################################################
+#### avhrr, edge pixels
+
+# we take only edge pixels
+scan_points = np.array([0, 2047])
+
+
+# build the scan geometry object
+avhrr_edge_geom = avhrr(scans_nb, scan_points)
+
+################################################################
+#### avhrr, every 40th pixel from the 24th (aapp style)
+
+# we take only every 40th pixel
+scan_points = np.arange(24, 2048, 40)
+
+# build the scan geometry object
+avhrr_40_geom = avhrr(scans_nb, scan_points)
+
+################################################################
+#
+# VIIRS
+#
+################################################################
+
+def viirs(scans_nb, scan_indices=slice(0, None)):
+ """Describe VIIRS instrument geometry, I-band.
+
+ """
+
+ entire_width = np.arange(6400)
+ scan_points = entire_width[scan_indices]
+
+ across_track = (scan_points / 3199.5 - 1) * np.deg2rad(-55.84)
+ y_max_angle = np.arctan2(11.87/2, 824.0)
+ along_track = np.array([-y_max_angle, 0, y_max_angle])
+
+ scan_pixels = len(scan_points)
+
+ scan = np.vstack((np.tile(across_track, scan_pixels),
+ np.repeat(along_track, 6400))).T
+
+ npp = np.tile(scan, [scans_nb, 1])
+
+ # from the timestamp in the filenames, a granule takes 1:25.400 to record
+ # (85.4 seconds) so 1.779166667 would be the duration of 1 scanline
+ # dividing the duration of a single scan by a width of 6400 pixels results
+ # in 0.0002779947917 seconds for each column of 32 pixels in the scanline
+
+ # the individual times per pixel are probably wrong, unless the scanning
+ # behaves the same as for AVHRR, The VIIRS sensor rotates to allow internal
+ # calibration before each scanline. This would imply that the scanline
+ # always moves in the same direction. more info @
+ # http://www.eoportal.org/directory/pres_NPOESSNationalPolarorbitingOperationalEnvironmentalSatelliteSystem.html
+
+ offset = np.arange(scans_nb) * 1.779166667
+ times = (np.tile(scan_points * 0.0002779947917, [scans_nb, scan_pixels])
+ + np.expand_dims(offset, 1))
+
+ # build the scan geometry object
+ return ScanGeometry(npp, times.ravel())
+
+
+################################################################
+#
+# AMSU-A
+#
+################################################################
+
+def amsua(scans_nb, edges_only=False):
+ """ Describe AMSU-A instrument geometry
+
+ Parameters:
+ scans_nb | int - number of scan lines
+
+ Keywords:
+ * edges_only - use only edge pixels
+
+ Returns:
+ pyorbital.geoloc.ScanGeometry object
+
+ """
+
+ scan_len = 30 # 30 samples per scan
+ scan_rate = 8 # single scan, seconds
+ scan_angle = -48.3 # swath, degrees
+ sampling_interval = 0.2 # single view, seconds
+ sync_time = 0.00355 # delay before the actual scan starts
+
+ if edges_only:
+ scan_points = np.array([0, scan_len - 1])
+ else:
+ scan_points = np.arange(0, scan_len)
+
+ # build the instrument (scan angles)
+ samples = np.vstack(((scan_points / (scan_len*0.5-0.5) - 1)
+ * np.deg2rad(scan_angle),
+ np.zeros((len(scan_points),)))).transpose()
+ samples = np.tile(samples, [scans_nb, 1])
+
+ # building the corresponding times array
+ offset = np.arange(scans_nb) * scan_rate
+ times = (np.tile(scan_points * sampling_interval + sync_time, [scans_nb, 1])
+ + np.expand_dims(offset, 1))
+
+ # build the scan geometry object
+ return ScanGeometry(samples, times.ravel())
diff --git a/pyorbital/orbital.py b/pyorbital/orbital.py
new file mode 100644
index 0000000..5409579
--- /dev/null
+++ b/pyorbital/orbital.py
@@ -0,0 +1,789 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011, 2012, 2013, 2014.
+
+# Author(s):
+
+# Esben S. Nielsen <esn at dmi.dk>
+# Adam Dybbroe <adam.dybbroe at smhi.se>
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Module for computing the orbital parameters of satellites.
+"""
+
+from datetime import datetime, timedelta
+import numpy as np
+from pyorbital import tlefile
+from pyorbital import astronomy
+import warnings
+
+ECC_EPS = 1.0e-6 # Too low for computing further drops.
+ECC_LIMIT_LOW = -1.0e-3
+ECC_LIMIT_HIGH = 1.0 - ECC_EPS # Too close to 1
+ECC_ALL = 1.0e-4
+
+EPS_COS = 1.5e-12
+
+NR_EPS = 1.0e-12
+
+CK2 = 5.413080e-4
+CK4 = 0.62098875e-6
+E6A = 1.0e-6
+QOMS2T = 1.88027916e-9
+S = 1.01222928
+S0 = 78.0
+XJ3 = -0.253881e-5
+XKE = 0.743669161e-1
+XKMPER = 6378.135
+XMNPDA = 1440.0
+#MFACTOR = 7.292115E-5
+AE = 1.0
+SECDAY = 8.6400E4
+
+F = 1 / 298.257223563 # Earth flattening WGS-84
+A = 6378.137 # WGS84 Equatorial radius
+
+
+SGDP4_ZERO_ECC = 0
+SGDP4_DEEP_NORM = 1
+SGDP4_NEAR_SIMP = 2
+SGDP4_NEAR_NORM = 3
+
+KS = AE * (1.0 + S0 / XKMPER)
+A3OVK2 = (-XJ3 / CK2) * AE**3
+
+class OrbitalError(Exception):
+ pass
+
+
+class Orbital(object):
+ """Class for orbital computations.
+
+ The *satellite* parameter is the name of the satellite to work on and is
+ used to retreive the right TLE data for internet or from *tle_file* in case
+ it is provided.
+ """
+
+ def __init__(self, satellite, tle_file=None, line1=None, line2=None):
+ satellite = satellite.upper()
+ self.satellite_name = satellite
+ self.tle = tlefile.read(satellite, tle_file=tle_file,
+ line1=line1, line2=line2)
+ self.orbit_elements = OrbitElements(self.tle)
+ self._sgdp4 = _SGDP4(self.orbit_elements)
+
+ def __str__(self):
+ return self.satellite_name + " " + str(self.tle)
+
+ def get_last_an_time(self, utc_time):
+ """Calculate time of last ascending node relative to the
+ specified time
+ """
+
+ # Propagate backwards to ascending node
+ dt = timedelta(minutes=10)
+ t_old = utc_time
+ t_new = t_old - dt
+ pos0, vel0 = self.get_position(t_old, normalize=False)
+ pos1, vel1 = self.get_position(t_new, normalize=False)
+ while not (pos0[2] > 0 and pos1[2] < 0):
+ pos0, vel0 = pos1, vel1
+ t_old = t_new
+ t_new = t_old - dt
+ pos1, vel1 = self.get_position(t_new, normalize=False)
+
+ # Return if z within 1 km of an
+ if np.abs(pos0[2]) < 1:
+ return t_old
+ elif np.abs(pos1[2]) < 1:
+ return t_new
+
+ # Bisect to z within 1 km
+ while np.abs(pos1[2]) > 1:
+ pos0, vel0 = pos1, vel1
+ dt = (t_old - t_new) / 2
+ t_mid = t_old - dt
+ pos1, vel1 = self.get_position(t_mid, normalize=False)
+ if pos1[2] > 0:
+ t_old = t_mid
+ else:
+ t_new = t_mid
+
+ return t_mid
+
+ def get_position(self, utc_time, normalize=True):
+ """Get the cartesian position and velocity from the satellite.
+ """
+
+ kep = self._sgdp4.propagate(utc_time)
+ pos, vel = kep2xyz(kep)
+
+ if normalize:
+ pos /= XKMPER
+ vel /= XKMPER * XMNPDA / SECDAY
+
+ return pos, vel
+
+
+ def get_lonlatalt(self, utc_time):
+ """Calculate sublon, sublat and altitude of satellite.
+ http://celestrak.com/columns/v02n03/
+ """
+ (pos_x, pos_y, pos_z), (vel_x, vel_y, vel_z) = self.get_position(utc_time, normalize=True)
+
+ lon = ((np.arctan2(pos_y * XKMPER, pos_x * XKMPER) - astronomy.gmst(utc_time))
+ % (2 * np.pi))
+
+ lon = np.where(lon > np.pi, lon - np.pi * 2, lon)
+ lon = np.where(lon <= -np.pi, lon + np.pi *2, lon)
+
+ r = np.sqrt(pos_x ** 2 + pos_y ** 2)
+ lat = np.arctan2(pos_z, r)
+ e2 = F * (2 - F)
+ while True:
+ lat2 = lat
+ c = 1/(np.sqrt(1 - e2 * (np.sin(lat2) ** 2)))
+ lat = np.arctan2(pos_z + c * e2 *np.sin(lat2), r)
+ if np.all(abs(lat - lat2) < 1e-10):
+ break
+ alt = r / np.cos(lat)- c;
+ alt *= A
+ return np.rad2deg(lon), np.rad2deg(lat), alt
+
+ def find_aos(self, utc_time, lon, lat):
+ pass
+
+ def find_aol(self, utc_time, lon, lat):
+ pass
+
+ def get_observer_look(self, utc_time, lon, lat, alt):
+ """Calculate observers look angle to a satellite.
+ http://celestrak.com/columns/v02n02/
+
+ utc_time: Observation time (datetime object)
+ lon: Longitude of observer position on ground
+ lat: Latitude of observer position on ground
+ alt: Altitude above sea-level (geoid) of observer position on ground
+
+ Return: (Azimuth, Elevation)
+ """
+ (pos_x, pos_y, pos_z), (vel_x, vel_y, vel_z) = self.get_position(utc_time, normalize=False)
+ (opos_x, opos_y, opos_z), (ovel_x, ovel_y, ovel_z) = \
+ astronomy.observer_position(utc_time, lon, lat, alt)
+
+ lon = np.deg2rad(lon)
+ lat = np.deg2rad(lat)
+
+ theta = (astronomy.gmst(utc_time) + lon) % (2 * np.pi)
+
+ rx = pos_x - opos_x
+ ry = pos_y - opos_y
+ rz = pos_z - opos_z
+
+ sin_lat = np.sin(lat)
+ cos_lat = np.cos(lat)
+ sin_theta = np.sin(theta)
+ cos_theta = np.cos(theta)
+
+ top_s = sin_lat * cos_theta * rx + sin_lat * sin_theta * ry - cos_lat * rz
+ top_e = -sin_theta * rx + cos_theta * ry
+ top_z = cos_lat * cos_theta * rx + cos_lat * sin_theta * ry + sin_lat * rz
+
+ az_ = np.arctan(-top_e / top_s)
+
+ az_ = np.where(top_s > 0, az_ + np.pi, az_)
+ az_ = np.where(az_ < 0, az_ + 2 * np.pi, az_)
+
+ rg_ = np.sqrt(rx * rx + ry * ry + rz * rz)
+ el_ = np.arcsin(top_z / rg_)
+
+ return np.rad2deg(az_), np.rad2deg(el_)
+
+ def get_orbit_number(self, utc_time, tbus_style=False):
+ """Calculate orbit number at specified time.
+ Optionally use TBUS-style orbit numbering (TLE orbit number + 1)
+ """
+ try:
+ dt = astronomy._days(utc_time - self.orbit_elements.an_time)
+ orbit_period = astronomy._days(self.orbit_elements.an_period)
+ except AttributeError:
+ pos_epoch, vel_epoch = self.get_position(self.tle.epoch,
+ normalize=False)
+ if np.abs(pos_epoch[2]) > 1 or not vel_epoch[2] > 0:
+ # Epoch not at ascending node
+ self.orbit_elements.an_time = self.get_last_an_time(self.tle.epoch)
+ else:
+ # Epoch at ascending node (z < 1 km) and positive v_z
+ self.orbit_elements.an_time = self.tle.epoch
+
+ self.orbit_elements.an_period = self.orbit_elements.an_time - \
+ self.get_last_an_time(self.orbit_elements.an_time
+ - timedelta(minutes=10))
+
+ dt = astronomy._days(utc_time - self.orbit_elements.an_time)
+ orbit_period = astronomy._days(self.orbit_elements.an_period)
+
+
+ orbit = int(self.tle.orbit + dt / orbit_period +
+ self.tle.mean_motion_derivative * dt**2 +
+ self.tle.mean_motion_sec_derivative * dt**3)
+
+ if tbus_style:
+ orbit += 1
+ return orbit
+
+ def get_next_passes(self, utc_time, length, lon, lat, alt, tol=0.001):
+ """Calculate passes for the next hours for a given start time and a
+ given observer.
+
+ Original by Martin.
+
+ utc_time: Observation time (datetime object)
+ length: Number of hours to find passes (int)
+ lon: Longitude of observer position on ground (float)
+ lat: Latitude of observer position on ground (float)
+ alt: Altitude above sea-level (geoid) of observer position on ground (float)
+ tol: precision of the result in seconds
+
+ Return: [(rise-time, fall-time, max-elevation-time), ...]
+ """
+
+ def elevation(minutes):
+ """elevation
+ """
+ return self.get_observer_look(utc_time +
+ timedelta(minutes=minutes),
+ lon, lat, alt)[1]
+ def elevation_inv(minutes):
+ """inverse of elevation
+ """
+ return -elevation(minutes)
+
+ def get_root_secant(fun, start, end, tol=0.01):
+ """Secant method
+ """
+ x_0 = end
+ x_1 = start
+ fx_0 = fun(end)
+ fx_1 = fun(start)
+ if abs(fx_0) < abs(fx_1):
+ fx_0, fx_1 = fx_1, fx_0
+ x_0, x_1 = x_1, x_0
+ while abs(x_0 - x_1) > tol:
+ x_n = x_1 - fx_1 * ((x_1 - x_0) / (fx_1 - fx_0))
+ x_0, x_1 = x_1, x_n
+ fx_0, fx_1 = fx_1, fun(x_n)
+ return x_1
+
+ def get_max_parab(fun, start, end, tol=0.01):
+ """Successive parabolic interpolation
+ """
+
+ a = start
+ c = end
+ b = (a + c) / 2.0
+ x = b
+
+ f_a = fun(a)
+ f_b = fun(b)
+ f_c = fun(c)
+
+ while abs(c - a) > tol:
+ x = b - 0.5 * (((b - a) ** 2 * (f_b - f_c)
+ - (b - c) ** 2 * (f_b - f_a)) /
+ ((b - a) * (f_b - f_c) - (b - c) * (f_b - f_a)))
+ f_x = fun(x)
+ if x > b:
+ a, b, c = b, x, c
+ f_a, f_b, f_c = f_b, f_x, f_c
+ else:
+ a, b, c = a, x, b
+ f_a, f_b, f_c = f_a, f_x, f_b
+
+ return x
+
+ times = utc_time + np.array([timedelta(minutes=minutes)
+ for minutes in range(length * 60)])
+ elev = self.get_observer_look(times, lon, lat, alt)[1]
+ zcs = np.where(np.diff(np.sign(elev)))[0]
+
+ res = []
+ risetime = None
+ falltime = None
+ for guess in zcs:
+ horizon_mins = get_root_secant(elevation, guess, guess + 1.0, tol=tol/60.0)
+ horizon_time = utc_time + timedelta(minutes=horizon_mins)
+ if elev[guess] < 0:
+ risetime = horizon_time
+ risemins = horizon_mins
+ falltime = None
+ else:
+ falltime = horizon_time
+ fallmins = horizon_mins
+ if risetime:
+ middle = (risemins + fallmins) / 2.0
+ highest = utc_time + \
+ timedelta(minutes=get_max_parab(
+ elevation_inv,
+ middle - 0.1, middle + 0.1,
+ tol=tol/60.0
+ ))
+ res += [(risetime, falltime, highest)]
+ risetime = None
+ return res
+
+ def _get_time_at_horizon(self, utc_time, obslon, obslat, **kwargs):
+ """Get the time closest in time to *utc_time* when the
+ satellite is at the horizon relative to the position of an observer on
+ ground (altitude = 0)
+
+ Note: This is considered deprecated and it's functionality is currently
+ replaced by 'get_next_passes'.
+ """
+ warnings.warn("_get_time_at_horizon is replaced with get_next_passes",
+ DeprecationWarning)
+ if "precision" in kwargs:
+ precision = kwargs['precision']
+ else:
+ precision = timedelta(seconds=0.001)
+ if "max_iterations" in kwargs:
+ nmax_iter = kwargs["max_iterations"]
+ else:
+ nmax_iter = 100
+
+ sec_step = 0.5
+ t_step = timedelta(seconds=sec_step/2.0)
+
+ # Local derivative:
+ def fprime(timex):
+ el0 = self.get_observer_look(timex - t_step,
+ obslon, obslat, 0.0)[1]
+ el1 = self.get_observer_look(timex + t_step,
+ obslon, obslat, 0.0)[1]
+ return el0, (abs(el1) - abs(el0)) / sec_step
+
+ tx0 = utc_time - timedelta(seconds=1.0)
+ tx1 = utc_time
+ idx = 0
+ #eps = 500.
+ eps = 100.
+ while abs(tx1 - tx0) > precision and idx < nmax_iter:
+ tx0 = tx1
+ fpr = fprime(tx0)
+ # When the elevation is high the scale is high, and when
+ # the elevation is low the scale is low
+ #var_scale = np.abs(np.sin(fpr[0] * np.pi/180.))
+ #var_scale = np.sqrt(var_scale)
+ var_scale = np.abs(fpr[0])
+ tx1 = tx0 - timedelta(seconds = (eps * var_scale * fpr[1]))
+ idx = idx + 1
+ #print idx, tx0, tx1, var_scale, fpr
+ if abs(tx1 - utc_time) < precision and idx < 2:
+ tx1 = tx1 + timedelta(seconds=1.0)
+
+ if abs(tx1 - tx0) <= precision and idx < nmax_iter:
+ return tx1
+ else:
+ return None
+
+class OrbitElements(object):
+ """Class holding the orbital elements.
+ """
+
+ def __init__(self, tle):
+ self.epoch = tle.epoch
+ self.excentricity = tle.excentricity
+ self.inclination = np.deg2rad(tle.inclination)
+ self.right_ascension = np.deg2rad(tle.right_ascension)
+ self.arg_perigee = np.deg2rad(tle.arg_perigee)
+ self.mean_anomaly = np.deg2rad(tle.mean_anomaly)
+
+ self.mean_motion = tle.mean_motion * (np.pi * 2 / XMNPDA)
+ self.mean_motion_derivative = tle.mean_motion_derivative * np.pi * 2 / XMNPDA ** 2
+ self.mean_motion_sec_derivative = tle.mean_motion_sec_derivative * np.pi * 2 / XMNPDA ** 3
+ self.bstar = tle.bstar * AE
+
+ n_0 = self.mean_motion
+ k_e = XKE
+ k_2 = CK2
+ i_0 = self.inclination
+ e_0 = self.excentricity
+
+ a_1 = (k_e / n_0) ** (2.0/3)
+ delta_1 = ((3/2.0) * (k_2 / a_1**2) * ((3 * np.cos(i_0)**2 - 1) /
+ (1 - e_0**2)**(2.0/3)))
+
+ a_0 = a_1 * (1 - delta_1/3 - delta_1**2 - (134.0/81) * delta_1**3)
+
+ delta_0 = ((3/2.0) * (k_2 / a_0**2) * ((3 * np.cos(i_0)**2 - 1) /
+ (1 - e_0**2)**(2.0/3)))
+
+ # original mean motion
+ n_0pp = n_0 / (1 + delta_0)
+ self.original_mean_motion = n_0pp
+
+ # semi major axis
+ a_0pp = a_0 / (1 - delta_0)
+ self.semi_major_axis = a_0pp
+
+ self.period = np.pi * 2 / n_0pp
+
+ self.perigee = (a_0pp * (1 - e_0) / AE - AE) * XKMPER
+
+ self.right_ascension_lon = (self.right_ascension
+ - astronomy.gmst(self.epoch))
+
+ if self.right_ascension_lon > np.pi:
+ self.right_ascension_lon -= 2 * np.pi
+
+
+class _SGDP4(object):
+ """Class for the SGDP4 computations.
+ """
+
+ def __init__(self, orbit_elements):
+ self.mode = None
+
+ perigee = orbit_elements.perigee
+ self.eo = orbit_elements.excentricity
+ self.xincl = orbit_elements.inclination
+ self.xno = orbit_elements.original_mean_motion
+ k_2 = CK2
+ k_4 = CK4
+ k_e = XKE
+ self.bstar = orbit_elements.bstar
+ self.omegao = orbit_elements.arg_perigee
+ self.xmo = orbit_elements.mean_anomaly
+ self.xnodeo = orbit_elements.right_ascension
+ self.t_0 = orbit_elements.epoch
+ self.xn_0 = orbit_elements.mean_motion
+ A30 = -XJ3 * AE**3
+
+ if not(0 < self.eo < ECC_LIMIT_HIGH):
+ raise OrbitalError('Eccentricity out of range: %e' % self.eo)
+ elif not((0.0035 * 2 * np.pi / XMNPDA) < self.xn_0 < (18 * 2 * np.pi / XMNPDA)):
+ raise OrbitalError('Mean motion out of range: %e' % self.xn_0)
+ elif not(0 < self.xincl < np.pi):
+ raise OrbitalError('Inclination out of range: %e' % self.xincl)
+
+ if self.eo < 0:
+ self.mode = self.SGDP4_ZERO_ECC
+ return
+
+ self.cosIO = np.cos(self.xincl)
+ self.sinIO = np.sin(self.xincl)
+ theta2 = self.cosIO**2
+ theta4 = theta2 ** 2
+ self.x3thm1 = 3.0 * theta2 - 1.0
+ self.x1mth2 = 1.0 - theta2
+ self.x7thm1 = 7.0 * theta2 - 1.0
+
+ a1 = (XKE / self.xn_0) ** (2. / 3)
+ betao2 = 1.0 - self.eo**2
+ betao = np.sqrt(betao2)
+ temp0 = 1.5 * CK2 * self.x3thm1 / (betao * betao2)
+ del1 = temp0 / (a1**2)
+ a0 = a1 * (1.0 - del1 * (1.0 / 3.0 + del1 * (1.0 + del1 * 134.0 / 81.0)))
+ del0 = temp0 / (a0**2)
+ self.xnodp = self.xn_0 / (1.0 + del0)
+ self.aodp = (a0 / (1.0 - del0))
+ self.perigee = (self.aodp * (1.0 - self.eo) - AE) * XKMPER
+ self.apogee = (self.aodp * (1.0 + self.eo) - AE) * XKMPER
+ self.period = (2 * np.pi * 1440.0 / XMNPDA) / self.xnodp
+
+ if self.period >= 225:
+ # Deep-Space model
+ self.mode = SGDP4_DEEP_NORM
+ elif self.perigee < 220:
+ # Near-space, simplified equations
+ self.mode = SGDP4_NEAR_SIMP
+ else:
+ # Near-space, normal equations
+ self.mode = SGDP4_NEAR_NORM
+
+ if self.perigee < 156:
+ s4 = self.perigee - 78
+ if s4 < 20:
+ s4 = 20
+
+ qoms24 = ((120 - s4) * (AE / XKMPER))**4
+ s4 = (s4 / XKMPER + AE)
+ else:
+ s4 = KS
+ qoms24 = QOMS2T
+
+ pinvsq = 1.0 / (self.aodp**2 * betao2**2)
+ tsi = 1.0 / (self.aodp - s4)
+ self.eta = self.aodp * self.eo * tsi
+ etasq = self.eta**2
+ eeta = self.eo * self.eta
+ psisq = np.abs(1.0 - etasq)
+ coef = qoms24 * tsi**4
+ coef_1 = coef / psisq**3.5
+
+ self.c2 = (coef_1 * self.xnodp * (self.aodp *
+ (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) +
+ (0.75 * CK2) * tsi / psisq * self.x3thm1 *
+ (8.0 + 3.0 * etasq * (8.0 + etasq))))
+
+ self.c1 = self.bstar * self.c2
+
+ self.c4 = (2.0 * self.xnodp * coef_1 * self.aodp * betao2 * (self.eta *
+ (2.0 + 0.5 * etasq) + self.eo * (0.5 + 2.0 *
+ etasq) - (2.0 * CK2) * tsi / (self.aodp * psisq) * (-3.0 *
+ self.x3thm1 * (1.0 - 2.0 * eeta + etasq *
+ (1.5 - 0.5 * eeta)) + 0.75 * self.x1mth2 * (2.0 *
+ etasq - eeta * (1.0 + etasq)) * np.cos(2.0 * self.omegao))))
+
+ self.c5, self.c3, self.omgcof = 0.0, 0.0, 0.0
+
+
+ if self.mode == SGDP4_NEAR_NORM:
+ self.c5 = (2.0 * coef_1 * self.aodp * betao2 *
+ (1.0 + 2.75 * (etasq + eeta) + eeta * etasq))
+ if self.eo > ECC_ALL:
+ self.c3 = coef * tsi * A3OVK2 * self.xnodp * AE * self.sinIO / self.eo
+ self.omgcof = self.bstar * self.c3 * np.cos(self.omegao)
+
+ temp1 = 3.0 * CK2 * pinvsq * self.xnodp
+ temp2 = temp1 * CK2 * pinvsq
+ temp3 = 1.25 * CK4 * pinvsq**2 * self.xnodp
+
+ self.xmdot = (self.xnodp + (0.5 * temp1 * betao * self.x3thm1 + 0.0625 *
+ temp2 * betao * (13.0 - 78.0 * theta2 +
+ 137.0 * theta4)))
+
+ x1m5th = 1.0 - 5.0 * theta2
+
+ self.omgdot = (-0.5 * temp1 * x1m5th + 0.0625 * temp2 *
+ (7.0 - 114.0 * theta2 + 395.0 * theta4) +
+ temp3 * (3.0 - 36.0 * theta2 + 49.0 * theta4))
+
+ xhdot1 = -temp1 * self.cosIO
+ self.xnodot = (xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * theta2) +
+ 2.0 * temp3 * (3.0 - 7.0 * theta2)) * self.cosIO)
+
+ if self.eo > ECC_ALL:
+ self.xmcof = (-(2. / 3) * AE) * coef * self.bstar / eeta
+ else:
+ self.xmcof = 0.0
+
+ self.xnodcf = 3.5 * betao2 * xhdot1 * self.c1
+ self.t2cof = 1.5 * self.c1
+
+ # Check for possible divide-by-zero for X/(1+cos(xincl)) when calculating xlcof */
+ temp0 = 1.0 + self.cosIO
+ if np.abs(temp0) < EPS_COS:
+ temp0 = np.sign(temp0) * EPS_COS
+
+ self.xlcof = 0.125 * A3OVK2 * self.sinIO * (3.0 + 5.0 * self.cosIO) / temp0
+
+ self.aycof = 0.25 * A3OVK2 * self.sinIO
+
+ self.cosXMO = np.cos(self.xmo)
+ self.sinXMO = np.sin(self.xmo)
+ self.delmo = (1.0 + self.eta * self.cosXMO)**3
+
+ if self.mode == SGDP4_NEAR_NORM:
+ c1sq = self.c1**2
+ self.d2 = 4.0 * self.aodp * tsi * c1sq
+ temp0 = self.d2 * tsi * self.c1 / 3.0
+ self.d3 = (17.0 * self.aodp + s4) * temp0
+ self.d4 = 0.5 * temp0 * self.aodp * tsi * (221.0 * self.aodp + 31.0 * s4) * self.c1
+ self.t3cof = self.d2 + 2.0 * c1sq
+ self.t4cof = 0.25 * (3.0 * self.d3 + self.c1 * (12.0 * self.d2 + 10.0 * c1sq))
+ self.t5cof = (0.2 * (3.0 * self.d4 + 12.0 * self.c1 * self.d3 + 6.0 * self.d2**2 +
+ 15.0 * c1sq * (2.0 * self.d2 + c1sq)))
+
+ elif self.mode == SGDP4_DEEP_NORM:
+ raise NotImplementedError('Deep space calculations not supported')
+
+ def propagate(self, utc_time):
+ kep = {}
+
+ ts = astronomy._days(utc_time - self.t_0) * XMNPDA
+
+ em = self.eo
+ xinc = self.xincl
+
+ xmp = self.xmo + self.xmdot * ts
+ xnode = self.xnodeo + ts * (self.xnodot + ts * self.xnodcf)
+ omega = self.omegao + self.omgdot * ts
+
+ if self.mode == SGDP4_ZERO_ECC:
+ raise NotImplementedError('Mode SGDP4_ZERO_ECC not implemented')
+ elif self.mode == SGDP4_NEAR_SIMP:
+ raise NotImplementedError('Mode "Near-space, simplified equations"'
+ ' not implemented')
+ elif self.mode == SGDP4_NEAR_NORM:
+ delm = self.xmcof * ((1.0 + self.eta * np.cos(xmp))**3 - self.delmo)
+ temp0 = ts * self.omgcof + delm
+ xmp += temp0
+ omega -= temp0
+ tempa = 1.0 - (ts * (self.c1 + ts * (self.d2 + ts * (self.d3 + ts * self.d4))))
+ tempe = self.bstar * (self.c4 * ts + self.c5 * (np.sin(xmp) - self.sinXMO))
+ templ = ts * ts * (self.t2cof + ts * (self.t3cof + ts * (self.t4cof + ts * self.t5cof)))
+ a = self.aodp * tempa**2
+ e = em - tempe
+ xl = xmp + omega + xnode + self.xnodp * templ
+
+ else:
+ raise NotImplementedError('Deep space calculations not supported')
+
+ if np.any(a < 1):
+ raise Exception('Satellite crased at time %s', utc_time)
+ elif np.any(e < ECC_LIMIT_LOW):
+ raise ValueError('Satellite modified eccentricity to low: %e < %e'
+ % (e, ECC_LIMIT_LOW))
+
+ e = np.where(e < ECC_EPS, ECC_EPS, e)
+ e = np.where(e > ECC_LIMIT_HIGH, ECC_LIMIT_HIGH, e)
+
+ beta2 = 1.0 - e**2
+
+ # Long period periodics
+ sinOMG = np.sin(omega)
+ cosOMG = np.cos(omega)
+
+ temp0 = 1.0 / (a * beta2)
+ axn = e * cosOMG
+ ayn = e * sinOMG + temp0 * self.aycof
+ xlt = xl + temp0 * self.xlcof * axn
+
+ elsq = axn**2 + ayn**2
+
+ if np.any(elsq >= 1):
+ raise Exception('e**2 >= 1 at %s', utc_time)
+
+ kep['ecc'] = np.sqrt(elsq)
+
+ epw = np.fmod(xlt - xnode, 2 * np.pi)
+ # needs a copy in case of an array
+ capu = np.array(epw)
+ maxnr = kep['ecc']
+ for i in range(10):
+ sinEPW = np.sin(epw)
+ cosEPW = np.cos(epw)
+
+ ecosE = axn * cosEPW + ayn * sinEPW
+ esinE = axn * sinEPW - ayn * cosEPW
+ f = capu - epw + esinE
+ if np.all(np.abs(f) < NR_EPS):
+ break
+
+ df = 1.0 - ecosE
+
+ # 1st order Newton-Raphson correction.
+ nr = f / df
+
+ # 2nd order Newton-Raphson correction.
+ nr = np.where(np.logical_and(i == 0, np.abs(nr) > 1.25 * maxnr),
+ np.sign(nr) * maxnr,
+ f / (df + 0.5*esinE*nr))
+ epw += nr
+
+ # Short period preliminary quantities
+ temp0 = 1.0 - elsq
+ betal = np.sqrt(temp0)
+ pl = a * temp0
+ r = a * (1.0 - ecosE)
+ invR = 1.0 / r
+ temp2 = a * invR
+ temp3 = 1.0 / (1.0 + betal)
+ cosu = temp2 * (cosEPW - axn + ayn * esinE * temp3)
+ sinu = temp2 * (sinEPW - ayn - axn * esinE * temp3)
+ u = np.arctan2(sinu, cosu)
+ sin2u = 2.0 * sinu * cosu
+ cos2u = 2.0 * cosu**2 - 1.0
+ temp0 = 1.0 / pl
+ temp1 = CK2 * temp0
+ temp2 = temp1 * temp0
+
+ # Update for short term periodics to position terms.
+
+ rk = r * (1.0 - 1.5 * temp2 * betal * self.x3thm1) + 0.5 * temp1 * self.x1mth2 * cos2u
+ uk = u - 0.25 * temp2 * self.x7thm1 * sin2u
+ xnodek = xnode + 1.5 * temp2 * self.cosIO * sin2u
+ xinck = xinc + 1.5 * temp2 * self.cosIO * self.sinIO * cos2u
+
+ if np.any(rk < 1):
+ raise Exception('Satellite crased at time %s', utc_time)
+
+ temp0 = np.sqrt(a)
+ temp2 = XKE / (a * temp0)
+ rdotk = ((XKE * temp0 * esinE * invR -temp2 * temp1 * self.x1mth2 * sin2u) *
+ (XKMPER / AE * XMNPDA / 86400.0))
+ rfdotk = ((XKE * np.sqrt(pl) * invR + temp2 * temp1 *
+ (self.x1mth2 * cos2u + 1.5 * self.x3thm1)) *
+ (XKMPER / AE * XMNPDA / 86400.0))
+
+ kep['radius'] = rk * XKMPER / AE
+ kep['theta'] = uk
+ kep['eqinc'] = xinck
+ kep['ascn'] = xnodek
+ kep['argp'] = omega
+ kep['smjaxs'] = a * XKMPER / AE
+ kep['rdotk'] = rdotk
+ kep['rfdotk'] = rfdotk
+
+ return kep
+
+
+def kep2xyz(kep):
+ sinT = np.sin(kep['theta'])
+ cosT = np.cos(kep['theta'])
+ sinI = np.sin(kep['eqinc'])
+ cosI = np.cos(kep['eqinc'])
+ sinS = np.sin(kep['ascn'])
+ cosS = np.cos(kep['ascn'])
+
+ xmx = -sinS * cosI
+ xmy = cosS * cosI
+
+ ux = xmx * sinT + cosS * cosT
+ uy = xmy * sinT + sinS * cosT
+ uz = sinI * sinT
+
+ x = kep['radius'] * ux
+ y = kep['radius'] * uy
+ z = kep['radius'] * uz
+
+ vx = xmx * cosT - cosS * sinT
+ vy = xmy * cosT - sinS * sinT
+ vz = sinI * cosT
+
+ v_x = kep['rdotk'] * ux + kep['rfdotk'] * vx
+ v_y = kep['rdotk'] * uy + kep['rfdotk'] * vy
+ v_z = kep['rdotk'] * uz + kep['rfdotk'] * vz
+
+ return np.array((x, y, z)), np.array((v_x, v_y, v_z))
+
+if __name__ == "__main__":
+ obs_lon, obs_lat = np.deg2rad((12.4143, 55.9065))
+ obs_alt = 0.02
+ o = Orbital(satellite="METOP-B")
+
+ t_start = datetime.now()
+ t_stop = t_start + timedelta(minutes=20)
+ t = t_start
+ while t < t_stop:
+ t += timedelta(seconds=15)
+ lon, lat, alt = o.get_lonlatalt(t)
+ lon, lat = np.rad2deg((lon, lat))
+ az, el = o.get_observer_look(t, obs_lon, obs_lat, obs_alt)
+ ob = o.get_orbit_number(t, tbus_style=True)
+ print az, el, ob
diff --git a/pyorbital/tests/SGP4-VER.TLE b/pyorbital/tests/SGP4-VER.TLE
new file mode 100644
index 0000000..cfa3133
--- /dev/null
+++ b/pyorbital/tests/SGP4-VER.TLE
@@ -0,0 +1,110 @@
+# ------------------ Verification test cases ----------------------
+# # TEME example
+1 00005U 58002B 00179.78495062 .00000023 00000-0 28098-4 0 4753
+2 00005 34.2682 348.7242 1859667 331.7664 19.3264 10.82419157413667 0.00 4320.0 360.00
+# ## fig show lyddane fix error with gsfc ver
+1 04632U 70093B 04031.91070959 -.00000084 00000-0 10000-3 0 9955
+2 04632 11.4628 273.1101 1450506 207.6000 143.9350 1.20231981 44145 -5184.0 -4896.0 120.00
+# DELTA 1 DEB # near earth normal drag equation
+# # perigee = 377.26km, so moderate drag case
+1 06251U 62025E 06176.82412014 .00008885 00000-0 12808-3 0 3985
+2 06251 58.0579 54.0425 0030035 139.1568 221.1854 15.56387291 6774 0.0 2880.0 120.00
+# MOLNIYA 2-14 # 12h resonant ecc in 0.65 to 0.7 range
+1 08195U 75081A 06176.33215444 .00000099 00000-0 11873-3 0 813
+2 08195 64.1586 279.0717 6877146 264.7651 20.2257 2.00491383225656 0.0 2880.0 120.00
+# MOLNIYA 1-36 ## fig 12h resonant ecc in 0.7 to 0.715 range
+1 09880U 77021A 06176.56157475 .00000421 00000-0 10000-3 0 9814
+2 09880 64.5968 349.3786 7069051 270.0229 16.3320 2.00813614112380 0.0 2880.0 120.00
+# SMS 1 AKM # show the integrator problem with gsfc ver
+1 09998U 74033F 05148.79417928 -.00000112 00000-0 00000+0 0 4480
+2 09998 9.4958 313.1750 0270971 327.5225 30.8097 1.16186785 45878 -1440.0 -720.00 60.0
+# # Original STR#3 SDP4 test
+1 11801U 80230.29629788 .01431103 00000-0 14311-1 13
+2 11801 46.7916 230.4354 7318036 47.4722 10.4117 2.28537848 13 0.0 1440.0 360.00
+# EUTELSAT 1-F1 (ECS1)## fig lyddane choice in GSFC at 2080 min
+1 14128U 83058A 06176.02844893 -.00000158 00000-0 10000-3 0 9627
+2 14128 11.4384 35.2134 0011562 26.4582 333.5652 0.98870114 46093 0.0 2880.0 120.00
+# SL-6 R/B(2) # Deep space, perigee = 82.48 (<98) for
+# # s4 > 20 mod
+1 16925U 86065D 06151.67415771 .02550794 -30915-6 18784-3 0 4486
+2 16925 62.0906 295.0239 5596327 245.1593 47.9690 4.88511875148616 0.0 1440.0 120.00
+# SL-12 R/B # Shows Lyddane choice at 1860 and 4700 min
+1 20413U 83020D 05363.79166667 .00000000 00000-0 00000+0 0 7041
+2 20413 12.3514 187.4253 7864447 196.3027 356.5478 0.24690082 7978 1440.0 4320.0 120.00
+# MOLNIYA 1-83 # 12h resonant, ecc > 0.715 (negative BSTAR)
+1 21897U 92011A 06176.02341244 -.00001273 00000-0 -13525-3 0 3044
+2 21897 62.1749 198.0096 7421690 253.0462 20.1561 2.01269994104880 0.0 2880.0 120.00
+# SL-6 R/B(2) # last tle given, decayed 2006-04-04, day 94
+1 22312U 93002D 06094.46235912 .99999999 81888-5 49949-3 0 3953
+2 22312 62.1486 77.4698 0308723 267.9229 88.7392 15.95744531 98783 54.2028672 1440.0 20.00
+# SL-6 R/B(2) # 12h resonant ecc in the > 0.715 range
+1 22674U 93035D 06176.55909107 .00002121 00000-0 29868-3 0 6569
+2 22674 63.5035 354.4452 7541712 253.3264 18.7754 1.96679808 93877 0.0 2880.0 120.00
+# ARIANE 44L+ R/B # Lyddane bug at <= 70 min for atan2(),
+# # no quadrant fix
+1 23177U 94040C 06175.45752052 .00000386 00000-0 76590-3 0 95
+2 23177 7.0496 179.8238 7258491 296.0482 8.3061 2.25906668 97438 0.0 1440.0 120.00
+# WIND # STR#3 Kepler failes past about 200 min
+1 23333U 94071A 94305.49999999 -.00172956 26967-3 10000-3 0 15
+2 23333 28.7490 2.3720 9728298 30.4360 1.3500 0.07309491 70 0.0 1600.0 120.00
+# ARIANE 42P+3 R/B ## fig Lyddane bug at > 280.5 min for AcTan()
+1 23599U 95029B 06171.76535463 .00085586 12891-6 12956-2 0 2905
+2 23599 6.9327 0.2849 5782022 274.4436 25.2425 4.47796565123555 0.0 720.0 20.00
+# ITALSAT 2 # 24h resonant GEO, inclination > 3 deg
+1 24208U 96044A 06177.04061740 -.00000094 00000-0 10000-3 0 1600
+2 24208 3.8536 80.0121 0026640 311.0977 48.3000 1.00778054 36119 0.0 1440.0 120.00
+# AMC-4 ## fig low incl, show incl shift with
+# ## gsfc version from 240 to 1440 min
+1 25954U 99060A 04039.68057285 -.00000108 00000-0 00000-0 0 6847
+2 25954 0.0004 243.8136 0001765 15.5294 22.7134 1.00271289 15615 -1440.0 1440.0 120.00
+# INTELSAT 902 # negative incl at 9313 min then
+# # 270 deg Lyddane bug at 37606 min
+1 26900U 01039A 06106.74503247 .00000045 00000-0 10000-3 0 8290
+2 26900 0.0164 266.5378 0003319 86.1794 182.2590 1.00273847 16981 9300.00 9400.00 60.00
+# COSMOS 1024 DEB # 12h resonant ecc in 0.5 to 0.65 range
+1 26975U 78066F 06174.85818871 .00000620 00000-0 10000-3 0 6809
+2 26975 68.4714 236.1303 5602877 123.7484 302.5767 2.05657553 67521 0.0 2880.0 120.00
+# CBERS 2 # Near Earth, ecc = 8.84E-5 (< 1.0e-4)
+# # drop certain normal drag terms
+1 28057U 03049A 06177.78615833 .00000060 00000-0 35940-4 0 1836
+2 28057 98.4283 247.6961 0000884 88.1964 271.9322 14.35478080140550 0.0 2880.0 120.00
+# NAVSTAR 53 (USA 175)# 12h non-resonant GPS (ecc < 0.5 ecc)
+1 28129U 03058A 06175.57071136 -.00000104 00000-0 10000-3 0 459
+2 28129 54.7298 324.8098 0048506 266.2640 93.1663 2.00562768 18443 0.0 1440.0 120.00
+# COSMOS 2405 # Near Earth, perigee = 127.20 (< 156) s4 mod
+1 28350U 04020A 06167.21788666 .16154492 76267-5 18678-3 0 8894
+2 28350 64.9977 345.6130 0024870 260.7578 99.9590 16.47856722116490 0.0 2880.0 120.00
+# H-2 R/B # Deep space, perigee = 135.75 (<156) s4 mod
+1 28623U 05006B 06177.81079184 .00637644 69054-6 96390-3 0 6000
+2 28623 28.5200 114.9834 6249053 170.2550 212.8965 3.79477162 12753 0.0 1440.0 120.00
+# XM-3 # 24h resonant geo, incl < 3 deg goes
+# # negative around 1130 min
+1 28626U 05008A 06176.46683397 -.00000205 00000-0 10000-3 0 2190
+2 28626 0.0019 286.9433 0000335 13.7918 55.6504 1.00270176 4891 0.0 1440.0 120.00
+# MINOTAUR R/B # Sub-orbital case - Decayed 2005-11-29
+# #(perigee = -51km), lost in 50 minutes
+1 28872U 05037B 05333.02012661 .25992681 00000-0 24476-3 0 1534
+2 28872 96.4736 157.9986 0303955 244.0492 110.6523 16.46015938 10708 0.0 60.0 5.00
+# SL-14 DEB # Last stage of decay - lost in under 420 min
+1 29141U 85108AA 06170.26783845 .99999999 00000-0 13519-0 0 718
+2 29141 82.4288 273.4882 0015848 277.2124 83.9133 15.93343074 6828 0.0 440.0 20.00
+# SL-12 DEB # Near Earth, perigee = 212.24 < 220
+# # simplified drag eq
+1 29238U 06022G 06177.28732010 .00766286 10823-4 13334-2 0 101
+2 29238 51.5595 213.7903 0202579 95.2503 267.9010 15.73823839 1061 0.0 1440.0 120.00
+# # Original STR#3 SGP4 test
+1 88888U 80275.98708465 .00073094 13844-3 66816-4 0 87
+2 88888 72.8435 115.9689 0086731 52.6988 110.5714 16.05824518 1058 0.0 1440.0 120.00
+#
+# # check error code 4
+1 33333U 05037B 05333.02012661 .25992681 00000-0 24476-3 0 1534
+2 33333 96.4736 157.9986 9950000 244.0492 110.6523 4.00004038 10708 0.0 150.0 5.00
+# # try and check error code 2 but this
+1 33334U 78066F 06174.85818871 .00000620 00000-0 10000-3 0 6809
+2 33334 68.4714 236.1303 5602877 123.7484 302.5767 0.00001000 67521 0.0 1440.0 1.00
+# # try to check error code 3 looks like ep never goes below zero, tied close to ecc
+1 33335U 05008A 06176.46683397 -.00000205 00000-0 10000-3 0 2190
+2 33335 0.0019 286.9433 0000004 13.7918 55.6504 1.00270176 4891 0.0 1440.0 20.00
+# SL-12 R/B # Shows Lyddane choice at 1860 and 4700 min
+1 20413U 83020D 05363.79166667 .00000000 00000-0 00000+0 0 7041
+2 20413 12.3514 187.4253 7864447 196.3027 356.5478 0.24690082 7978 1844000 1845100 5.00
diff --git a/pyorbital/tests/__init__.py b/pyorbital/tests/__init__.py
new file mode 100644
index 0000000..fb67767
--- /dev/null
+++ b/pyorbital/tests/__init__.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""The tests package.
+"""
+
+from pyorbital.tests import (test_aiaa, test_tlefile, test_orbital,
+ test_astronomy, test_geoloc)
+import unittest
+
+def suite():
+ """The global test suite.
+ """
+ mysuite = unittest.TestSuite()
+ # Test the documentation strings
+ #mysuite.addTests(doctest.DocTestSuite(image))
+ # Use the unittests also
+ mysuite.addTests(test_aiaa.suite())
+ mysuite.addTests(test_tlefile.suite())
+ mysuite.addTests(test_orbital.suite())
+ mysuite.addTests(test_astronomy.suite())
+ mysuite.addTests(test_geoloc.suite())
+
+ return mysuite
+
+if __name__ == '__main__':
+ unittest.TextTestRunner(verbosity=2).run(suite())
diff --git a/pyorbital/tests/aiaa_results b/pyorbital/tests/aiaa_results
new file mode 100644
index 0000000..c79823e
--- /dev/null
+++ b/pyorbital/tests/aiaa_results
@@ -0,0 +1,548 @@
+# Min from epoch position x km position y km position z km vel km/s vel km/s vel km/s year mon day hr min sec
+5 xx
+0.00000000 7022.46529266 -1400.08296755 0.03995155 1.893841015 6.405893759 4.534807250
+360.00000000 -7154.03120202 -3783.17682504 -3536.19412294 4.741887409 -4.151817765 -2.093935425 2000 6 28 0:50:19.733571
+720.00000000 -7134.59340119 6531.68641334 3260.27186483 -4.113793027 -2.911922039 -2.557327851 2000 6 28 6:50:19.733571
+1080.00000000 5568.53901181 4492.06992591 3863.87641983 -4.209106476 5.159719888 2.744852980 2000 6 28 12:50:19.733571
+1440.00000000 -938.55923943 -6268.18748831 -4294.02924751 7.536105209 -0.427127707 0.989878080 2000 6 28 18:50:19.733571
+1800.00000000 -9680.56121728 2802.47771354 124.10688038 -0.905874102 -4.659467970 -3.227347517 2000 6 29 0:50:19.733571
+2160.00000000 190.19796988 7746.96653614 5110.00675412 -6.112325142 1.527008184 -0.139152358 2000 6 29 6:50:19.733571
+2520.00000000 5579.55640116 -3995.61396789 -1518.82108966 4.767927483 5.123185301 4.276837355 2000 6 29 12:50:19.733571
+2880.00000000 -8650.73082219 -1914.93811525 -3007.03603443 3.067165127 -4.828384068 -2.515322836 2000 6 29 18:50:19.733571
+3240.00000000 -5429.79204164 7574.36493792 3747.39305236 -4.999442110 -1.800561422 -2.229392830 2000 6 30 0:50:19.733571
+3600.00000000 6759.04583722 2001.58198220 2783.55192533 -2.180993947 6.402085603 3.644723952 2000 6 30 6:50:19.733571
+3960.00000000 -3791.44531559 -5712.95617894 -4533.48630714 6.668817493 -2.516382327 -0.082384354 2000 6 30 12:50:19.733571
+4320.00000000 -9060.47373569 4658.70952502 813.68673153 -2.232832783 -4.110453490 -3.157345433 2000 6 30 18:50:19.733571
+4632 xx
+0.00000000 2334.11450085 -41920.44035349 -0.03867437 2.826321032 -0.065091664 0.570936053
+-5184.00000000 -29020.02587128 13819.84419063 -5713.33679183 -1.768068390 -3.235371192 -0.395206135 2004 1 28 7:27:25.308584
+-5064.00000000 -32982.56870101 -11125.54996609 -6803.28472771 0.617446996 -3.379240041 0.085954707 2004 1 28 9:27:25.308597
+-4944.00000000 -22097.68730513 -31583.13829284 -4836.34329328 2.230597499 -2.166594667 0.426443070 2004 1 28 11:27:25.308611
+-4896.00000000 -15129.94694545 -36907.74526221 -3487.56256701 2.581167187 -1.524204737 0.504805763 2004 1 28 12:15:25.308600
+6251 xx
+0.00000000 3988.31022699 5498.96657235 0.90055879 -3.290032738 2.357652820 6.496623475
+120.00000000 -3935.69800083 409.10980837 5471.33577327 -3.374784183 -6.635211043 -1.942056221 2006 6 25 21:46:43.980124
+240.00000000 -1675.12766915 -5683.30432352 -3286.21510937 5.282496925 1.508674259 -5.354872978 2006 6 25 23:46:43.980097
+360.00000000 4993.62642836 2890.54969900 -3600.40145627 0.347333429 5.707031557 5.070699638 2006 6 26 1:46:43.980111
+480.00000000 -1115.07959514 4015.11691491 5326.99727718 -5.524279443 -4.765738774 2.402255961 2006 6 26 3:46:43.980124
+600.00000000 -4329.10008198 -5176.70287935 409.65313857 2.858408303 -2.933091792 -6.509690397 2006 6 26 5:46:43.980097
+720.00000000 3692.60030028 -976.24265255 -5623.36447493 3.897257243 6.415554948 1.429112190 2006 6 26 7:46:43.980111
+840.00000000 2301.83510037 5723.92394553 2814.61514580 -5.110924966 -0.764510559 5.662120145 2006 6 26 9:46:43.980124
+960.00000000 -4990.91637950 -2303.42547880 3920.86335598 -0.993439372 -5.967458360 -4.759110856 2006 6 26 11:46:43.980097
+1080.00000000 642.27769977 -4332.89821901 -5183.31523910 5.720542579 4.216573838 -2.846576139 2006 6 26 13:46:43.980111
+1200.00000000 4719.78335752 4798.06938996 -943.58851062 -2.294860662 3.492499389 6.408334723 2006 6 26 15:46:43.980124
+1320.00000000 -3299.16993602 1576.83168320 5678.67840638 -4.460347074 -6.202025196 -0.885874586 2006 6 26 17:46:43.980097
+1440.00000000 -2777.14682335 -5663.16031708 -2462.54889123 4.915493146 0.123328992 -5.896495091 2006 6 26 19:46:43.980111
+1560.00000000 4992.31573893 1716.62356770 -4287.86065581 1.640717189 6.071570434 4.338797931 2006 6 26 21:46:43.980124
+1680.00000000 -8.22384755 4662.21521668 4905.66411857 -5.891011274 -3.593173872 3.365100460 2006 6 26 23:46:43.980097
+1800.00000000 -4966.20137963 -4379.59155037 1349.33347502 1.763172581 -3.981456387 -6.343279443 2006 6 27 1:46:43.980111
+1920.00000000 2954.49390331 -2080.65984650 -5754.75038057 4.895893306 5.858184322 0.375474825 2006 6 27 3:46:43.980124
+2040.00000000 3363.28794321 5559.55841180 1956.05542266 -4.587378863 0.591943403 6.107838605 2006 6 27 5:46:43.980097
+2160.00000000 -4856.66780070 -1107.03450192 4557.21258241 -2.304158557 -6.186437070 -3.956549542 2006 6 27 7:46:43.980111
+2280.00000000 -497.84480071 -4863.46005312 -4700.81211217 5.960065407 2.996683369 -3.767123329 2006 6 27 9:46:43.980124
+2400.00000000 5241.61936096 3910.75960683 -1857.93473952 -1.124834806 4.406213160 6.148161299 2006 6 27 11:46:43.980097
+2520.00000000 -2451.38045953 2610.60463261 5729.79022069 -5.366560525 -5.500855666 0.187958716 2006 6 27 13:46:43.980111
+2640.00000000 -3791.87520638 -5378.82851382 -1575.82737930 4.266273592 -1.199162551 -6.276154080 2006 6 27 15:46:43.980124
+2760.00000000 4730.53958356 524.05006433 -4857.29369725 2.918056288 6.135412849 3.495115636 2006 6 27 17:46:43.980097
+2880.00000000 1159.27802897 5056.60175495 4353.49418579 -5.968060341 -2.314790406 4.230722669 2006 6 27 19:46:43.980111
+8195 xx
+0.00000000 2349.89483350 -14785.93811562 0.02119378 2.721488096 -3.256811655 4.498416672
+120.00000000 15223.91713658 -17852.95881713 25280.39558224 1.079041732 0.875187372 2.485682813 2006 6 25 9:58:18.143649
+240.00000000 19752.78050009 -8600.07130962 37522.72921090 0.238105279 1.546110924 0.986410447 2006 6 25 11:58:18.143622
+360.00000000 19089.29762968 3107.89495018 39958.14661370 -0.410308034 1.640332277 -0.306873818 2006 6 25 13:58:18.143636
+480.00000000 13829.66070574 13977.39999817 32736.32082508 -1.065096849 1.279983299 -1.760166075 2006 6 25 15:58:18.143649
+600.00000000 3333.05838525 18395.31728674 12738.25031238 -1.882432221 -0.611623333 -4.039586549 2006 6 25 17:58:18.143622
+720.00000000 2622.13222207 -15125.15464924 474.51048398 2.688287199 -3.078426664 4.494979530 2006 6 25 19:58:18.143636
+840.00000000 15320.56770017 -17777.32564586 25539.53198382 1.064346229 0.892184771 2.459822414 2006 6 25 21:58:18.143649
+960.00000000 19769.70267785 -8458.65104454 37624.20130236 0.229304396 1.550363884 0.966993056 2006 6 25 23:58:18.143622
+1080.00000000 19048.56201523 3260.43223119 39923.39143967 -0.418015536 1.639346953 -0.326094840 2006 6 26 1:58:18.143636
+1200.00000000 13729.19205837 14097.70014810 32547.52799890 -1.074511043 1.270505211 -1.785099927 2006 6 26 3:58:18.143649
+1320.00000000 3148.86165643 18323.19841703 12305.75195578 -1.895271701 -0.678343847 -4.086577951 2006 6 26 5:58:18.143622
+1440.00000000 2890.80638268 -15446.43952300 948.77010176 2.654407490 -2.909344895 4.486437362 2006 6 26 7:58:18.143636
+1560.00000000 15415.98410712 -17699.90714437 25796.19644689 1.049818334 0.908822332 2.434107329 2006 6 26 9:58:18.143649
+1680.00000000 19786.00618538 -8316.74570581 37723.74539119 0.220539813 1.554518900 0.947601047 2006 6 26 11:58:18.143622
+1800.00000000 19007.28688729 3412.85948715 39886.66579255 -0.425733568 1.638276809 -0.345353807 2006 6 26 13:58:18.143636
+1920.00000000 13627.93015254 14216.95401307 32356.13706868 -1.083991976 1.260802347 -1.810193903 2006 6 26 15:58:18.143649
+2040.00000000 2963.26486560 18243.85063641 11868.25797486 -1.908015447 -0.747870342 -4.134004492 2006 6 26 17:58:18.143622
+2160.00000000 3155.85126036 -15750.70393364 1422.32496953 2.620085624 -2.748990396 4.473527039 2006 6 26 19:58:18.143636
+2280.00000000 15510.15191770 -17620.71002219 26050.43525345 1.035454678 0.925111006 2.408534465 2006 6 26 21:58:18.143649
+2400.00000000 19801.67198812 -8174.33337167 37821.38577439 0.211812700 1.558576937 0.928231880 2006 6 26 23:58:18.143622
+2520.00000000 18965.46529379 3565.19666242 39847.97510998 -0.433459945 1.637120585 -0.364653213 2006 6 27 1:58:18.143636
+2640.00000000 13525.88227400 14335.15978787 32162.13236536 -1.093537945 1.250868256 -1.835451681 2006 6 27 3:58:18.143649
+2760.00000000 2776.30574260 18156.98538451 11425.73046481 -1.920632199 -0.820370733 -4.181839232 2006 6 27 5:58:18.143622
+2880.00000000 3417.20931587 -16038.79510665 1894.74934058 2.585515864 -2.596818146 4.456882556 2006 6 27 7:58:18.143636
+9880 xx
+0.00000000 13020.06750784 -2449.07193500 1.15896030 4.247363935 1.597178501 4.956708611
+120.00000000 19190.32482476 9249.01266902 26596.71345328 -0.624960193 1.324550562 2.495697637 2006 6 25 15:28:40.058423
+240.00000000 11332.67806218 16517.99124008 38569.78482991 -1.400974747 0.710947006 0.923935636 2006 6 25 17:28:40.058396
+360.00000000 328.74217398 19554.92047380 40558.26246145 -1.593281066 0.126772913 -0.359627307 2006 6 25 19:28:40.058410
+480.00000000 -10684.90590680 18057.15728839 33158.75253886 -1.383205997 -0.582328999 -1.744412556 2006 6 25 21:28:40.058423
+600.00000000 -17069.78000550 9944.86797897 13885.91649059 0.044133354 -1.853448464 -3.815303117 2006 6 25 23:28:40.058396
+720.00000000 13725.09398980 -2180.70877090 863.29684523 3.878478111 1.656846496 4.944867241 2006 6 26 1:28:40.058410
+840.00000000 19089.63879226 9456.29670247 27026.79562883 -0.656614299 1.309112636 2.449371941 2006 6 26 3:28:40.058423
+960.00000000 11106.41248373 16627.60874079 38727.35140296 -1.409722680 0.698582526 0.891383535 2006 6 26 5:28:40.058396
+1080.00000000 72.40958621 19575.08054144 40492.12544001 -1.593394604 0.113655142 -0.390556063 2006 6 26 7:28:40.058410
+1200.00000000 -10905.89252576 17965.41205111 32850.07298244 -1.371396120 -0.601706604 -1.782817058 2006 6 26 9:28:40.058423
+1320.00000000 -17044.61207568 9635.48491849 13212.59462953 0.129244030 -1.903551430 -3.884569098 2006 6 26 11:28:40.058396
+1440.00000000 14369.90303735 -1903.85601062 1722.15319853 3.543393116 1.701687176 4.913881358 2006 6 26 13:28:40.058410
+1560.00000000 18983.96210441 9661.12233804 27448.99557732 -0.687189304 1.293808870 2.403630759 2006 6 26 15:28:40.058423
+1680.00000000 10878.79336704 16735.31433954 38879.23434264 -1.418239666 0.686235750 0.858951848 2006 6 26 17:28:40.058396
+1800.00000000 -184.03743100 19593.09371709 40420.40606889 -1.593348925 0.100448697 -0.421571993 2006 6 26 19:28:40.058410
+1920.00000000 -11125.12138631 17870.19488928 32534.21521208 -1.359116236 -0.621413776 -1.821629856 2006 6 26 21:28:40.058423
+2040.00000000 -17004.43272827 9316.53926351 12526.11883812 0.220330736 -1.955594322 -3.955058575 2006 6 26 23:28:40.058396
+2160.00000000 14960.06492693 -1620.68430805 2574.96359381 3.238634028 1.734723385 4.868880331 2006 6 27 1:28:40.058410
+2280.00000000 18873.46347257 9863.57004586 27863.46574735 -0.716736981 1.278632817 2.358448535 2006 6 27 3:28:40.058423
+2400.00000000 10649.86857581 16841.14172669 39025.48035006 -1.426527152 0.673901057 0.826632332 2006 6 27 5:28:40.058396
+2520.00000000 -440.53459323 19608.95524423 40343.10675451 -1.593138597 0.087147884 -0.452680559 2006 6 27 7:28:40.058410
+2640.00000000 -11342.45028909 17771.44223942 32211.12535721 -1.346344015 -0.641464291 -1.860864234 2006 6 27 9:28:40.058423
+2760.00000000 -16948.06005711 8987.64254880 11826.28284367 0.318007297 -2.009693492 -4.026726648 2006 6 27 11:28:40.058396
+2880.00000000 15500.53445068 -1332.90981042 3419.72315308 2.960917974 1.758331634 4.813698638 2006 6 27 13:28:40.058410
+9998 xx
+0.00000000 25532.98947267 -27244.26327953 -1.11572421 2.410283885 2.194175683 0.545888526
+-1440.00000000 -11362.18265118 -35117.55867813 -5413.62537994 3.137861261 -1.011678260 0.267510059 2005 5 27 19:03:37.089777
+-1380.00000000 309.25349929 -36960.43090143 -4198.48007670 3.292429375 -0.002166046 0.402111628 2005 5 27 20:03:37.089763
+-1320.00000000 11949.04009077 -35127.37816804 -2565.89806468 3.119942784 1.012096444 0.497284100 2005 5 27 21:03:37.089790
+-1260.00000000 22400.45329336 -29798.63236321 -677.91515122 2.638533344 1.922477736 0.542792913 2005 5 27 22:03:37.089777
+-1200.00000000 30640.84752458 -21525.02340201 1277.34808722 1.903464941 2.634294312 0.534540934 2005 5 27 23:03:37.089763
+-1140.00000000 35899.56788035 -11152.71158138 3108.72535238 0.997393045 3.079858548 0.474873291 2005 5 28 0:03:37.089790
+-1080.00000000 37732.45438600 288.18821054 4643.87587495 0.016652226 3.225184410 0.371669746 2005 5 28 1:03:37.089777
+-1020.00000000 36045.92961699 11706.61816230 5746.32646574 -0.942409065 3.069888941 0.236662980 2005 5 28 2:03:37.089763
+-960.00000000 31076.77273609 22063.44379776 6325.93403705 -1.794027976 2.642072476 0.083556127 2005 5 28 3:03:37.089790
+-900.00000000 23341.26015320 30460.88002531 6342.91707895 -2.469409743 1.990861658 -0.073612096 2005 5 28 4:03:37.089777
+-840.00000000 13568.39733054 36204.45930900 5806.79548733 -2.919354203 1.178920217 -0.221646814 2005 5 28 5:03:37.089763
+-780.00000000 2628.58762420 38840.10855897 4771.91979854 -3.114400514 0.276239109 -0.348926401 2005 5 28 6:03:37.089790
+-720.00000000 -8535.81598158 38171.79073851 3331.00311285 -3.043839958 -0.644462527 -0.445808894 2005 5 28 7:03:37.089777
+11801 xx
+0.00000000 7473.37102491 428.94748312 5828.74846783 5.107155391 6.444680305 -0.186133297
+360.00000000 -3305.22148694 32410.84323331 -24697.16974954 -1.301137319 -1.151315600 -0.283335823 1980 8 17 13:06:40.136822
+720.00000000 14271.29083858 24110.44309009 -4725.76320143 -0.320504528 2.679841539 -2.084054355 1980 8 17 19:06:40.136822
+1080.00000000 -9990.05800009 22717.34212448 -23616.88515553 -1.016674392 -2.290267981 0.728923337 1980 8 18 1:06:40.136822
+1440.00000000 9787.87836256 33753.32249667 -15030.79874625 -1.094251553 0.923589906 -1.522311008 1980 8 18 7:06:40.136822
+14128 xx
+0.00000000 34747.57932696 24502.37114079 -1.32832986 -1.731642662 2.452772615 0.608510081
+120.00000000 18263.33439094 38159.96004751 4186.18304085 -2.744396611 1.255583260 0.528558932 2006 6 25 2:40:57.987566
+240.00000000 -3023.38840703 41783.13186459 7273.03412906 -3.035574793 -0.271656544 0.309645251 2006 6 25 4:40:57.987539
+360.00000000 -23516.34391907 34424.42065671 8448.49867693 -2.529120477 -1.726186020 0.009582303 2006 6 25 6:40:57.987553
+480.00000000 -37837.46699511 18028.39727170 7406.25540271 -1.360069525 -2.725794686 -0.292555349 2006 6 25 8:40:57.987566
+600.00000000 -42243.58460661 -3093.72887774 4422.91711801 0.163110919 -3.009980598 -0.517584362 2006 6 25 10:40:57.987539
+720.00000000 -35597.57919549 -23407.91145393 282.09554383 1.641405246 -2.506773678 -0.606963478 2006 6 25 12:40:57.987553
+840.00000000 -19649.19834455 -37606.11623860 -3932.71525948 2.689647056 -1.349150016 -0.537710698 2006 6 25 14:40:57.987566
+960.00000000 1431.30912160 -41982.04949668 -7120.45467057 3.035263353 0.160882945 -0.327993994 2006 6 25 16:40:57.987539
+1080.00000000 22136.97605384 -35388.19823762 -8447.62393401 2.587624889 1.630097136 -0.032349004 2006 6 25 18:40:57.987553
+1200.00000000 37050.15790219 -19537.23321425 -7564.83463543 1.461844494 2.674654256 0.272202191 2006 6 25 20:40:57.987566
+1320.00000000 42253.81760945 1431.81867593 -4699.87621174 -0.049247334 3.019518960 0.505890058 2006 6 25 22:40:57.987539
+1440.00000000 36366.59147396 22023.54245720 -601.47121821 -1.549681546 2.571788981 0.607057418 2006 6 26 0:40:57.987553
+1560.00000000 20922.12287985 36826.33975981 3654.91125886 -2.644070068 1.447521216 0.548722983 2006 6 26 2:40:57.987566
+1680.00000000 -23.77224182 41945.51688402 6950.29891751 -3.043358385 -0.057417440 0.346112094 2006 6 26 4:40:57.987539
+1800.00000000 -20964.17821076 36039.06206172 8418.91984963 -2.642795221 -1.546099886 0.052725852 2006 6 26 6:40:57.987553
+1920.00000000 -36401.63863057 20669.75286162 7677.19769359 -1.549488154 -2.627052310 -0.254079652 2006 6 26 8:40:57.987566
+2040.00000000 -42298.30327543 -119.03351118 4922.96388841 -0.052232768 -3.018152669 -0.493827331 2006 6 26 10:40:57.987539
+2160.00000000 -37125.62383511 -20879.63058368 879.86971348 1.456499841 -2.619358421 -0.604081694 2006 6 26 12:40:57.987553
+2280.00000000 -22250.12320553 -36182.74736487 -3393.15365183 2.583161226 -1.536647628 -0.556404555 2006 6 26 14:40:57.987566
+2400.00000000 -1563.06258654 -42035.43179159 -6780.02161760 3.034917506 -0.052702046 -0.363395654 2006 6 26 16:40:57.987539
+2520.00000000 19531.64069587 -36905.65470956 -8395.46892032 2.693682199 1.446079999 -0.075256054 2006 6 26 18:40:57.987553
+2640.00000000 35516.53506142 -22123.71916638 -7815.04516935 1.646882125 2.568416058 0.232985912 2006 6 26 20:40:57.987566
+2760.00000000 42196.03535976 -1547.32646751 -5187.39401981 0.166491841 3.019211549 0.480665780 2006 6 26 22:40:57.987539
+2880.00000000 37802.25393045 19433.57330019 -1198.66634226 -1.359930580 2.677830903 0.602507466 2006 6 27 0:40:57.987553
+16925 xx
+0.00000000 5559.11686836 -11941.04090781 -19.41235206 3.392116762 -1.946985124 4.250755852
+120.00000000 12339.83273749 -2771.14447871 18904.57603433 -0.871247614 2.600917693 0.581560002 2006 5 31 18:10:47.226141
+240.00000000 -3385.00215658 7538.13955729 200.59008616 -2.023512865 -4.261808344 -6.856385787 2006 5 31 20:10:47.226115
+360.00000000 12805.22442200 -10258.94667177 13780.16486738 0.619279224 1.821510542 2.507365975 2006 5 31 22:10:47.226128
+480.00000000 5682.46556318 7199.30270473 15437.67134070 -2.474365406 2.087897336 -2.583767460 2006 6 1 0:10:47.226141
+600.00000000 7628.94243982 -12852.72097492 2902.87208981 2.748131081 -0.740084579 4.125307943 2006 6 1 2:10:47.226115
+720.00000000 11531.64866625 -858.27542736 19086.85993771 -1.170071901 2.660311986 0.096005705 2006 6 1 4:10:47.226128
+840.00000000 -3866.98069515 2603.73442786 -4577.36484577 1.157257298 -8.453281164 -4.683959407 2006 6 1 6:10:47.226141
+960.00000000 13054.77732721 -8707.92757730 15537.63259903 0.229846748 2.119467054 2.063396852 2006 6 1 8:10:47.226115
+1080.00000000 3496.91064652 8712.83919778 12845.81838327 -2.782184997 1.552950644 -3.554436131 2006 6 1 10:10:47.226128
+1200.00000000 9593.07424729 -13023.75963608 6250.46484931 2.072666376 0.278735334 3.778111073 2006 6 1 12:10:47.226141
+1320.00000000 10284.79205084 1487.89914169 18824.37381327 -1.530335053 2.663107730 -0.542205966 2006 6 1 14:10:47.226115
+1440.00000000 -984.62035146 -5187.03480813 -5745.59594144 4.340271916 -7.266811354 1.777668888 2006 6 1 16:10:47.226128
+20413 xx
+0.00000000 25123.29290741 -13225.49966286 3249.40351869 0.488683419 4.797897593 -0.961119693
+1440.00000000 -151669.05280515 -5645.20454550 -2198.51592118 -0.869182889 -0.870759872 0.156508219 2005 12 30 19:00:00.000268
+1560.00000000 -157497.71657495 -11884.99595074 -1061.44439402 -0.749657961 -0.864016715 0.157766101 2005 12 30 21:00:00.000282
+1680.00000000 -162498.32255577 -18062.99733167 81.00915253 -0.638980378 -0.853687105 0.158098992 2005 12 30 23:00:00.000255
+1800.00000000 -166728.76010920 -24155.99648299 1222.84128677 -0.535600687 -0.840455444 0.157680857 2005 12 31 1:00:00.000268
+1920.00000000 -169935.81924592 -31767.29787964 2749.01540345 -0.430050431 -0.828904183 0.157812340 2005 12 31 3:00:00.000282
+2040.00000000 -172703.07831815 -37662.95639336 3883.60052579 -0.338004891 -0.810277487 0.156020035 2005 12 31 5:00:00.000255
+2160.00000000 -174823.19337404 -43417.55605219 5003.26312809 -0.250258622 -0.789828672 0.153764903 2005 12 31 7:00:00.000268
+2280.00000000 -176324.63925775 -49018.51958648 6104.85025002 -0.166136613 -0.767706262 0.151092242 2005 12 31 9:00:00.000282
+2400.00000000 -177231.42142458 -54454.12699497 7185.48661607 -0.085067854 -0.744001567 0.148033403 2005 12 31 11:00:00.000255
+2520.00000000 -177563.73583232 -59713.14859144 8242.48472591 -0.006561730 -0.718760309 0.144608676 2005 12 31 13:00:00.000267
+2640.00000000 -177338.48026483 -64784.54644698 9273.27220003 0.069809946 -0.691990238 0.140829236 2005 12 31 15:00:00.000281
+2760.00000000 -176569.65151461 -69657.21976255 10275.33063459 0.144426878 -0.663665876 0.136698419 2005 12 31 17:00:00.000254
+2880.00000000 -175268.65299073 -74319.77625463 11246.14177160 0.217631370 -0.633731091 0.132212491 2005 12 31 19:00:00.000267
+3000.00000000 -173444.53039609 -78760.31560396 12183.13775212 0.289737325 -0.602099929 0.127361017 2005 12 31 21:00:00.000281
+3120.00000000 -171104.14813653 -82966.21323591 13083.65278381 0.361037779 -0.568655903 0.122126889 2005 12 31 23:00:00.000254
+3240.00000000 -168252.31543803 -86923.89363433 13944.87382716 0.431811396 -0.533249797 0.116486022 2006 1 1 0:59:59.000268
+3360.00000000 -164891.86832887 -90618.58225954 14763.78794247 0.502328269 -0.495695896 0.110406725 2006 1 1 2:59:59.000282
+3480.00000000 -161023.71139825 -94034.02398835 15537.12375729 0.572855321 -0.455766412 0.103848688 2006 1 1 4:59:59.000255
+3600.00000000 -156646.82136726 -97152.15370791 16261.28409305 0.643661538 -0.413183688 0.096761524 2006 1 1 6:59:59.000268
+3720.00000000 -151758.21285737 -99952.70098346 16932.26607548 0.715023254 -0.367609561 0.089082727 2006 1 1 8:59:59.000282
+3840.00000000 -146352.86521283 -102412.70506284 17545.56394158 0.787229695 -0.318630913 0.080734873 2006 1 1 10:59:59.000255
+3960.00000000 -140423.60777444 -104505.90799734 18096.04807097 0.860588979 -0.265739987 0.071621768 2006 1 1 12:59:59.000268
+4080.00000000 -133960.95961851 -106201.98091318 18577.81121953 0.935434758 -0.208307307 0.061623110 2006 1 1 14:59:59.000282
+4200.00000000 -126952.91860010 -107465.51906186 18983.96903112 1.012133628 -0.145543878 0.050587007 2006 1 1 16:59:59.000255
+4320.00000000 -119384.69396454 -108254.71115372 19306.39581892 1.091093313 -0.076447479 0.038319282 2006 1 1 18:59:59.000268
+21897 xx
+0.00000000 -14464.72135182 -4699.19517587 0.06681686 -3.249312013 -3.281032707 4.007046940
+120.00000000 -19410.46286123 -19143.03318969 23114.05522619 0.508602237 -1.156882269 2.379923455 2006 6 25 2:33:42.834827
+240.00000000 -12686.06129708 -23853.75335645 35529.81733588 1.231633829 -0.221718202 1.118440291 2006 6 25 4:33:42.834800
+360.00000000 -2775.46649359 -22839.64574119 39494.64689967 1.468963405 0.489481769 -0.023972788 2006 6 25 6:33:42.834814
+480.00000000 7679.87883570 -16780.50760106 34686.21815555 1.364171080 1.211183897 -1.385151371 2006 6 25 8:33:42.834827
+600.00000000 14552.40023028 -4819.50121461 17154.70672449 0.109201591 2.176124494 -3.854856805 2006 6 25 10:33:42.834800
+720.00000000 -15302.38845375 -5556.43440300 1095.95088753 -2.838224312 -3.134231137 3.992596326 2006 6 25 12:33:42.834814
+840.00000000 -19289.20066748 -19427.04851118 23759.45685636 0.552495087 -1.112499437 2.325112654 2006 6 25 14:33:42.834827
+960.00000000 -12376.21976437 -23893.38020018 35831.33691892 1.246701529 -0.194294048 1.074867282 2006 6 25 16:33:42.834800
+1080.00000000 -2400.55677665 -22698.62264640 39482.75964390 1.472582922 0.513555654 -0.069306561 2006 6 25 18:33:42.834814
+1200.00000000 8031.66819252 -16455.77592085 34298.94391742 1.351357426 1.239633234 -1.448195324 2006 6 25 20:33:42.834827
+1320.00000000 14559.48780372 -4238.43773813 16079.23154704 -0.026409655 2.218938770 -4.012628896 2006 6 25 22:33:42.834800
+1440.00000000 -16036.04980660 -6372.51406468 2183.44834232 -2.485113443 -2.994994355 3.955891272 2006 6 26 0:33:42.834814
+1560.00000000 -19156.71583814 -19698.89059957 24389.29473934 0.594278133 -1.069418599 2.271152044 2006 6 26 2:33:42.834827
+1680.00000000 -12062.72925552 -23925.82362911 36120.66680667 1.261238798 -0.167201856 1.031478939 2006 6 26 4:33:42.834800
+1800.00000000 -2024.96136966 -22551.56626703 39458.50085787 1.475816889 0.537615764 -0.114887472 2006 6 26 6:33:42.834814
+1920.00000000 8379.80916204 -16123.95878459 33894.75123231 1.337468254 1.268432783 -1.512473301 2006 6 26 8:33:42.834827
+2040.00000000 14527.86748873 -3646.33817120 14960.74306518 -0.180035839 2.261273515 -4.179355590 2006 6 26 10:33:42.834800
+2160.00000000 -16680.12147335 -7149.80800425 3257.64227208 -2.178897351 -2.863927095 3.904876943 2006 6 26 12:33:42.834814
+2280.00000000 -19013.58793448 -19958.93766022 25003.81778666 0.634100431 -1.027559823 2.218002685 2006 6 26 14:33:42.834827
+2400.00000000 -11745.76155818 -23951.19438627 36397.87676581 1.275261813 -0.140425132 0.988259441 2006 6 26 16:33:42.834800
+2520.00000000 -1648.81945070 -22398.50594576 39421.83273890 1.478660174 0.561671519 -0.160733093 2006 6 26 18:33:42.834814
+2640.00000000 8723.97652795 -15784.99406275 33473.35215527 1.322433593 1.297602497 -1.578055493 2006 6 26 20:33:42.834827
+2760.00000000 14452.25571587 -3043.42332645 13796.84870805 -0.355190169 2.302485443 -4.355767077 2006 6 26 22:33:42.834800
+2880.00000000 -17246.31075678 -7890.72601508 4315.39410307 -1.910968458 -2.740945672 3.844722726 2006 6 27 0:33:42.834814
+22312 xx
+0.00000000 1442.10132912 6510.23625449 8.83145885 -3.475714837 0.997262768 6.835860345
+54.20286720 306.10478453 -5816.45655525 -2979.55846068 3.950663855 3.415332543 -5.879974329 2006 4 4 12:00:00.000000
+74.20286720 3282.82085464 2077.46972905 -5189.17988770 0.097342701 7.375135692 2.900196702 2006 4 4 12:20:00.000009
+94.20286720 530.82729176 6426.20790003 1712.37076793 -3.837120395 -1.252430637 6.561602577 2006 4 4 12:40:00.000018
+114.20286720 -3191.69170212 170.27219912 5956.29807775 -1.394956872 -7.438073471 -0.557553115 2006 4 4 13:00:00.000027
+134.20286720 -1818.99222465 -6322.45146616 681.95247154 3.349795173 -1.530140265 -6.831522765 2006 4 4 13:19:59.999996
+154.20286720 2515.66448634 -2158.83091224 -5552.13320544 2.571979660 7.311930509 -1.639865620 2006 4 4 13:40:00.000004
+174.20286720 2414.52833210 5749.10150922 -1998.59693165 -2.681032960 3.527589301 6.452951429 2006 4 4 14:00:00.000013
+194.20286720 -1877.98944331 3862.27848302 5112.48435863 -3.261489804 -6.026859137 3.433254768 2006 4 4 14:20:00.000022
+214.20286720 -3117.36584395 -4419.74773864 3840.85960912 1.545479182 -5.475416581 -5.207913748 2006 4 4 14:40:00.000031
+234.20286720 815.32034678 -5231.67692249 -3760.04690354 3.870864200 4.455588552 -5.211082191 2006 4 4 15:00:00.000000
+254.20286720 3269.54341810 3029.00081083 -4704.67969713 -0.526711345 6.812157950 3.929825087 2006 4 4 15:20:00.000009
+274.20286720 -10.18099756 6026.23341453 2643.50518407 -3.953623254 -2.616070012 6.145637500 2006 4 4 15:40:00.000018
+294.20286720 -3320.58819584 -1248.42679945 5563.06017927 -0.637046974 -7.417786044 -2.076120187 2006 4 4 16:00:00.000027
+314.20286720 -1025.48974616 -6366.98945782 -911.23559153 3.811771909 0.438071490 -6.829260617 2006 4 4 16:19:59.999996
+334.20286720 3003.75996128 -413.85708003 -5706.15591435 1.674350083 7.694169068 0.316915204 2006 4 4 16:40:00.000004
+354.20286720 1731.42816980 6258.27676925 -409.32527982 -3.400497806 1.447945424 6.904010052 2006 4 4 17:00:00.000013
+374.20286720 -2582.52111460 2024.19020680 5647.55650268 -2.530348121 -7.221719393 1.438141553 2006 4 4 17:20:00.000022
+394.20286720 -2440.56848578 -5702.77311877 1934.81094689 2.731792947 -3.350576075 -6.527773339 2006 4 4 17:40:00.000031
+414.20286720 1951.22934391 -3423.59443045 -5121.67808201 3.249039133 6.465974362 -3.069806659 2006 4 4 18:00:00.000000
+434.20286720 2886.50939356 4888.68626216 -3096.29885989 -1.973162139 4.877039020 5.832414910 2006 4 4 18:20:00.000009
+454.20286720 -1276.55532182 4553.26898463 4406.19787375 -3.715146421 -5.320176914 4.418210777 2006 4 4 18:40:00.000018
+474.20286720 -3181.54698042 -3831.29976506 4096.80242787 1.114159970 -6.104773578 -4.829967400 2006 4 4 19:00:00.000027
+22674 xx
+0.00000000 14712.22023280 -1443.81061850 0.83497888 4.418965470 1.629592098 4.115531802
+120.00000000 25418.88807860 9342.60307989 23611.46690798 0.051284086 1.213127306 2.429004159 2006 6 25 15:25:05.468479
+240.00000000 21619.59550749 16125.24978864 36396.79365831 -0.963604380 0.685454965 1.177181937 2006 6 25 17:25:05.468452
+360.00000000 12721.50543331 19258.96193362 40898.47648359 -1.457448565 0.179955469 0.071502601 2006 6 25 19:25:05.468465
+480.00000000 1272.80760054 18458.41971897 37044.74742696 -1.674863386 -0.436454983 -1.201040990 2006 6 25 21:25:05.468479
+600.00000000 -10058.43188619 11906.60764454 21739.62097733 -1.245829683 -1.543789125 -3.324449221 2006 6 25 23:25:05.468452
+720.00000000 10924.40116466 -2571.92414170 -2956.34856294 6.071727751 1.349579102 3.898430260 2006 6 26 1:25:05.468465
+840.00000000 25332.14851525 8398.91099924 21783.90654357 0.222320754 1.272214306 2.580527192 2006 6 26 3:25:05.468479
+960.00000000 22317.71926039 15574.82086129 35495.77144092 -0.892750056 0.737383381 1.291738834 2006 6 26 5:25:05.468452
+1080.00000000 13795.68675885 19088.83051008 40803.69584385 -1.420277669 0.235599456 0.185517056 2006 6 26 7:25:05.468465
+1200.00000000 2515.17145049 18746.63776282 37864.58088636 -1.668016053 -0.360431458 -1.052854596 2006 6 26 9:25:05.468479
+1320.00000000 -9084.48602106 12982.62608646 24045.63900249 -1.378032363 -1.373184736 -3.013963835 2006 6 26 11:25:05.468452
+1440.00000000 5647.00909495 -3293.90518693 -5425.85235063 8.507977176 0.414560797 2.543322806 2006 6 26 13:25:05.468465
+1560.00000000 25111.63372210 7412.55109488 19844.25781729 0.416496290 1.332106006 2.739301737 2006 6 26 15:25:05.468479
+1680.00000000 22961.47461641 14985.74459578 34511.09257381 -0.816711048 0.789391108 1.407901804 2006 6 26 17:25:05.468452
+1800.00000000 14841.15301459 18876.91439870 40626.25901619 -1.380403341 0.290228810 0.298258120 2006 6 26 19:25:05.468465
+1920.00000000 3750.70174081 18978.57939698 38578.11783220 -1.656939412 -0.287930881 -0.910825599 2006 6 26 21:25:05.468479
+2040.00000000 -8027.30219489 13939.54436955 26136.49045637 -1.474476061 -1.222693624 -2.737178731 2006 6 26 23:25:05.468452
+2160.00000000 -1296.95657092 -2813.69369768 -5871.09587258 9.881929371 -1.978467207 -1.922261005 2006 6 27 1:25:05.468465
+2280.00000000 24738.60364819 6383.41644019 17787.27631900 0.639556952 1.392554379 2.906206324 2006 6 27 3:25:05.468479
+2400.00000000 23546.85388669 14358.15602832 33441.67679479 -0.734895006 0.841564851 1.526009909 2006 6 27 5:25:05.468452
+2520.00000000 15855.87696303 18624.05633582 40367.13420574 -1.337753546 0.343969522 0.410018472 2006 6 27 7:25:05.468465
+2640.00000000 4976.44933591 19156.75504042 39189.68603184 -1.642084365 -0.218525096 -0.774148204 2006 6 27 9:25:05.468479
+2760.00000000 -6909.20746210 14790.44707042 28034.46732222 -1.545152610 -1.088119523 -2.487447214 2006 6 27 11:25:05.468452
+2880.00000000 -7331.65006707 -604.17323419 -2723.51014575 6.168997265 -3.634011554 -5.963531682 2006 6 27 13:25:05.468465
+23177 xx
+0.00000000 -8801.60046706 -0.03357557 -0.44522743 -3.835279101 -7.662552175 0.944561323
+120.00000000 -1684.34352858 -31555.95196340 3888.99944319 2.023055719 -2.151306405 0.265065778 2006 6 24 12:58:49.772928
+240.00000000 12325.51410155 -38982.15046244 4802.88832275 1.763224157 -0.102514446 0.012397139 2006 6 24 14:58:49.772902
+360.00000000 22773.66831936 -34348.02176606 4228.77407391 1.067616787 1.352427865 -0.166956367 2006 6 24 16:58:49.772915
+480.00000000 26194.40441089 -19482.94203672 2393.84774063 -0.313732186 2.808771328 -0.346204118 2006 6 24 18:58:49.772928
+600.00000000 8893.50573448 5763.38890561 -713.69884164 -7.037399220 3.022613131 -0.370272416 2006 6 24 20:58:49.772902
+720.00000000 -6028.75686537 -25648.99913786 3164.37107274 1.883159288 -3.177051976 0.390793162 2006 6 24 22:58:49.772915
+840.00000000 8313.57299056 -38146.45710922 4697.80777535 1.905002133 -0.625883074 0.076098187 2006 6 25 0:58:49.772928
+960.00000000 20181.29108622 -36842.60674073 4529.12568218 1.326244476 0.921916487 -0.114527455 2006 6 25 2:58:49.772902
+1080.00000000 26302.61794569 -25173.39539436 3084.65309986 0.245398835 2.329974347 -0.287495880 2006 6 25 4:58:49.772915
+1200.00000000 19365.07045602 -2700.00490122 317.42727417 -3.009733018 3.902496058 -0.478928582 2006 6 25 6:58:49.772928
+1320.00000000 -9667.81878780 -16930.19112642 2095.87469034 1.279288285 -4.736005905 0.582878255 2006 6 25 8:58:49.772902
+1440.00000000 4021.31438583 -36066.09209609 4442.91587411 2.007322354 -1.227461376 0.149383897 2006 6 25 10:58:49.772915
+23333 xx
+0.00000000 -9301.24542292 3326.10200382 2318.36441127 -8.729303005 -0.828225037 -0.122314827
+120.00000000 -44672.91239680 -6213.11996581 -1738.80131727 -3.719475070 -1.336673022 -0.621888261 1994 11 1 13:59:59.999169
+240.00000000 -67053.08885388 -14994.69685946 -5897.99072793 -2.860576613 -1.183771565 -0.568473909 1994 11 1 15:59:59.999142
+360.00000000 -85227.84253168 -22897.08484471 -9722.59184564 -2.426469823 -1.078592475 -0.525341431 1994 11 1 17:59:59.999155
+480.00000000 -100986.00419136 -30171.19698695 -13283.77044765 -2.147108978 -1.000530827 -0.491587582 1994 11 1 19:59:59.999169
+600.00000000 -115093.00686387 -36962.56316477 -16634.15682929 -1.945446188 -0.938947736 -0.464199202 1994 11 1 21:59:59.999142
+720.00000000 -127965.80064891 -43363.32967165 -19809.90480432 -1.789652016 -0.888278463 -0.441254468 1994 11 1 23:59:59.999155
+840.00000000 -139863.28332207 -49436.45704153 -22836.80438139 -1.663762568 -0.845315913 -0.421548627 1994 11 2 1:59:59.999169
+960.00000000 -150960.22978259 -55227.45413896 -25734.01408879 -1.558730986 -0.808061065 -0.404293846 1994 11 2 3:59:59.999142
+1080.00000000 -161381.71414630 -60770.64040903 -28516.26290017 -1.468977174 -0.775190459 -0.388951810 1994 11 2 5:59:59.999155
+1200.00000000 -171221.18736947 -66092.76474442 -31195.19847387 -1.390837596 -0.745785633 -0.375140398 1994 11 2 7:59:59.999169
+1320.00000000 -180550.82888746 -71215.23290630 -33780.24938270 -1.321788672 -0.719184752 -0.362579495 1994 11 2 9:59:59.999142
+1440.00000000 -189427.87533074 -76155.54943344 -36279.19882816 -1.260024473 -0.694896053 -0.351058133 1994 11 2 11:59:59.999155
+1560.00000000 -197898.69401409 -80928.29015181 -38698.57972447 -1.204211888 -0.672544709 -0.340413731 1994 11 2 13:59:59.999169
+1600.00000000 -200638.82986236 -82484.14969882 -39488.34331447 -1.186748462 -0.665472422 -0.337037582 1994 11 2 14:39:59.999146
+23599 xx
+0.00000000 9892.63794341 35.76144969 -1.08228838 3.556643237 6.456009375 0.783610890
+20.00000000 11931.95642997 7340.74973750 886.46365987 0.308329116 5.532328972 0.672887281 2006 6 20 18:42:06.640047
+40.00000000 11321.71039205 13222.84749156 1602.40119049 -1.151973982 4.285810871 0.521919425 2006 6 20 19:02:06.640056
+60.00000000 9438.29395675 17688.05450261 2146.59293402 -1.907904054 3.179955046 0.387692479 2006 6 20 19:22:06.640025
+80.00000000 6872.08634639 20910.11016811 2539.79945034 -2.323995367 2.207398462 0.269506121 2006 6 20 19:42:06.640034
+100.00000000 3933.37509798 23024.07662542 2798.25966746 -2.542860616 1.327134966 0.162450076 2006 6 20 20:02:06.640043
+120.00000000 816.64091546 24118.98675475 2932.69459428 -2.626838010 0.504502763 0.062344306 2006 6 20 20:22:06.640052
+140.00000000 -2334.41705804 24246.86096326 2949.36448841 -2.602259646 -0.288058266 -0.034145135 2006 6 20 20:42:06.640020
+160.00000000 -5394.31798039 23429.42716149 2850.86832586 -2.474434068 -1.074055982 -0.129868366 2006 6 20 21:02:06.640029
+180.00000000 -8233.35130237 21661.24480883 2636.51456118 -2.230845533 -1.875742344 -0.227528603 2006 6 20 21:22:06.640038
+200.00000000 -10693.96497348 18909.88168891 2302.33707548 -1.835912433 -2.716169865 -0.329931880 2006 6 20 21:42:06.640047
+220.00000000 -12553.89669904 15114.63990716 1840.93573231 -1.212478879 -3.619036996 -0.439970633 2006 6 20 22:02:06.640056
+240.00000000 -13450.20591864 10190.57904289 1241.95958736 -0.189082511 -4.596701971 -0.559173899 2006 6 20 22:22:06.640025
+260.00000000 -12686.60437121 4079.31106161 498.27078614 1.664498211 -5.559889865 -0.676747779 2006 6 20 22:42:06.640034
+280.00000000 -8672.55867753 -2827.56823315 -342.59644716 5.515079852 -5.551222962 -0.676360044 2006 6 20 23:02:06.640043
+300.00000000 1153.31498060 -6411.98692060 -779.87288941 9.689818102 1.388598425 0.167868798 2006 6 20 23:22:06.640052
+320.00000000 9542.79201056 -533.71253081 -65.73165428 3.926947087 6.459583539 0.785686755 2006 6 20 23:42:06.640020
+340.00000000 11868.80960100 6861.59590848 833.72780602 0.452957852 5.632811328 0.685262323 2006 6 21 0:02:06.640029
+360.00000000 11376.23941678 12858.97121366 1563.40660172 -1.087665695 4.374693347 0.532207051 2006 6 21 0:22:06.640038
+380.00000000 9547.70300782 17421.48570758 2118.56907515 -1.876540262 3.253891728 0.395810243 2006 6 21 0:42:06.640047
+400.00000000 7008.51470263 20725.47471227 2520.56064289 -2.308703599 2.270724438 0.276138613 2006 6 21 1:02:06.640056
+420.00000000 4083.18551180 22910.88306802 2786.35642660 -2.536610941 1.383768875 0.168165414 2006 6 21 1:22:06.640025
+440.00000000 970.13107533 24071.19896282 2927.30875440 -2.626673095 0.557274717 0.067549303 2006 6 21 1:42:06.640034
+460.00000000 -2183.75499348 24261.30188126 2950.09189560 -2.607082241 -0.236785937 -0.029112844 2006 6 21 2:02:06.640043
+480.00000000 -5252.49066783 23505.58108388 2857.68628654 -2.484465059 -1.022158411 -0.124702643 2006 6 21 2:22:06.640052
+500.00000000 -8107.41437587 21801.13395060 2649.76852683 -2.247669530 -1.821071275 -0.221914939 2006 6 21 2:42:06.640020
+520.00000000 -10594.01813094 19118.22269010 2322.77197767 -1.863224062 -2.656353699 -0.323512642 2006 6 21 3:02:06.640029
+540.00000000 -12496.70758499 15399.13096351 1869.75958053 -1.258272118 -3.551534022 -0.432332913 2006 6 21 3:22:06.640038
+560.00000000 -13467.50382653 10561.43040038 1280.84842178 -0.272050695 -4.520503543 -0.550014833 2006 6 21 3:42:06.640047
+580.00000000 -12848.00717497 4541.72432009 548.59976478 1.493938056 -5.489644146 -0.667479244 2006 6 21 4:02:06.640056
+600.00000000 -9152.79920397 -2343.88902799 -287.93741332 5.127695273 -5.650584983 -0.686013644 2006 6 21 4:22:06.640025
+620.00000000 280.12478642 -6500.11368508 -790.36236302 9.779642904 0.581430120 0.074124421 2006 6 21 4:42:06.640034
+640.00000000 9166.21406115 -1093.48756223 -129.53833135 4.316926785 6.438465969 0.785095966 2006 6 21 5:02:06.640043
+660.00000000 11794.74563870 6381.74484842 780.82775971 0.604642523 5.731705440 0.697571522 2006 6 21 5:22:06.640052
+680.00000000 11424.80363789 12493.80833338 1524.27683836 -1.021148661 4.463489406 0.542537702 2006 6 21 5:42:06.640020
+700.00000000 9652.78920084 17153.46470428 2090.43413681 -1.844382696 3.327595388 0.403924198 2006 6 21 6:02:06.640029
+720.00000000 7141.24742526 20538.97115158 2501.18059966 -2.293079623 2.333598993 0.282727441 2006 6 21 6:22:06.640038
+24208 xx
+0.00000000 7534.10987189 41266.39266843 -0.10801028 -3.027168008 0.558848996 0.207982755
+120.00000000 -14289.19940414 39469.05530051 1428.62838591 -2.893205245 -1.045447840 0.179634249 2006 6 26 2:58:29.343360
+240.00000000 -32222.92014955 26916.25425799 2468.59996594 -1.973007929 -2.359335071 0.102539376 2006 6 26 4:58:29.343334
+360.00000000 -41413.95109398 7055.51656639 2838.90906671 -0.521665080 -3.029172207 -0.002066843 2006 6 26 6:58:29.343347
+480.00000000 -39402.72251896 -14716.42475223 2441.32678358 1.066928187 -2.878714619 -0.105865729 2006 6 26 8:58:29.343360
+600.00000000 -26751.08889828 -32515.13982431 1384.38865570 2.366228869 -1.951032799 -0.181018498 2006 6 26 10:58:29.343334
+720.00000000 -6874.77975542 -41530.38329422 -46.60245459 3.027415087 -0.494671177 -0.207337260 2006 6 26 12:58:29.343347
+840.00000000 14859.52039042 -39302.58907247 -1465.02482524 2.869609883 1.100123969 -0.177514425 2006 6 26 14:58:29.343360
+960.00000000 32553.14863770 -26398.88401807 -2485.45866002 1.930064459 2.401574539 -0.099250520 2006 6 26 16:58:29.343334
+1080.00000000 41365.67576837 -6298.09965811 -2828.05254033 0.459741276 3.051680214 0.006431872 2006 6 26 18:58:29.343347
+1200.00000000 38858.83295070 15523.39314924 -2396.86850752 -1.140211488 2.867567143 0.110637217 2006 6 26 20:58:29.343360
+1320.00000000 25701.46068162 33089.42617648 -1308.68556638 -2.428713821 1.897381431 0.184605907 2006 6 26 22:58:29.343334
+1440.00000000 5501.08137100 41590.27784405 138.32522930 -3.050691874 0.409203052 0.207958133 2006 6 27 0:58:29.343347
+25954 xx
+0.00000000 8827.15660472 -41223.00971237 3.63482963 3.007087319 0.643701323 0.000941663
+-1440.00000000 8118.18519221 -41368.40537378 4.11046687 3.017696741 0.591994297 0.000933016 2004 2 7 16:20:01.494254
+-1320.00000000 27766.34015328 -31724.97000557 9.93297846 2.314236153 2.024903193 0.000660861 2004 2 7 18:20:01.494268
+-1200.00000000 39932.57237973 -13532.60040454 13.12958252 0.987382819 2.911942843 0.000213298 2004 2 7 20:20:01.494241
+-1080.00000000 41341.01365441 8305.71681955 12.84988501 -0.605098224 3.014378268 -0.000291034 2004 2 7 22:20:01.494254
+-960.00000000 31614.99210558 27907.29155353 9.16618797 -2.034243523 2.305014102 -0.000718418 2004 2 8 0:20:01.494268
+-840.00000000 13375.75227587 39994.27017651 3.05416854 -2.915424366 0.975119874 -0.000955576 2004 2 8 2:20:01.494241
+-720.00000000 -8464.89963309 41312.93549892 -3.86622919 -3.011600615 -0.617275050 -0.000939664 2004 2 8 4:20:01.494254
+-600.00000000 -28026.23406158 31507.89995661 -9.76047869 -2.296840160 -2.043607595 -0.000674889 2004 2 8 6:20:01.494268
+-480.00000000 -40040.01314363 13218.00579413 -13.06594832 -0.963328772 -2.919827983 -0.000231414 2004 2 8 8:20:01.494241
+-360.00000000 -41268.43291976 -8632.06859693 -12.90661266 0.630042315 -3.009677376 0.000273163 2004 2 8 10:20:01.494254
+-240.00000000 -31377.85317015 -28156.13970334 -9.32605530 2.054021717 -2.288554158 0.000704959 2004 2 8 12:20:01.494268
+-120.00000000 -13031.41552688 -40092.33381029 -3.27636660 2.924657466 -0.950541167 0.000949381 2004 2 8 14:20:01.494241
+0.00000000 8827.15660472 -41223.00971237 3.63482963 3.007087319 0.643701323 0.000941663 2004 2 8 16:20:01.494254
+120.00000000 28306.85426674 -31243.80147394 9.57216891 2.279137743 2.064316875 0.000684127 2004 2 8 18:20:01.494268
+240.00000000 40159.05128805 -12845.39151157 12.96086316 0.937265422 2.928448287 0.000245505 2004 2 8 20:20:01.494241
+360.00000000 41192.55903455 9013.79606759 12.90495666 -0.656727442 3.003543458 -0.000257479 2004 2 8 22:20:01.494254
+480.00000000 31131.69755798 28445.55681731 9.42419238 -2.073484842 2.269770851 -0.000691233 2004 2 9 0:20:01.494268
+600.00000000 12687.81846530 40217.83324639 3.44726249 -2.931721827 0.924962230 -0.000940766 2004 2 9 2:20:01.494241
+720.00000000 -9172.23500245 41161.63475527 -3.43575757 -3.000571486 -0.668847508 -0.000940101 2004 2 9 4:20:01.494254
+840.00000000 -28562.51093192 31022.45987587 -9.39562161 -2.261449202 -2.082713897 -0.000689669 2004 2 9 6:20:01.494268
+960.00000000 -40260.77504549 12529.11484344 -12.84915105 -0.913097031 -2.935933528 -0.000256181 2004 2 9 8:20:01.494241
+1080.00000000 -41114.14376538 -9338.87194483 -12.87952404 0.681588815 -2.998432565 0.000245006 2004 2 9 10:20:01.494254
+1200.00000000 -30890.01512240 -28690.40750792 -9.48037212 2.092989805 -2.252978152 0.000680459 2004 2 9 12:20:01.494268
+1320.00000000 -12341.46194020 -40310.06316386 -3.55833201 2.940537098 -0.900219523 0.000934170 2004 2 9 14:20:01.494241
+1440.00000000 9533.27750818 -41065.52390214 3.30756482 2.995596171 0.695200236 0.000938525 2004 2 9 16:20:01.494254
+26900 xx
+0.00000000 -42014.83795787 3702.34357772 -26.67500257 -0.269775247 -3.061854393 0.000336726
+9300.00000000 40968.68133298 -9905.99156086 11.84946837 0.722756848 2.989645389 -0.000161261 2006 4 23 4:52:50.805439
+9360.00000000 42135.66858481 1072.99195618 10.83481752 -0.078150602 3.074772455 -0.000380063 2006 4 23 5:52:50.805426
+9400.00000000 41304.75156132 8398.27742944 9.74006214 -0.612515135 3.014117469 -0.000511575 2006 4 23 6:32:50.805444
+26975 xx
+0.00000000 -14506.92313768 -21613.56043281 10.05018894 2.212943308 1.159970892 3.020600202
+120.00000000 7309.62197950 6076.00713664 6800.08705263 1.300543383 5.322579615 -4.788746312 2006 6 23 22:35:47.504573
+240.00000000 -3882.62933791 11960.00543452 -25088.14383845 -2.146773699 -1.372461491 -2.579382089 2006 6 24 0:35:47.504546
+360.00000000 -16785.45507465 -734.79159704 -34300.57085853 -1.386528125 -1.907762641 -0.220949641 2006 6 24 2:35:47.504559
+480.00000000 -23524.16689356 -13629.45124622 -30246.27899200 -0.462846784 -1.586139830 1.269293624 2006 6 24 4:35:47.504573
+600.00000000 -22890.23597092 -22209.35900155 -16769.91946116 0.704351342 -0.671112594 2.432433851 2006 6 24 6:35:47.504546
+720.00000000 -11646.39698980 -19855.44222106 3574.00109607 2.626712727 1.815887329 2.960883901 2006 6 24 8:35:47.504559
+840.00000000 7665.76124241 11159.78946577 345.93813117 -0.584818007 3.193514161 -5.750338922 2006 6 24 10:35:47.504573
+960.00000000 -6369.35388112 10204.80073022 -27844.52150384 -2.050573276 -1.582940542 -2.076075232 2006 6 24 12:35:47.504546
+1080.00000000 -18345.64763145 -2977.76684430 -34394.90760612 -1.243589864 -1.892050757 0.060372061 2006 6 24 14:35:47.504559
+1200.00000000 -23979.74839255 -15436.44139571 -28616.50540218 -0.294973425 -1.482987916 1.478255628 2006 6 24 16:35:47.504573
+1320.00000000 -21921.97167880 -22852.45147658 -13784.85308485 0.945455629 -0.428940995 2.596964378 2006 6 24 18:35:47.504546
+1440.00000000 -8266.43821031 -17210.74590112 6967.95546070 3.082244069 2.665881872 2.712555075 2006 6 24 20:35:47.504559
+1560.00000000 6286.85464535 13809.56328971 -6321.60663781 -1.615964016 1.383135377 -5.358719132 2006 6 24 22:35:47.504573
+1680.00000000 -8730.87526788 8244.63344365 -30039.92372791 -1.935622871 -1.724162072 -1.631224738 2006 6 25 0:35:47.504546
+1800.00000000 -19735.81883249 -5191.76593007 -34166.14974143 -1.097835530 -1.860148418 0.324401050 2006 6 25 2:35:47.504559
+1920.00000000 -24232.73847703 -17112.08243255 -26742.88893252 -0.119786184 -1.364365317 1.680220468 2006 6 25 4:35:47.504573
+2040.00000000 -20654.45640708 -23184.54386047 -10611.55144716 1.209238113 -0.144169639 2.748054938 2006 6 25 6:35:47.504546
+2160.00000000 -4337.15988957 -13410.46817244 9870.45949215 3.532753095 3.772236461 2.088424247 2006 6 25 8:35:47.504559
+2280.00000000 4074.62263523 14698.07548285 -12248.65327973 -2.053824693 0.203325817 -4.607867718 2006 6 25 10:35:47.504573
+2400.00000000 -10950.23438984 6148.66879447 -31736.65532865 -1.809875605 -1.816179062 -1.233364913 2006 6 25 12:35:47.504546
+2520.00000000 -20952.40702045 -7358.71507895 -33633.06643074 -0.948973031 -1.813594137 0.573893078 2006 6 25 14:35:47.504559
+2640.00000000 -24273.48944134 -18637.15546906 -24633.27702390 0.064161440 -1.228537560 1.875728935 2006 6 25 16:35:47.504573
+2760.00000000 -19057.55468077 -23148.29322082 -7269.38614178 1.500802809 0.195383037 2.879031237 2006 6 25 18:35:47.504546
+2880.00000000 43.69305308 -8145.90299207 11634.57079913 3.780661682 5.105315423 0.714401345 2006 6 25 20:35:47.504559
+28057 xx
+0.00000000 -2715.28237486 -6619.26436889 -0.01341443 -1.008587273 0.422782003 7.385272942
+120.00000000 -1816.87920942 -1835.78762132 6661.07926465 2.325140071 6.655669329 2.463394512 2006 6 26 20:52:04.079709
+240.00000000 1483.17364291 5395.21248786 4448.65907172 2.560540387 4.039025766 -5.736648561 2006 6 26 22:52:04.079682
+360.00000000 2801.25607157 5455.03931333 -3692.12865695 -0.595095864 -3.951923117 -6.298799125 2006 6 27 0:52:04.079695
+480.00000000 411.09332812 -1728.99769152 -6935.45548810 -2.935970964 -6.684085058 1.492800886 2006 6 27 2:52:04.079709
+600.00000000 -2506.52558454 -6628.98655094 -988.07784497 -1.390577189 -0.556164143 7.312736468 2006 6 27 4:52:04.079682
+720.00000000 -2090.79884266 -2723.22832193 6266.13356576 1.992640665 6.337529519 3.411803080 2006 6 27 6:52:04.079695
+840.00000000 1091.80560222 4809.88229503 5172.42897894 2.717483546 4.805518977 -5.030019896 2006 6 27 8:52:04.079709
+960.00000000 2811.14062300 5950.65707171 -2813.23705389 -0.159662742 -3.121215491 -6.775341949 2006 6 27 10:52:04.079682
+1080.00000000 805.72698304 -812.16627907 -7067.58483968 -2.798936020 -6.889265977 0.472770873 2006 6 27 12:52:04.079695
+1200.00000000 -2249.59837532 -6505.84890714 -1956.72365062 -1.731234729 -1.528750230 7.096660885 2006 6 27 14:52:04.079709
+1320.00000000 -2311.57375797 -3560.99112891 5748.16749600 1.626569751 5.890482233 4.293545048 2006 6 27 16:52:04.079682
+1440.00000000 688.16056594 4124.87618964 5794.55994449 2.810973665 5.479585563 -4.224866316 2006 6 27 18:52:04.079695
+1560.00000000 2759.94088230 6329.87271798 -1879.19518331 0.266930672 -2.222670878 -7.119390567 2006 6 27 20:52:04.079709
+1680.00000000 1171.50677137 125.82053748 -7061.96626202 -2.605687852 -6.958489749 -0.556333225 2006 6 27 22:52:04.079682
+1800.00000000 -1951.43708472 -6251.71945820 -2886.95472355 -2.024131483 -2.475214272 6.741537478 2006 6 28 0:52:04.079695
+1920.00000000 -2475.70722288 -4331.90569958 5117.31234924 1.235823539 5.322743371 5.091281211 2006 6 28 2:52:04.079709
+2040.00000000 281.46097847 3353.51057102 6302.87900650 2.840647273 6.047222485 -3.337085992 2006 6 28 4:52:04.079682
+2160.00000000 2650.33118860 6584.33434851 -908.29027134 0.675457235 -1.274044972 -7.323921567 2006 6 28 6:52:04.079695
+2280.00000000 1501.17226597 1066.31132756 -6918.71472952 -2.361891904 -6.889669974 -1.574718619 2006 6 28 8:52:04.079709
+2400.00000000 -1619.73468334 -5871.14051991 -3760.56587071 -2.264093975 -3.376316601 6.254622256 2006 6 28 10:52:04.079682
+2520.00000000 -2581.04202505 -5020.05572531 4385.92329047 0.829668458 4.645048038 5.789262667 2006 6 28 12:52:04.079695
+2640.00000000 -119.22080628 2510.90620488 6687.45615459 2.807575712 6.496549689 -2.384136661 2006 6 28 14:52:04.079709
+2760.00000000 2486.23806726 6708.18210028 80.43349581 1.057274905 -0.294294027 -7.384689123 2006 6 28 16:52:04.079682
+2880.00000000 1788.42334580 1990.50530957 -6640.59337725 -2.074169091 -6.683381288 -2.562777776 2006 6 28 18:52:04.079695
+28129 xx
+0.00000000 21707.46412351 -15318.61752390 0.13551152 1.304029214 1.816904974 3.161919976
+120.00000000 18616.75971861 3166.15177043 18833.41523210 -2.076122016 2.838457575 1.586210535 2006 6 24 15:41:49.461504
+240.00000000 -3006.50596328 18522.20742011 18941.84078154 -3.375452789 1.032680773 -1.559324534 2006 6 24 17:41:49.461477
+360.00000000 -21607.02086957 15432.59962630 206.62470309 -1.306049851 -1.817011568 -3.163725018 2006 6 24 19:41:49.461491
+480.00000000 -18453.06134549 -3150.83256134 -18685.83030936 2.106017925 -2.860236337 -1.586151870 2006 6 24 21:41:49.461504
+600.00000000 3425.11742384 -18514.73232706 -18588.67200557 3.394666340 -1.003072030 1.610061295 2006 6 24 23:41:49.461477
+720.00000000 21858.23838148 -15101.51661554 387.34517048 1.247973967 1.856017403 3.161439948 2006 6 25 1:41:49.461491
+840.00000000 18360.69935796 3506.55256762 19024.81678979 -2.122684184 2.830618605 1.537510677 2006 6 25 3:41:49.461504
+960.00000000 -3412.84765409 18646.85269710 18748.00359987 -3.366815728 0.986039922 -1.607874972 2006 6 25 5:41:49.461477
+1080.00000000 -21758.08331586 15215.44829478 -180.82181406 -1.250144680 -1.856490448 -3.163774870 2006 6 25 7:41:49.461491
+1200.00000000 -18193.41290284 -3493.85876912 -18877.14757717 2.153326942 -2.852221264 -1.536617760 2006 6 25 9:41:49.461504
+1320.00000000 3833.57386848 -18635.77026711 -18388.68722885 3.384748179 -0.955363841 1.658785020 2006 6 25 11:41:49.461477
+1440.00000000 22002.20074562 -14879.72595593 774.32827099 1.191573619 1.894561165 3.159953047 2006 6 25 13:41:49.461491
+28350 xx
+0.00000000 6333.08123128 -1580.82852326 90.69355720 0.714634423 3.224246550 7.083128132
+120.00000000 -3990.93845855 3052.98341907 4155.32700629 -5.909006188 -0.876307966 -5.039131404 2006 6 16 7:13:45.407419
+240.00000000 -603.55232010 -2685.13474569 -5891.70274282 7.572519907 -1.975656726 0.121722605 2006 6 16 9:13:45.407392
+360.00000000 4788.22345627 782.56169214 4335.14284621 -4.954509026 3.683346464 4.804645839 2006 6 16 11:13:45.407405
+480.00000000 -6291.84601644 1547.82790772 -453.67116498 -0.308625588 -3.341538574 -7.082659115 2006 6 16 13:13:45.407419
+600.00000000 4480.74573428 -3028.55200374 -3586.94343641 5.320920857 1.199736275 5.626350481 2006 6 16 15:13:45.407392
+720.00000000 -446.42460916 2932.28872588 5759.19389757 -7.561000245 1.550975493 -1.374970885 2006 6 16 17:13:45.407405
+840.00000000 -3713.79581831 -1382.66125130 -5122.45131136 6.090931626 -3.512629733 -3.467571746 2006 6 16 19:13:45.407419
+960.00000000 6058.32017522 -827.47406722 2104.04678651 -1.798403024 3.787067272 6.641439744 2006 6 16 21:13:45.407392
+1080.00000000 -5631.73659006 2623.70953644 1766.49125084 -3.216401578 -2.309140959 -6.788609120 2006 6 16 23:13:45.407405
+1200.00000000 2776.84991560 -3255.36941953 -4837.19667790 6.748135564 -0.193044825 4.005718698 2006 6 17 1:13:45.407419
+1320.00000000 1148.04430837 2486.07343386 5826.34075913 -7.420162295 2.589456382 0.356350006 2006 6 17 3:13:45.407392
+1440.00000000 -4527.90871828 -723.29199041 -4527.44608319 5.121674217 -3.909895427 -4.500218556 2006 6 17 5:13:45.407405
+28623 xx
+0.00000000 -11665.70902324 24943.61433357 25.80543633 -1.596228621 -1.476127961 1.126059754
+120.00000000 -11645.35454950 979.37668356 5517.89500058 3.407743502 -5.183094988 -0.492983277 2006 6 26 21:27:32.414976
+240.00000000 5619.19252274 19651.44862280 -7261.38496765 -2.013634213 3.106842861 0.284235517 2006 6 26 23:27:32.414949
+360.00000000 -9708.68629714 26306.14553149 -1204.29478856 -1.824164290 -0.931909596 1.113419052 2006 6 27 1:27:32.414963
+480.00000000 -14394.03162892 6659.30765074 5593.38345858 1.556522911 -4.681657614 0.296912248 2006 6 27 3:27:32.414976
+600.00000000 7712.09476270 15565.72627434 -7342.40465571 -1.646800364 4.070313571 -0.109483081 2006 6 27 5:27:32.414949
+720.00000000 -7558.36739603 27035.11367962 -2385.12054184 -1.999583791 -0.393409283 1.078093515 2006 6 27 7:27:32.414963
+840.00000000 -15495.61862220 11550.15897828 5053.83178121 0.469277336 -4.029761073 0.679054742 2006 6 27 9:27:32.414976
+960.00000000 9167.02568222 10363.65204210 -6871.52576042 -0.881621027 5.223361510 -0.740696297 2006 6 27 11:27:32.414949
+1080.00000000 -5275.80272094 27151.78486008 -3494.50687216 -2.129609388 0.150196480 1.021038089 2006 6 27 13:27:32.414963
+1200.00000000 -15601.37656145 15641.29379850 4217.03266850 -0.249183123 -3.405238557 0.888214503 2006 6 27 15:27:32.414976
+1320.00000000 9301.05872300 3883.15265574 -5477.86477017 0.871447821 6.493677331 -1.885545282 2006 6 27 17:27:32.414949
+1440.00000000 -2914.31065828 26665.20392758 -4511.09814335 -2.216261909 0.710067769 0.940691824 2006 6 27 19:27:32.414963
+28626 xx
+0.00000000 42080.71852213 -2646.86387436 0.81851294 0.193105177 3.068688251 0.000438449
+120.00000000 37740.00085593 18802.76872802 3.45512584 -1.371035206 2.752105932 0.000336883 2006 6 25 13:12:14.455025
+240.00000000 23232.82515008 35187.33981802 4.98927428 -2.565776620 1.694193132 0.000163365 2006 6 25 15:12:14.454998
+360.00000000 2467.44290178 42093.60909959 5.15062987 -3.069341800 0.179976276 -0.000031739 2006 6 25 17:12:14.455012
+480.00000000 -18962.59052991 37661.66243819 4.04433258 -2.746151982 -1.382675777 -0.000197633 2006 6 25 19:12:14.455025
+600.00000000 -35285.00095313 23085.44402778 2.08711880 -1.683277908 -2.572893625 -0.000296282 2006 6 25 21:12:14.454998
+720.00000000 -42103.20138132 2291.06228893 -0.13274964 -0.166974816 -3.070104560 -0.000311007 2006 6 25 23:12:14.455012
+840.00000000 -37580.31858370 -19120.40485693 -2.02755702 1.394367848 -2.740341612 -0.000248591 2006 6 26 1:12:14.455025
+960.00000000 -22934.20761876 -35381.23870806 -3.16495932 2.580167539 -1.672360951 -0.000134907 2006 6 26 3:12:14.454998
+1080.00000000 -2109.90332389 -42110.71508198 -3.36507889 3.070935369 -0.153808390 -0.000005855 2006 6 26 5:12:14.455012
+1200.00000000 19282.77774728 -37495.59250598 -2.71861462 2.734400524 1.406220933 0.000103486 2006 6 26 7:12:14.455025
+1320.00000000 35480.60990600 -22779.03375285 -1.52841859 1.661210676 2.587414593 0.000168300 2006 6 26 9:12:14.454998
+1440.00000000 42119.96263499 -1925.77567263 -0.19827433 0.140521206 3.071541613 0.000179561 2006 6 26 11:12:14.455012
+28872 xx
+0.00000000 -6131.82730456 2446.52815528 -253.64211033 -0.144920228 0.995100963 7.658645067
+5.00000000 -5799.24256134 2589.14811119 2011.54515100 2.325207364 -0.047125672 7.296234071 2005 11 29 0:33:58.939092
+10.00000000 -4769.05061967 2420.46580562 4035.30855837 4.464585796 -1.060923209 6.070907874 2005 11 29 0:38:58.939114
+15.00000000 -3175.45157340 1965.98738086 5582.12569607 6.049639376 -1.935777558 4.148607019 2005 11 29 0:43:58.939096
+20.00000000 -1210.19024802 1281.54541294 6474.68172772 6.920746273 -2.580517337 1.748783868 2005 11 29 0:48:58.939118
+25.00000000 896.73799533 447.12357305 6607.22400507 6.983396282 -2.925846168 -0.872655207 2005 11 29 0:53:58.939101
+30.00000000 2896.99663534 -440.04738594 5954.92675486 6.211488246 -2.926949815 -3.433959806 2005 11 29 0:58:58.939123
+35.00000000 4545.78970167 -1273.55952872 4580.16512984 4.656984233 -2.568711513 -5.638510954 2005 11 29 1:03:58.939105
+40.00000000 5627.43299371 -1947.94282469 2634.16714930 2.464141047 -1.873985161 -7.195743032 2005 11 29 1:08:58.939127
+45.00000000 5984.72318534 -2371.37691609 349.87996209 -0.121276950 -0.911981546 -7.859613894 2005 11 29 1:13:58.939109
+50.00000000 5548.43325922 -2480.16469245 -1979.24314527 -2.763269534 0.199691915 -7.482796996 2005 11 29 1:18:58.939092
+29141 xx
+0.00000000 423.99295524 -6658.12256149 136.13040356 1.006373613 0.217309983 7.662587892
+20.00000000 931.80883587 -1017.17852239 6529.19244527 -0.298847918 7.613891977 1.226399480 2006 6 19 6:45:41.242102
+40.00000000 -83.44906141 6286.20208453 2223.49837161 -1.113515974 2.530970283 -7.219445568 2006 6 19 7:05:41.242111
+60.00000000 -958.57681221 3259.26005348 -5722.63732467 -0.101225813 -6.735338321 -3.804851872 2006 6 19 7:25:41.242079
+80.00000000 -255.25619985 -5132.59762974 -4221.27233118 1.077709303 -4.905938824 5.892521264 2006 6 19 7:45:41.242088
+100.00000000 867.44295097 -5038.40402933 4256.73810533 0.479447535 5.032326446 5.857126248 2006 6 19 8:05:41.242097
+120.00000000 559.16882013 3376.30587937 5699.22017391 -0.906749328 6.646149867 -3.852331832 2006 6 19 8:25:41.242106
+140.00000000 -669.85184205 6196.00229484 -2281.95741770 -0.795804092 -2.752114827 -7.202478520 2006 6 19 8:45:41.242075
+160.00000000 -784.20708019 -1278.53125553 -6449.19892596 0.636702380 -7.595425203 1.431090802 2006 6 19 9:05:41.242084
+180.00000000 406.15811659 -6607.03115799 148.33021477 1.009818575 0.231843765 7.692047844 2006 6 19 9:25:41.242093
+200.00000000 916.34911813 -884.08649248 6491.09810362 -0.302163049 7.669887109 1.084336909 2006 6 19 9:45:41.242102
+220.00000000 -104.02490970 6304.31821405 1960.08739882 -1.108873823 2.259522809 -7.351147710 2006 6 19 10:05:41.242111
+240.00000000 -944.61642849 2872.17248379 -5846.94103362 -0.051117686 -6.989747076 -3.413102600 2006 6 19 10:25:41.242079
+260.00000000 -187.16569888 -5404.86163467 -3731.97057618 1.094696706 -4.412110995 6.326060952 2006 6 19 10:45:41.242088
+280.00000000 884.59720467 -4465.74516163 4725.83632696 0.380656028 5.691554046 5.303910983 2006 6 19 11:05:41.242097
+300.00000000 446.40767236 4086.66839620 5093.05596650 -0.982424447 6.072965199 -4.791630682 2006 6 19 11:25:41.242106
+320.00000000 -752.24467495 5588.35473301 -3275.04092573 -0.661161370 -4.016290740 -6.676898026 2006 6 19 11:45:41.242075
+340.00000000 -643.72872525 -2585.02528560 -5923.01306608 0.807922142 -7.171597814 3.041115058 2006 6 19 12:05:41.242084
+360.00000000 584.40295819 -6202.35605817 1781.00536019 0.869250450 2.226927514 7.471676765 2006 6 19 12:25:41.242093
+380.00000000 779.59211765 1100.73728301 6311.59529480 -0.599552305 7.721032522 -1.275153027 2006 6 19 12:45:41.242102
+400.00000000 -403.03155588 6399.18000837 -364.12735875 -1.008861924 -0.516636615 -7.799812287 2006 6 19 13:05:41.242111
+420.00000000 -852.93910071 192.65232023 -6322.47054784 0.396006194 -7.882964919 -0.289331517 2006 6 19 13:25:41.242079
+29238 xx
+0.00000000 -5566.59512819 -3789.75991159 67.60382245 2.873759367 -3.825340523 6.023253926
+120.00000000 4474.27915495 -1447.72286142 4619.83927235 4.712595822 5.668306153 -2.701606741 2006 6 26 8:53:44.456634
+240.00000000 1922.17712474 5113.01138342 -4087.08470203 -6.490769651 -0.522350158 -3.896001154 2006 6 26 10:53:44.456607
+360.00000000 -6157.93546882 -2094.70798790 -1941.63730960 0.149900661 -5.175192523 5.604262034 2006 6 26 12:53:44.456620
+480.00000000 2482.64052411 -3268.45944555 5146.38006190 6.501814698 4.402848754 -0.350943511 2006 6 26 14:53:44.456634
+600.00000000 4036.26455287 4827.43347201 -2507.99063955 -5.184409515 1.772280695 -5.331390168 2006 6 26 16:53:44.456607
+720.00000000 -5776.81371622 -118.64155319 -3641.22052418 -2.539917207 -5.622701582 4.403125405 2006 6 26 18:53:44.456620
+840.00000000 67.98699487 -4456.49213473 4863.71794283 7.183809420 2.418917791 2.015642495 2006 6 26 20:53:44.456634
+960.00000000 5520.62207038 3782.38203554 -596.73193161 -3.027966069 3.754152525 -6.013506363 2006 6 26 22:53:44.456607
+1080.00000000 -4528.05104455 1808.46273329 -4816.99727762 -4.808419763 -5.185789345 2.642104494 2006 6 27 0:53:44.456620
+1200.00000000 -2356.61468078 -4852.51202272 3856.53816184 6.688446735 0.118520958 4.021854210 2006 6 27 2:53:44.456634
+1320.00000000 6149.65800134 2173.59423261 1369.29488732 -0.345832777 5.109857861 -5.842951828 2006 6 27 4:53:44.456607
+1440.00000000 -2629.55011449 3400.98040158 -5344.38217129 -6.368548448 -3.998963509 0.577253064 2006 6 27 6:53:44.456620
+88888 xx
+0.00000000 2328.96975262 -5995.22051338 1719.97297192 2.912073281 -0.983417956 -7.090816210
+120.00000000 1020.69234558 2286.56260634 -6191.55565927 -3.746543902 6.467532721 1.827985678 1980 10 2 1:41:24.113771
+240.00000000 -3226.54349155 3503.70977525 4532.80979343 1.000992116 -5.788042888 5.162585826 1980 10 2 3:41:24.113744
+360.00000000 2456.10706533 -6071.93855503 1222.89768554 2.679390040 -0.448290811 -7.228792155 1980 10 2 5:41:24.113757
+480.00000000 787.16457349 2719.91800946 -6043.86662024 -3.759883839 6.277439314 2.397897864 1980 10 2 7:41:24.113771
+600.00000000 -3110.97648029 3121.73026235 4878.15217035 1.244916056 -6.124880425 4.700576353 1980 10 2 9:41:24.113744
+720.00000000 2567.56229695 -6112.50383922 713.96374435 2.440245751 0.098109002 -7.319959258 1980 10 2 11:41:24.113757
+840.00000000 556.05661780 3144.52288201 -5855.34636178 -3.754660143 6.044752775 2.957941672 1980 10 2 13:41:24.113771
+960.00000000 -2982.47940539 2712.61663711 5192.32330472 1.475566773 -6.427737014 4.202420227 1980 10 2 15:41:24.113744
+1080.00000000 2663.08964352 -6115.48290885 196.40072866 2.196121564 0.652415093 -7.362824152 1980 10 2 17:41:24.113757
+1200.00000000 328.54999674 3557.09490552 -5626.21427211 -3.731193288 5.769341172 3.504058731 1980 10 2 19:41:24.113771
+1320.00000000 -2842.06876757 2278.42343492 5472.33437150 1.691852635 -6.693216335 3.671022712 1980 10 2 21:41:24.113744
+1440.00000000 2742.55398832 -6079.67009123 -326.39012649 1.948497651 1.211072678 -7.356193131 1980 10 2 23:41:24.113757
diff --git a/pyorbital/tests/test_aiaa.py b/pyorbital/tests/test_aiaa.py
new file mode 100644
index 0000000..40f47c2
--- /dev/null
+++ b/pyorbital/tests/test_aiaa.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011, 2014 SMHI
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Test cases from the AIAA article.
+"""
+
+# TODO: right formal unit tests.
+from __future__ import with_statement
+
+import os
+
+from pyorbital.orbital import Orbital, OrbitElements, _SGDP4
+from pyorbital.tlefile import ChecksumError
+from pyorbital import tlefile, astronomy
+import numpy as np
+from datetime import timedelta, datetime
+import unittest
+
+class LineOrbital(Orbital):
+ """Read TLE lines instead of file.
+ """
+ def __init__(self, satellite, line1, line2):
+ satellite = satellite.upper()
+ self.satellite_name = satellite
+ self.tle = tlefile.read(satellite, line1=line1, line2=line2)
+ self.orbit_elements = OrbitElements(self.tle)
+ self._sgdp4 = _SGDP4(self.orbit_elements)
+
+
+def get_results(satnumber, delay):
+ """Get expected results from result file.
+ """
+ path = os.path.dirname(os.path.abspath(__file__))
+ with open(os.path.join(path, "aiaa_results")) as f_2:
+ line = f_2.readline()
+ while(line):
+ if line.endswith(" xx\n") and int(line[:-3]) == satnumber:
+ line = f_2.readline()
+ while(not line.startswith("%.8f"%delay)):
+ line = f_2.readline()
+ sline = line.split()
+ if delay == 0:
+ utc_time = None
+ else:
+ utc_time = datetime.strptime(sline[-1], "%H:%M:%S.%f")
+ utc_time = utc_time.replace(year=int(sline[-4]),
+ month=int(sline[-3]),
+ day=int(sline[-2]))
+ return (float(sline[1]),
+ float(sline[2]),
+ float(sline[3]),
+ float(sline[4]),
+ float(sline[5]),
+ float(sline[6]),
+ utc_time)
+ line = f_2.readline()
+
+class AIAAIntegrationTest(unittest.TestCase):
+ """Test against the AIAA test cases.
+ """
+
+ def test_aiaa(self):
+ """Do the tests against AIAA test cases.
+ """
+ path = os.path.dirname(os.path.abspath(__file__))
+ with open(os.path.join(path, "SGP4-VER.TLE")) as f__:
+ test_line = f__.readline()
+ while(test_line):
+ if test_line.startswith("#"):
+ test_name = test_line
+ if test_line.startswith("1 "):
+ line1 = test_line
+ if test_line.startswith("2 "):
+ line2 = test_line[:69]
+ times = str.split(test_line[69:])
+ times = np.arange(float(times[0]),
+ float(times[1]) + 1,
+ float(times[2]))
+ if test_name.startswith("# SL-14 DEB"):
+ # FIXME: we have to handle decaying satellites!
+ test_line = f__.readline()
+ continue
+
+ try:
+ o = LineOrbital("unknown", line1, line2)
+ except NotImplementedError, e:
+ test_line = f__.readline()
+ continue
+ except ChecksumError, e:
+ self.assertTrue(test_line.split()[1] in ["33333", "33334", "33335"])
+ for delay in times:
+ try:
+ test_time = timedelta(minutes=delay) + o.tle.epoch
+ pos, vel = o.get_position(test_time, False)
+ res = get_results(int(o.tle.satnumber), float(delay))
+ except NotImplementedError:
+ # Skipping deep-space
+ break
+ # except ValueError, e:
+ # from warnings import warn
+ # warn(test_name + ' ' + str(e))
+ # break
+
+ delta_pos = 5e-6 # km = 5 mm
+ delta_vel = 5e-9 # km/s = 5 um/s
+ delta_time = 1e-3 # 1 milisecond
+ self.assertTrue(abs(res[0] - pos[0]) < delta_pos)
+ self.assertTrue(abs(res[1] - pos[1]) < delta_pos)
+ self.assertTrue(abs(res[2] - pos[2]) < delta_pos)
+ self.assertTrue(abs(res[3] - vel[0]) < delta_vel)
+ self.assertTrue(abs(res[4] - vel[1]) < delta_vel)
+ self.assertTrue(abs(res[5] - vel[2]) < delta_vel)
+ if res[6] is not None:
+ dt = astronomy._days(res[6] - test_time) * 24 * 60
+ self.assertTrue(abs(dt) < delta_time)
+
+ test_line = f__.readline()
+
+
+def suite():
+ """The suite for test_aiaa
+ """
+ loader = unittest.TestLoader()
+ mysuite = unittest.TestSuite()
+ mysuite.addTest(loader.loadTestsFromTestCase(AIAAIntegrationTest))
+
+ return mysuite
+
diff --git a/pyorbital/tests/test_astronomy.py b/pyorbital/tests/test_astronomy.py
new file mode 100644
index 0000000..ae39d1c
--- /dev/null
+++ b/pyorbital/tests/test_astronomy.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013, 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+import unittest
+
+from datetime import datetime
+import pyorbital.astronomy as astr
+
+
+
+class TestAstronomy(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def test_jdays(self):
+ """Test julian day functions.
+ """
+
+ t = datetime(2000, 1, 1, 12, 0)
+ self.assertEqual(astr.jdays(t), 2451545.0)
+ self.assertEqual(astr.jdays2000(t), 0)
+ t = datetime(2009, 10, 8, 14, 30)
+ self.assertEqual(astr.jdays(t), 2455113.1041666665)
+ self.assertEqual(astr.jdays2000(t), 3568.1041666666665)
+
+ def test_sunangles(self):
+ """Test the sun-angle calculations:
+ """
+ lat, lon = 58.6167, 16.1833 # Norrkoping
+ time_slot = datetime(2011, 9, 23, 12, 0)
+
+ sun_theta = astr.sun_zenith_angle(time_slot, lon, lat)
+ self.assertEqual(sun_theta, 60.371433482557833)
+ sun_theta = astr.sun_zenith_angle(time_slot, 0., 0.)
+ self.assertEqual(sun_theta, 1.8751916863323426)
+
+def suite():
+ """The suite for test_astronomy
+ """
+ loader = unittest.TestLoader()
+ mysuite = unittest.TestSuite()
+ mysuite.addTest(loader.loadTestsFromTestCase(TestAstronomy))
+
+ return mysuite
+
diff --git a/pyorbital/tests/test_geoloc.py b/pyorbital/tests/test_geoloc.py
new file mode 100644
index 0000000..a2a69cc
--- /dev/null
+++ b/pyorbital/tests/test_geoloc.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Test the geoloc module.
+"""
+
+import unittest
+from pyorbital.geoloc_instrument_definitions import avhrr
+from pyorbital.geoloc import (ScanGeometry, qrotate,
+ subpoint, geodetic_lat)
+import numpy as np
+from datetime import datetime, timedelta
+
+class TestQuaternion(unittest.TestCase):
+ """Test the quaternion rotation.
+ """
+
+ def test_qrotate(self):
+ """Test quaternion rotation
+ """
+ vector = np.array([[1, 0, 0]]).T
+ axis = np.array([[0, 1, 0]]).T
+ angle = np.deg2rad(90)
+ self.assertTrue(np.allclose(qrotate(vector, axis, angle),
+ np.array([[0, 0, 1]]).T))
+
+ axis = np.array([0, 1, 0])
+ self.assertTrue(np.allclose(qrotate(vector, axis, angle),
+ np.array([[0, 0, 1]]).T))
+
+ vector = np.array([[1, 0, 0],
+ [0, 0, 1]]).T
+ axis = np.array([0, 1, 0])
+ angle = np.deg2rad(90)
+ self.assertTrue(np.allclose(qrotate(vector, axis, angle),
+ np.array([[0, 0, 1],
+ [-1, 0, 0]]).T))
+
+ axis = np.array([[0, 1, 0]]).T
+ self.assertTrue(np.allclose(qrotate(vector, axis, angle),
+ np.array([[0, 0, 1],
+ [-1, 0, 0]]).T))
+
+
+class TestGeoloc(unittest.TestCase):
+ """Test for the core computing part.
+ """
+
+ def test_scan_geometry(self):
+ """Test the ScanGeometry object.
+ """
+ instrument = ScanGeometry(np.deg2rad(np.array([[10, 0],
+ [0, 0],
+ [-10, 0]])),
+ np.array([-0.1, 0, 0.1]))
+ self.assertTrue(np.allclose(np.rad2deg(instrument.fovs[:, 0]),
+ np.array([10, 0, -10])))
+
+ # Test vectors
+
+ pos = np.array([[0, 0, 7000]]).T
+ vel = np.array([[1, 0, 0]]).T
+ vec = instrument.vectors(pos, vel)
+ self.assertTrue(np.allclose(np.array([[0, 0, -1]]),
+ vec[:, 1]))
+
+ # minus sin because we use trigonometrical direction of angles
+
+ self.assertTrue(np.allclose(np.array([[0,
+ -np.sin(np.deg2rad(10)),
+ -np.cos(np.deg2rad(10))]]),
+ vec[:, 0]))
+ self.assertTrue(np.allclose(np.array([[0,
+ -np.sin(np.deg2rad(-10)),
+ -np.cos(np.deg2rad(-10))]]),
+ vec[:, 2]))
+
+ # Test times
+
+ start_of_scan = datetime(2014, 1, 8, 11, 30)
+ times = instrument.times(start_of_scan)
+ self.assertEquals(times[1], start_of_scan)
+ self.assertEquals(times[0], start_of_scan - timedelta(seconds=0.1))
+ self.assertEquals(times[2], start_of_scan + timedelta(seconds=0.1))
+
+ def test_geodetic_lat(self):
+ """Test the determination of the geodetic latitude.
+ """
+
+ a = 6378.137 # km
+ b = 6356.75231414 # km, GRS80
+
+ point = np.array([7000, 0, 7000])
+ self.assertEqual(geodetic_lat(point), 0.78755832699854733)
+ points = np.array([[7000, 0, 7000],
+ [7000, 0, 7000]]).T
+ self.assertTrue(np.allclose(geodetic_lat(points),
+ np.array([0.78755832699854733,
+ 0.78755832699854733])))
+
+
+ def test_subpoint(self):
+ """Test nadir determination.
+ """
+ a = 6378.137 # km
+ b = 6356.75231414 # km, GRS80
+ point = np.array([0, 0, 7000])
+ nadir = subpoint(point, a, b)
+ self.assertTrue(np.allclose(nadir, np.array([[0, 0, b]]).T))
+
+ point = np.array([7000, 0, 7000])
+ nadir = subpoint(point, a, b)
+ self.assertTrue(np.allclose(nadir,
+ np.array([[4507.85431429,
+ 0,
+ 4497.06396339]]).T))
+ points = np.array([[7000, 0, 7000],
+ [7000, 0, 7000]]).T
+ nadir = subpoint(points, a, b)
+ self.assertTrue(np.allclose(nadir,
+ np.array([[4507.85431429,
+ 0,
+ 4497.06396339]]).T))
+
+
+
+
+class TestGeolocDefs(unittest.TestCase):
+ """Test the instrument definitions.
+ """
+ def test_avhrr(self):
+ """Test the definition of the avhrr instrument
+ """
+ avh = avhrr(1, np.array([0, 1023.5 ,2047]))
+ self.assertTrue(np.allclose(np.rad2deg(avh.fovs[:, 0]),
+ np.array([55.37, 0, -55.37])))
+
+ avh = avhrr(1, np.array([0, 1023.5 ,2047]), 10)
+ self.assertTrue(np.allclose(np.rad2deg(avh.fovs[:, 0]),
+ np.array([10, 0, -10])))
+
+def suite():
+ """The suite for test_geoloc
+ """
+ loader = unittest.TestLoader()
+ mysuite = unittest.TestSuite()
+ mysuite.addTest(loader.loadTestsFromTestCase(TestQuaternion))
+ mysuite.addTest(loader.loadTestsFromTestCase(TestGeoloc))
+ mysuite.addTest(loader.loadTestsFromTestCase(TestGeolocDefs))
+
+ return mysuite
diff --git a/pyorbital/tests/test_orbital.py b/pyorbital/tests/test_orbital.py
new file mode 100644
index 0000000..9704ca6
--- /dev/null
+++ b/pyorbital/tests/test_orbital.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012-2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Test the geoloc orbital.
+"""
+
+import unittest
+from datetime import datetime, timedelta
+
+import numpy as np
+
+from pyorbital import orbital
+
+eps_deg = 10e-3
+
+class Test(unittest.TestCase):
+
+ def test_get_orbit_number(self):
+ """Testing getting the orbitnumber from the tle"""
+ sat = orbital.Orbital("NPP",
+ line1="1 37849U 11061A 12017.90990040 -.00000112 00000-0 -32693-4 0 772",
+ line2="2 37849 98.7026 317.8811 0001845 92.4533 267.6830 14.19582686 11574")
+ dobj = datetime(2012, 1, 18, 8, 4, 19)
+ orbnum = sat.get_orbit_number(dobj)
+ self.assertEqual(orbnum, 1163)
+
+ def test_sublonlat(self):
+ sat = orbital.Orbital("ISS (ZARYA)",
+ line1="1 25544U 98067A 03097.78853147 .00021906 00000-0 28403-3 0 8652",
+ line2="2 25544 51.6361 13.7980 0004256 35.6671 59.2566 15.58778559250029")
+ d = datetime(2003, 3, 23, 0, 3, 22)
+ lon, lat, alt = sat.get_lonlatalt(d)
+ expected_lon = -68.199894472013213
+ expected_lat = 23.159747677881075
+ expected_alt = 392.01953430856935
+ self.failUnless(np.abs(lon - expected_lon) < eps_deg, 'Calculation of sublon failed')
+ self.failUnless(np.abs(lat - expected_lat) < eps_deg, 'Calculation of sublat failed')
+ self.failUnless(np.abs(alt - expected_alt) < eps_deg, 'Calculation of altitude failed')
+
+
+ def test_observer_look(self):
+ sat = orbital.Orbital("ISS (ZARYA)",
+ line1="1 25544U 98067A 03097.78853147 .00021906 00000-0 28403-3 0 8652",
+ line2="2 25544 51.6361 13.7980 0004256 35.6671 59.2566 15.58778559250029")
+ d = datetime(2003, 3, 23, 0, 3, 22)
+ az, el = sat.get_observer_look(d, -84.39733, 33.775867, 0)
+ expected_az = 122.45169655331965
+ expected_el = 1.9800219611255456
+ self.failUnless(np.abs(az - expected_az) < eps_deg, 'Calculation of azimut failed')
+ self.failUnless(np.abs(el - expected_el) < eps_deg, 'Calculation of elevation failed')
+
+ def test_orbit_num_an(self):
+ sat = orbital.Orbital("METOP-A",
+ line1="1 29499U 06044A 11254.96536486 .00000092 00000-0 62081-4 0 5221",
+ line2="2 29499 98.6804 312.6735 0001758 111.9178 248.2152 14.21501774254058")
+ d = datetime(2011, 9, 14, 5, 30)
+ self.assertEqual(sat.get_orbit_number(d), 25437)
+
+ def test_orbit_num_non_an(self):
+ sat = orbital.Orbital("METOP-A",
+ line1="1 29499U 06044A 13060.48822809 .00000017 00000-0 27793-4 0 9819",
+ line2="2 29499 98.6639 121.6164 0001449 71.9056 43.3132 14.21510544330271")
+ dt = timedelta(minutes=98)
+ self.assertEqual(sat.get_orbit_number(sat.tle.epoch + dt), 33028)
+
+ def test_orbit_num_equator(self):
+ sat = orbital.Orbital("SUOMI NPP",
+ line1="1 37849U 11061A 13061.24611272 .00000048 00000-0 43679-4 0 4334",
+ line2="2 37849 98.7444 1.0588 0001264 63.8791 102.8546 14.19528338 69643")
+ t1 = datetime(2013, 3, 2, 22, 2, 25)
+ t2 = datetime(2013, 3, 2, 22, 2, 26)
+ on1 = sat.get_orbit_number(t1)
+ on2 = sat.get_orbit_number(t2)
+ self.assertEqual(on1, 6973)
+ self.assertEqual(on2, 6974)
+ pos1, vel1 = sat.get_position(t1, normalize=False)
+ pos2, vel2 = sat.get_position(t2, normalize=False)
+ del vel1, vel2
+ self.assertTrue(pos1[2] < 0)
+ self.assertTrue(pos2[2] > 0)
+
+
+
+def suite():
+ """The suite for test_orbital
+ """
+ loader = unittest.TestLoader()
+ mysuite = unittest.TestSuite()
+ mysuite.addTest(loader.loadTestsFromTestCase(Test))
+
+ return mysuite
diff --git a/pyorbital/tests/test_tlefile.py b/pyorbital/tests/test_tlefile.py
new file mode 100644
index 0000000..b7e41e1
--- /dev/null
+++ b/pyorbital/tests/test_tlefile.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Testing TLE file reading
+"""
+
+
+from pyorbital.tlefile import Tle
+import datetime
+import unittest
+
+line0 = "ISS (ZARYA)"
+line1 = "1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927"
+line2 = "2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537"
+
+
+
+class TLETest(unittest.TestCase):
+ """Test TLE reading.
+
+ We're using the wikipedia example::
+
+ ISS (ZARYA)
+ 1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927
+ 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537
+
+ """
+
+ def check_example(self, tle):
+ """Check the *tle* instance against predetermined values.
+ """
+ # line 1
+ self.assertEqual(tle.satnumber, "25544")
+ self.assertEqual(tle.classification, "U")
+ self.assertEqual(tle.id_launch_year, "98")
+ self.assertEqual(tle.id_launch_number, "067")
+ self.assertEqual(tle.id_launch_piece.strip(), "A")
+ self.assertEqual(tle.epoch_year, "08")
+ self.assertEqual(tle.epoch_day, 264.51782528)
+ epoch = (datetime.datetime(2008, 1, 1)
+ + datetime.timedelta(days=264.51782528 - 1))
+ self.assertEqual(tle.epoch, epoch)
+ self.assertEqual(tle.mean_motion_derivative, -.00002182)
+ self.assertEqual(tle.mean_motion_sec_derivative, 0.0)
+ self.assertEqual(tle.bstar, -.11606e-4)
+ self.assertEqual(tle.ephemeris_type, 0)
+ self.assertEqual(tle.element_number, 292)
+
+ # line 2
+ self.assertEqual(tle.inclination, 51.6416)
+ self.assertEqual(tle.right_ascension, 247.4627)
+ self.assertEqual(tle.excentricity, .0006703)
+ self.assertEqual(tle.arg_perigee, 130.5360)
+ self.assertEqual(tle.mean_anomaly, 325.0288)
+ self.assertEqual(tle.mean_motion, 15.72125391)
+ self.assertEqual(tle.orbit, 56353)
+
+ def test_from_line(self):
+ tle = Tle("ISS (ZARYA)", line1=line1, line2=line2)
+ self.check_example(tle)
+
+ def test_from_file(self):
+ from tempfile import mkstemp
+ from os import write, close, remove
+ filehandle, filename = mkstemp()
+ try:
+ write(filehandle, "\n".join([line0, line1, line2]))
+ close(filehandle)
+ tle = Tle("ISS (ZARYA)", filename)
+ self.check_example(tle)
+ finally:
+ remove(filename)
+
+
+def suite():
+ """The suite for test_tlefile
+ """
+ loader = unittest.TestLoader()
+ mysuite = unittest.TestSuite()
+ mysuite.addTest(loader.loadTestsFromTestCase(TLETest))
+
+ return mysuite
+
diff --git a/pyorbital/tlefile.py b/pyorbital/tlefile.py
new file mode 100644
index 0000000..a939c62
--- /dev/null
+++ b/pyorbital/tlefile.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011, 2012, 2013, 2014.
+
+# Author(s):
+
+# Esben S. Nielsen <esn at dmi.dk>
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+
+import logging
+import datetime
+import urllib2
+
+tle_urls = ('http://celestrak.com/NORAD/elements/weather.txt',
+ 'http://celestrak.com/NORAD/elements/resource.txt')
+
+logger = logging.getLogger(__name__)
+
+def read(platform, tle_file=None, line1=None, line2=None):
+ """Read TLE for *satellite* from *tle_file*, from *line1* and *line2*, or
+ from internet if none is provided.
+ """
+ return Tle(platform, tle_file=tle_file, line1=line1, line2=line2)
+
+def fetch(destination):
+ """fetch TLE from internet and save it to *destination*.
+ """
+ with open(destination, "w") as dest:
+ for url in tle_urls:
+ response = urllib2.urlopen(url)
+ dest.write(response.read())
+
+class ChecksumError(Exception):
+ pass
+
+
+class Tle(object):
+ """Class holding TLE objects.
+ """
+
+ def __init__(self, platform, tle_file=None, line1=None, line2=None):
+ platform = platform.strip().upper()
+
+ if line1 is not None and line2 is not None:
+ tle = line1.strip() + "\n" + line2.strip()
+ else:
+ if tle_file:
+ urls = (tle_file,)
+ open_func = open
+ else:
+ logger.debug("Fetch tle from the internet.")
+ urls = tle_urls
+ open_func = urllib2.urlopen
+
+ tle = ""
+ for url in urls:
+ fp = open_func(url)
+ for l0 in fp:
+ l1, l2 = fp.next(), fp.next()
+ if l0.strip() == platform:
+ tle = l1.strip() + "\n" + l2.strip()
+ break
+ fp.close()
+ if tle:
+ break
+
+ if not tle:
+ raise AttributeError, "Found no TLE entry for '%s'" % platform
+
+ self._platform = platform
+ self._line1, self._line2 = tle.split('\n')
+ self._checksum()
+ self._read_tle()
+
+ @property
+ def line1(self):
+ return self._line1
+
+ @property
+ def line2(self):
+ return self._line2
+
+ @property
+ def platform(self):
+ return self._platform
+
+ def _checksum(self):
+ """Performs the checksum for the current TLE.
+ """
+ for line in [self.line1, self.line2]:
+ check = 0
+ for char in line[:-1]:
+ if char.isdigit():
+ check += int(char)
+ if char == "-":
+ check += 1
+
+ if (check % 10) != int(line[-1]):
+ raise ChecksumError(self._platform + " " + line)
+
+ def _read_tle(self):
+
+ def _read_tle_decimal(rep):
+ if rep[0] in ["-", " "]:
+ val = rep[0] + "." + rep[1:-2] + "e" + rep[-2:]
+ else:
+ val = "." + rep[:-2] + "e" + rep[-2:]
+
+ return float(val)
+
+ self.satnumber = self._line1[2:7]
+ self.classification = self._line1[7]
+ self.id_launch_year = self._line1[9:11]
+ self.id_launch_number = self._line1[11:14]
+ self.id_launch_piece = self._line1[14:17]
+ self.epoch_year = self._line1[18:20]
+ self.epoch_day = float(self._line1[20:32])
+ self.epoch = (datetime.datetime.strptime(self.epoch_year, "%y") +
+ datetime.timedelta(days=self.epoch_day - 1))
+ self.mean_motion_derivative = float(self._line1[33:43])
+ self.mean_motion_sec_derivative = _read_tle_decimal(self._line1[44:52])
+ self.bstar = float(self._line1[53] + "." + self._line1[54:59] + "e" + self._line1[59:61])
+ _read_tle_decimal(self._line1[53:61])
+ try:
+ self.ephemeris_type = int(self._line1[62])
+ except ValueError:
+ self.ephemeris_type = 0
+ self.element_number = int(self._line1[64:68])
+
+ self.inclination = float(self._line2[8:16])
+ self.right_ascension = float(self._line2[17:25])
+ self.excentricity = int(self._line2[26:33]) * 10 ** -7
+ self.arg_perigee = float(self._line2[34:42])
+ self.mean_anomaly = float(self._line2[43:51])
+ self.mean_motion = float(self._line2[52:63])
+ self.orbit = int(self._line2[63:68])
+
+ def __str__(self):
+ import pprint, StringIO
+ s = StringIO.StringIO()
+ d = dict(([(k, v) for k, v in self.__dict__.items() if k[0] != '_']))
+ pprint.pprint(d, s)
+ return s.getvalue()[:-1]
+
+if __name__ == '__main__':
+ tle = read('noaa 19')
+ print tle
diff --git a/pyorbital/version.py b/pyorbital/version.py
new file mode 100644
index 0000000..db58857
--- /dev/null
+++ b/pyorbital/version.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 Martin Raspaud
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+"""Version file.
+"""
+
+__major__ = "0"
+__minor__ = "3"
+__patch__ = "2"
+
+__version__ = "v" + ".".join([__major__, __minor__, __patch__])
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..3ce9449
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011-2014
+
+# Author(s):
+
+# Martin Raspaud <martin.raspaud at smhi.se>
+
+# 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/>.
+
+from setuptools import setup
+import imp
+
+version = imp.load_source('pyorbital.version', 'pyorbital/version.py')
+
+setup(name='pyorbital',
+ version=version.__version__,
+ description='Orbital parameters and astronomical computations in Python',
+ author='Martin Raspaud, Esben S. Nielsen',
+ author_email='martin.raspaud at smhi.se, esn at dmi.dk',
+ classifiers=["Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: GNU General Public License v3 " +
+ "or later (GPLv3+)",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Topic :: Scientific/Engineering",
+ "Topic :: Scientific/Engineering :: Astronomy"],
+ url="https://github.com/mraspaud/pyorbital",
+ test_suite='pyorbital.tests.suite',
+ package_dir = {'pyorbital': 'pyorbital'},
+ packages = ['pyorbital'],
+ install_requires=['numpy'],
+ zip_safe=False,
+ )
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pyorbital.git
More information about the Pkg-grass-devel
mailing list