Commit Graph

360 Commits

Author SHA1 Message Date
Don Cross
dd0245cbf8 C: Astronomy_GetCurrentTime supports microsecond resolution.
This is a follow-up to work provided by:
Eric Wheeler, KJ7LNW <astronomy-git@z.ewheeler.org>

Before now, the C function Astronomy_GetCurrentTime returned
the current time from the system clock, but only with whole
second resolution. Now it supports microsecond resolution on
Linux/Unix, Mac OS, and Windows.

For unsupported platforms, a compiler error will occur
to indicate that microsecond resolution is not available.
However, it is possible to define one of the following two
preprocessor symbols to work around the compiler error:

1. ASTRONOMY_ENGINE_NO_CURRENT_TIME
   Excludes the function Astronomy_CurrentTime from the build.
   If your project does not need to obtain the current time,
   or your hardware platform does not provide current date
   and time in the first place, this is likely the better option.

2. ASTRONOMY_ENGINE_WHOLE_SECOND
   If your project does need to use the current date and time
   for astronomy calculations, and it can tolerate whole
   second resolution, this option provides a version of
   Astronomy_CurrentTime that uses a call to `time(NULL)`.

Notes:

- Added unit test to confirm at least millisecond resolution.
  Because these tests have to run on GitHub Actions cloud platform,
  and those systems can be heavily CPU-loaded, I want to be tolerant
  of resolution and avoid false failures.

- Added detection of Mac platform.

- Added preprocessor options documented above.

- On Windows, use ULARGE_INTEGER and eliminated one integer division.

- Added comments and developer documentation.

- Converted tabs to spaces in astronomy.c, for consistent code format.
2023-08-28 12:24:20 -04:00
Don Cross
69311b3ccf Adjusted cppcheck options and fixed more warnings. 2023-03-26 06:47:09 -04:00
Don Cross
37a0c44c9b Fixed uninitialized struct in C tests. 2023-03-25 15:34:03 -04:00
Don Cross
501c19015b Run cppcheck. Fixed errors in C code found by cppcheck. 2023-03-25 14:46:42 -04:00
Don Cross
cdd75c7810 C SearchRiseSetEx: moved metersAboveGround parameter to end.
Because I plan on adding metersAboveGround as a parameter
that defaults to 0.0 in the other languages, and I want
the language implementations to be reasonably consistent,
I moved the metersAboveGround parameter to the end of
the parameter list for the C version of SearchRiseSetEx.
2023-03-11 18:50:57 -05:00
Don Cross
9a0151d9d4 C: Added unit tests for Atmosphere function. 2023-03-06 14:15:30 -05:00
Don Cross
c275922c0e C: rise/set now corrects for height above ground.
I realized I had to rework the RiseSetEx function so that
it accepts a height above ground level, rather than a generic
altitude angle correction, because atmospheric effects are
important both for the horizon dip angle and for the amount
of refraction at ground level.

The atmosphere calculations were interesting enough that
I made them public as a new function Astronomy_Atmosphere.
This returns the idealized temperature, pressure, and relative
density of air at the given elevation above/below sea level.
2023-03-05 22:05:40 -05:00
Don Cross
cc7d9f5bc9 C: Implemented horizon dip calculation for observer above ground.
This is the first step toward calculating body rise/set times
for an observer that is significantly above the ground.
It figures out the angular correction of the horizon
using both parallax and refractive correction of a light
ray from the horizon to the observer's eye.
2023-03-05 13:56:26 -05:00
Don Cross
ce0acf6d44 Kotlin: support calendar dates for years -999999 to +999999.
Enhanced the Time class to correctly calculate calendar
dates for the year range -999999 to +999999.

Made unit tests in C, C#, and Kotlin all exercise
the full year range, for February 28 and March 1 in each year,
to make sure we cover before and after each potential leap day.
2023-02-26 12:54:57 -05:00
Don Cross
1ac4ab2dba C: Fixed more problems with calendar date calculations.
With more rigorous testing, I discovered more bugs
in the C functions for converting calendar dates
to times and vice versa.

Astronomy_UtcFromTime():
When the year went before -4714, the value of the variable
`djd` went negative, causing the typecast `(long)djd` to
round toward zero instead of taking the true floor.
Changed this to `(long)floor(djd)`.

