I’m happy to announce the release of SquareWidget.Astronomy.Core, a new code library targeting .NET 8.0 and written in C#, that supports common astronomical calculations and algorithms. The current version is 1.1.0. You can reference the NuGet package at the link above. It has a baseline of functionality and I have plans to add more over time.
Why a library? I’ve been writing code (and snippets of code) over several years to solve various problems in astronomy. When something looked interesting enough to share, I published some of that code on my GitHub repo and on this blog. Recently I was ploughing through the position angle of Saturn’s north pole (Jean Meeus, Astronomical Algorithms, Chapter 49). After some long debugging sessions, I realized I was using the double data type for everything. Several times I would forget whether a value was in degrees, radians, large angles, reduced angles, or something else entirely. So, I decided I needed a basic code library to bring a little order out of the chaos. The first thing I added were the units of measure. Then planets and calculators came later. I have two design goals in mind for the library: useability and robustness. Certainly, the library should return results accurate to within a few minutes of degrees. But it should also be intuitive and easy to use.
I’ve written more detailed documentation on the GitHub README. Here I’ll just introduce a few of the features. At the heart of the library is a Moment
struct. You can pass in date and time parameters, a DateTime
instance, or a Julian Day (JD) value:
Moment m1 = new(2024, 1, 31, 9, 36, 0); Moment m2 = new(2024, 1, 31.4); Moment m3 = new(2460340.90001); string s1 = m1.ToDateTime().ToString("yyyy MMM dd HH:mm"); string s2 = m2.ToDateTime().ToString("yyyy MMM dd HH:mm"); string s3 = m3.ToDateTime().ToString("yyyy MMM dd HH:mm"); Console.WriteLine(s1); // 2024 Jan 31 09:36 Console.WriteLine(s2); // 2024 Jan 31 09:36 Console.WriteLine(s3); // 2024 Jan 31 09:36
Once you have a Moment you can get its JD, modified JDE, Day D, or Time T (measure of Julian centuries from epoch J2000.0).
The code library also includes several units of measure with the ability to convert between them. For example, suppose I want to model the Earth’s obliquity of the ecliptic. I can create a Degrees
object by passing in decimal degrees:
Degrees d = new(23.41); Console.WriteLine(d.ToString()); // 23°.41
Units can be converted to other units. Here I’ll convert to Radians
, then a SexesimalAngle
, and back to Degrees
again:
Degrees d = new(23.41); Console.WriteLine(d.ToString()); // 23°.41 Radians r = d.ToRadians(); Console.WriteLine(r.ToString()); // 0.4085816 SexigesimalAngle sa = new(d); Console.WriteLine(sa.ToString()); // +23° 24' 36" Degrees d1 = new(sa); Console.WriteLine(d1.ToString()); // 23°.41
Quite often in astronomical calculations we deal with very large angles. Those can be reduced to within the range [0, 360] with the ToReducedAngle
function:
Degrees d = new(13512.45); Console.WriteLine(d.ToString()); // 13512°.45 Console.WriteLine(d.ToReducedAngle().ToString()); // 192°.45
A RightAscension
can be constructed with the standard hours, minutes, and seconds (HMS) or decimal degrees:
// passing in HMS RightAscension ra = new(12, 37, 27); Console.WriteLine(ra.ToString()); // 12h 37m 27s // passing decimal degrees RightAscension ra = new(189.3625); Console.WriteLine(ra.ToString()); // 12h 37m 27s
Two coordinate systems have been implemented, equitorial and ecliptical, and you can convert back and forth between them. Suppose we have the equatorial coordinates (α, δ) of Pollux from a star catalog or the wiki and we know Earth’s obliquity of the ecliptic (ε):
// Pollux (β Gem) RightAscension α = new(7, 45, 18.946); SexigesimalAngle δ = new(28, 01, 34.26); Degrees ε = new(23.4392911); EquitorialCoordinates eqc = new(δ, α, ε); Console.WriteLine(eqc.α.ToString()); // 7h 45m 18.946s Console.WriteLine(eqc.δ.ToString()); // +28° 1' 34.26"
We can take those coordinates and convert them to ecliptical coordinates:
EquitorialCoordinates eqc = new(δ, α, ε); EclipticalCoordinates ec = eqc.ToΕclipticCoordinates(); Console.WriteLine(ec.λ.ToDegrees().ToReducedAngle().ToString()); // 113°.21 Console.WriteLine(ec.β.ToDegrees().ToString()); // 6°.68
You can instantiate a planet with the new
operator or use the factory method. You must pass in a Moment
struct either way.
DateTime datetime = new(2028, 7, 1); Moment moment = new(datetime); // using new operator Earth earth = new(moment); // using factory method for polymorphism Planet planet = PlanetFactory.Create(PlanetName.Earth, moment);
Once you have a planet you can get its properties which include orbital elements and heliocentric spherical coordinates.
The library has six calculators right now and I plan to add at least a couple more in the next few weeks.
-
- Geocentric position calculator
- Moon phase and dates calculator
- Nutation calculator
- Position Angle of Saturn’s semiminor axis calculator
- Sundial calculator
- Solar longitude calculator
Consult the README documentation and the unit tests for details. Let me just illustrate one here. Suppose I want to know the four main phases of the moon for the month of August 2024:
DateOnly startDate = new(2024, 7, 1); DateOnly endDate = new(2024, 9, 30); DateRange dateRange = new(startDate, endDate); var list = MoonPhaseDatesCalculator.Calculate(dateRange); // use a collection expression to get just August list = [.. list .Where(i => i.Moment.Month == 8) .OrderBy(o => o.Moment.ToDateTime())]; foreach (var item in list) { Console.WriteLine(item.PhaseName + " on " + item.Moment.ToDateTime().ToString("MM/dd/yyyy hh:mm:ss.fff tt")); }
This displays:
NewMoon on 08/04/2024 11:12:56.525 AM FirstQuarter on 08/12/2024 03:19:31.125 PM FullMoon on 08/19/2024 06:25:37.281 PM LastQuarter on 08/26/2024 09:27:16.726 AM
What’s next? I’ve got two enhancements open right now. One is to add a feature to calculate solar eclipses and the other is to calculate the positions of the four Galilean moons of Jupiter. Sometime after that I’ll want to address magnitude, planetary perihelion and aphelion, and probably more fun stuff with the Moon. Drop me a line if you have any requests.