Astronomy_MakeTime():
Reworked the logic so that none of the integer divisions
involve negative values over the year range -999999..+999999.
2023-02-25 18:18:42 -05:00
Don Cross
f537974530 C: Fixed bugs in Astronomy_UtcFromTime for extreme year values.
Addressed limitations of the logic I copied from NOVAS cal_date().
Its formulas did not work for years much before -12000 due to
integer division going negative. I figured out how to make the
formulas work for plus or minus 1 million years from the present era.
2023-02-24 20:31:55 -05:00
ris-tlp
f442afd342 Relaxation of test for M1 MacOS Ventura 13.2.1 2023-02-18 02:03:42 -05:00
Don Cross
43c37c9038 C#: Implemented HourAngle function. 2023-02-12 13:05:29 -05:00
Don Cross
6a8a905aa5 C: Implemented Astronomy_HourAngle function.
We already had a function to search for the next time a body
reaches a certain hour angle. But we didn't have a function
to ask what the current hour angle of a body is.
This will resolve that problem, which will also answer
questions about true solar time: use the Sun as the body,
and add 12 to the hour angle, modulo 24.
2023-02-12 10:52:42 -05:00
Don Cross
ae467d67df ctest: Finished eliminating hardcoded function names. 2023-02-08 14:26:20 -05:00
Don Cross
67955c2575 ctest.c: More WIP eliminating hardcoded function names. 2023-02-08 11:57:17 -05:00
Don Cross
3777b7f5bb C tests: remove hardcoded function names (WIP). 2023-02-07 15:45:14 -05:00
Don Cross
1624ca0890 A quick test to see if __func__ is supported.
It looks like the C unit tests can use __func__ to avoid
hardcoded function names everywhere. I know this is defined
in C++11 and C99, so it should be fine. If it passes unit
testing across all platforms I exercise in GitHub Actions,
I feel comfortable using it, since it will not affect
production code.
2023-02-07 12:27:22 -05:00
Don Cross
1a4f842764 Updated Ecliptic to return ECL in all languages. 2022-12-10 19:35:42 -05:00
Don Cross
47ce0ac34e C#: EquatorialToEcliptic now returns ECT instead of ECL. 2022-12-09 21:03:05 -05:00
Don Cross
f811b6f55b C: Ecliptic function returns ECT instead of ECL.
Now the C function Astronomy_Ecliptic returns ecliptic
coordinates in true equinox of date instead of the
J2000 mean equinox. I'm doing this because it is a
better fit for physical phenomena that ecliptic
coordinates are often used for. For example, lunar nodes,
eclipses, phase angles, and oppositions make more sense
with true latitude and longitude of date.

I will port these changes to the other languages also.
2022-12-09 20:00:52 -05:00
Don Cross
1864fa8539 Orientation nomenclature. C: EQJ/ECT rotations.
More work standardizing the nomenclature of the
orientation systems across all language documents.

Added C functions to calculate rotation matrices
for EQJ/ECT and ECT/EQJ.
2022-12-08 22:03:43 -05:00
Don Cross
c102208e2b C: Rotation matrices for EQD/ECT.
Added new C functions to convert back and forth
between Equator of Date (EQD) and True Ecliptic of Date (ECT).
2022-12-06 15:09:00 -05:00
Don Cross
552c7a5557 EclipticGeoMoon uses true equinox of date in all languages.
Added EclipticGeoMoon as output to the temp/*_check.txt files as 'm' lines.
This ensures that all the languages calculate nearly identical values.

Optimized EclipticGeoMoon a little more by eliminating a redundant
call to mean_obliq.
2022-12-05 21:44:35 -05:00
Don Cross
2bdb25227e C EclipticGeoMoon: use true equinox of date.
Updated the C function Astronomy_EclipticGeoMoon to
correct ecliptic coordinates for nutation.
This means that the returned value is expressed in
true equinox of date instead of mean equinox of date.

This results in the moon_ecm test decreasing the max
longitude error from 24 arcseconds to 6 arcseconds.
EclipticGeoMoon is now about 40% slower, but it still
runs in about 0.4 microseconds per call.
2022-12-05 13:55:36 -05:00
Don Cross
b8d195cbca C moon_ecm: handle 360-degree wraparound. More checking. 2022-12-05 11:50:18 -05:00
Don Cross
6b8816b1b5 C tests: make excluded tests more obviously marked. 2022-12-05 11:37:19 -05:00
Don Cross
d3f36b942d Verify nutation angles are consistent across languages. 2022-12-04 14:20:44 -05:00
Don Cross
740a65d29b Windows: fixes for testing nutation changes. 2022-12-04 11:13:24 -05:00
Don Cross
8a153315cf Simplified and optimized nutation formula.
While trying to convert ecliptic coordinates from mean
equinox of date to true equinox of date, I ran into excessive
overhead from the IAU2000B nutation model. The fact that it
uses 77 trigonometric terms made the calculations a lot slower.

https://apps.dtic.mil/sti/pdfs/AD1112517.pdf
Page 4 in the above document mentions a shorter series
“NOD version 2” that has 13 terms instead of 77 as used in IAU2000B.
I had not noticed NOD2 before, because it appears only in
the FORTRAN version of NOVAS 3.x, not the C version.

After reading the FORTRAN code, I realized NOD2 is the same
as IAU2000B, only it keeps the first 13 of 77 terms.
The terms are already arranged in descending order of
significance, so it is easy to truncate the series.

Based on this discovery, I realized I could achieve all of
the required accuracy needed for Astronomy Engine by
keeping only the first 5 terms of the nutation series.
This tremendously speeds up nutation calculations while
sacrificing only a couple of arcseconds of accuracy.

It also makes the minified JavaScript code smaller:
Before: 119500 bytes.
After:  116653 bytes.

So that's what I did here. Most of the work was updating
unit tests for accepting slightly different calculation
results.

The nutation formula change did trigger detection of a
lurking bug in the inverse_terra functions, which convert
a geocentric vector into latitude, longitude, and elevation
(i.e. an Observer object). The Newton's Method loop in
this function was not always converging, resulting in
an infinite loop. I fixed that by increasing the
convergence threshold and throwing an exception
if the loop iterates more than 10 times.

I also fixed a couple of bugs in the `demotest` scripts.
2022-12-04 10:31:15 -05:00
Don Cross
b2b426096f Added C performance test for nutation.
SiderealTime called 14,609,700 times in 47.217 seconds
= 3.23 microseconds per call.
2022-12-03 21:40:20 -05:00
Don Cross
c29ec327f5 Measure the speed of EclipticGeoMoon.
Added a performance test to measure how fast
a call to EclipticGeoMoon is. Results:
Over 3 trials, mean time = 24.064 seconds.
Number of calls = 14,609,700.
Time per call = 1.647 microseconds.
That is faster than I thought!

Also replaced conditional compilation with a runtime flag
to indicate whether a test should be skipped by the "all"
command. This allows me to run performance tests without
hacking a #define in the code, plus it ensures that even
though I don't run the performance tests every time I change
Astronomy Engine, they at least compile without errors.
2022-12-03 13:38:22 -05:00
Don Cross
72634ea84b Removed test: C Ecliptic. No longer needed.
This was another test where I was trying to figure out
an apparent anomaly that was actually based on my
flawed assumption about why obliquity changes over time.
2022-12-01 13:51:42 -05:00
Don Cross
0ae8bf2bd3 C MoonEcliptic test: add error threshold checks. 2022-12-01 13:49:28 -05:00
Don Cross
a20f17bf8f Removed C MoonLatitudes test.
I don't need the MoonLatitudes test any more.
Its purpose was to investigate what I thought was an
ecliptic latitude discrepancy. Now I understand that
changes in obliquity are caused by changes in the ecliptic
plane, not the equatorial plane.
2022-12-01 13:34:09 -05:00
Don Cross
28a3505040 More C ecliptic latitude tests.
I'm still trying to understand a discrepancy
between ecliptic latitudes calculated in two
different equinoxes: mean equinox of date and
mean J2000 equinox. I keep thinking the two
latitude values should be the same, because they
are measured against an essentially unchanging
ecliptic plane. I understand that ecliptic longitudes
should change as the Earth's equator precesses
by 47 arcseconds per century.

Added new test MoonEcliptic(), that compares
JPL Horizons calculations of the Moon's ecliptic
coordinates relative to equator of date versus
Astronomy_EclipticGeoMoon():

C MoonEcliptic: PASS: count=73050, max lat=1.825 arcsec, max lon=23.462 arcsec.

It is so weird that the maximum latitude discrepancy is less than 2 arcseconds.

Updated MoonVector test to measure maximum errors in addition to RMS errors.
Display distance errors in kilometers instead of dimensionless units.

Defined constant JD_2000 so all my tests that
convert Julian Dates from JPL Horizons can share it.
2022-11-30 12:36:36 -05:00
Don Cross
f71e9d17a0 C: added test "Ecliptic" that confirms latitude discrepancy.
There is a discrepancy between ecliptic latitudes measured
using two different mean equinoxes: 1900 and 2000.
The discrepancy is very close to the change of obliquity
expected for a 100-year period: 47 arcseconds.
But ecliptic latitudes should remain constant as
the Earth's axis precesses!
2022-11-29 17:20:06 -05:00
Don Cross
1558f808e4 MoonLatitudes writes CSV file. MoonVector has larger time span.
MoonLatitudes now generates a CSV file for me to study the
ecliptic latitude discrepancy as a function of time.
I can see that it increases away from the year 2000,
and that it is periodic with the Moon's orbit.
This indicates an error in correcting for precession.

Generated new JPL Horizons test data for MoonVector that
covers the years 1900..2100 instead of 1980..2020.
Confirmed that its maximum error is still 1.16 arcsec.
That is error comparing EQJ vectors and ECL vectors.
2022-11-29 11:31:18 -05:00
Don Cross
6cdc6b9d9e ctest: moon_lat experiment, list test names.
The C unit test program ctest.c now includes a MoonLatitudes
function invoked by the name `moon_lat`.
This function demonstrates that there is a 47 arcsecond
discrepancy between ecliptic latitudes using the mean
equator of date and ecliptic latitudes using the mean
equator of J2000. This should not happen! I'm investigating.

Also, when running ctest without command-line arguments,
print a list of all available test names, so I don't have
to go open up the file ctest.c and read the code.
2022-11-29 09:41:38 -05:00
Don Cross
48a95c4ec4 C MoonNodes: print maximum node latitude. 2022-11-28 21:05:45 -05:00
Don Cross
704d412e16 C MoonVector: report errors in arcseconds. 2022-11-28 19:20:46 -05:00
Don Cross
298262e7a0 C MoonVector: test both ECL and EQJ coordinates. 2022-11-28 19:04:03 -05:00
Don Cross
9e48df6d91 Added C MoonVector test.
Extra verification of Astronomy_GeoMoon().
Confirmed accuracy as compared to JPL Horizons:
RMS angular error = 0.017988 arcmin.
RMS distance (relative) = 0.000028.
2022-11-28 18:30:46 -05:00
Don Cross
7b7a306baf Python: Find rise/set/culm of user-defined stars.
Added Python support for user-defined stars.
Defined new StateVector methods: Position and Velocity.
Defined division operator: Vector / float.
Bumped version number to 2.1.12.
2022-11-22 21:42:02 -05:00
Don Cross
f6ad8b5b26 C: Find rise/set/culm of user-defined stars.
SearchRiseSet and SearchHourAngle now work with user-defined stars.

Fixed a bug in InternalSearchAltitude where I failed to return an error
code when its call to MaxAltitudeSlope failed.
2022-11-22 05:46:50 -05:00
Don Cross
6b4c6c67e2 C: Added Astronomy_DefineStar.
Beginning to add support in C for user-defined stars.
2022-11-21 22:16:30 -05:00
Don Cross
480e0c3ab5 C#: Overhauled altitude search for polar regions.
The C# version of the altitude searches now work correctly
near the Earth's poles. This is a port of the C version.
Cleaned up a little code in the C version.
2022-11-13 12:25:10 -05:00
Don Cross
a5995e2ee0 C RiseSet: improved efficiency.
Do not recurse deeper when any solution would
have a rise+set or a set+rise consecutively
within one second. This would risk confusing the
search, which has a 0.1 second tolerance for convergence.
For practical reasons, such events are dubious anyway,
being swamped by unpredictable atmospheric refraction.
Plus it's just faster to not have to recurse so deeply.

Add a safety valve that fails the search if recursion
gets deeper than the above tolerance would ever allow
to happen in the first place.

This change improves performance significantly:

C RiseSet: passed 5909 lines: time errors in minutes: rms=0.2904, max=1.1541, recur=15, altcount=156881

Added helper function AscentError for cleaner code in error cases.
2022-11-13 10:32:47 -05:00
Don Cross
8498d23c73 C RiseSet: print performance stats.
Track the maximum recursion depth in FindAscent.
Count the number of times the altitude_diff function is called.
These are important performance statistics that I want to
measure, so I can try a few optimization ideas.

Current results:

don@spearmint:~/github/astronomy/generate $ ./generate source && ./ctbuild && ./ctest -v riseset
./ctbuild: C compiler = gcc
./ctbuild: Built 'ctest' program.
C RiseSet: Moon    lat=-61.0 lon=103.0
C RiseSet: Moon    lat=-45.0 lon=150.0
C RiseSet: Moon    lat=29.0 lon=-81.0
C RiseSet: Moon    lat=80.0 lon=130.0
C RiseSet: Moon    lat=83.0 lon=105.0
C RiseSet: Moon    lat=84.0 lon=125.0
C RiseSet: Moon    lat=85.0 lon=135.0
C RiseSet: Moon    lat=85.0 lon=140.0
C RiseSet: Sun     lat=-90.0 lon=0.0
C RiseSet: Sun     lat=-88.0 lon=45.0
C RiseSet: Sun     lat=-60.0 lon=-150.0
C RiseSet: Sun     lat=15.0 lon=75.0
C RiseSet: Sun     lat=29.0 lon=-81.0
C RiseSet: Sun     lat=60.0 lon=0.0
C RiseSet: Sun     lat=89.0 lon=30.0
C RiseSet: Sun     lat=90.0 lon=0.0
C RiseSet: passed 5909 lines: time errors in minutes: rms=0.2904, max=1.1541, recur=19, altcount=171438
2022-11-13 09:36:48 -05:00
Don Cross
4602f619d3 C: Rise/set that works near the poles!
This is a whole new algorithm that efficiently finds
all rise/set events, even near the poles.
It uses a recursive bisection search that limits
recursion depth by knowing the maximum possible
|da/dt| = change in altitude with respect to time.
2022-11-12 21:40:20 -05:00