From 261390a3fb7be923895d08cfd8ae172b22895b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C3=ADas=20A=2E=20Angulo=20Klein?= Date: Sun, 21 Jul 2024 22:05:30 +0200 Subject: [PATCH] Added MoonPhase library --- src/MoonPhase.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++ src/MoonPhase.h | 33 ++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/MoonPhase.cpp create mode 100644 src/MoonPhase.h diff --git a/src/MoonPhase.cpp b/src/MoonPhase.cpp new file mode 100644 index 0000000..7797c14 --- /dev/null +++ b/src/MoonPhase.cpp @@ -0,0 +1,96 @@ +// Calculate the phase and position of the moon for a given date. +// The algorithm is simple and adequate for many purposes. +// +// This software was originally adapted to javascript by Stephen R. Schmitt +// from a BASIC program from the 'Astronomical Computing' column of Sky & Telescope, +// April 1994, page 86, written by Bradley E. Schaefer. +// +// Subsequently adapted from Stephen R. Schmitt's javascript to c++ for the Arduino +// by Cyrus Rahman, this work is subject to Stephen Schmitt's copyright: +// +// Copyright 2004 Stephen R. Schmitt +// You may use or modify this source code in any way you find useful, provided +// that you agree that the author(s) have no warranty, obligations or liability. You +// must determine the suitability of this source code for your use. + +#include +#include "MoonPhase.h" + +// Names of lunar phases +static const char *phaseNames[] = {"New", "Evening Crescent", "First Quarter", + "Waxing Gibbous", "Full", "Waning Gibbous", + "Last Quarter", "Morning Crescent"}; +// Names of Zodiac constellations +static const char *zodiacNames[] = {"Pisces", "Aries", "Taurus", "Gemini", "Cancer", + "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", + "Capricorn", "Aquarius"}; +// Ecliptic angles of Zodiac constellations +static const float zodiacAngles[] = {33.18, 51.16, 93.44, 119.48, 135.30, 173.34, + 224.17, 242.57, 271.26, 302.49, 311.72, 348.58}; + +// Constructor initialization. +MoonPhase::MoonPhase() { + jDate = 0; + phase = 0; + age = 0; + fraction = 0; + distance = 0; + latitude = 0; + longitude = 0; + phaseName = zodiacName = ""; +} + +// Determine the Moon Phase and orbital positions for the specified time. +void +MoonPhase::calculate(time_t t) { + jDate = julianDate(t); + + // Calculate illumination (synodic) phase. + // From number of days since new moon on Julian date MOON_SYNODIC_OFFSET + // (1815UTC January 6, 2000), determine remainder of incomplete cycle. + phase = (jDate - MOON_SYNODIC_OFFSET) / MOON_SYNODIC_PERIOD; + phase -= floor(phase); + + // Calculate age and illumination fraction. + age = phase * MOON_SYNODIC_PERIOD; + fraction = (1.0 - cos(2 * M_PI * phase)) * 0.5; + phaseName = phaseNames[(int)(phase * 8 + 0.5) % 8]; + + // Calculate distance from anomalistic phase. + double distancePhase = (jDate - MOON_DISTANCE_OFFSET) / MOON_DISTANCE_PERIOD; + distancePhase -= floor(distancePhase); + distance = 60.4 - 3.3 * cos(2 * M_PI * distancePhase) + - 0.6 * cos(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase) + - 0.5 * cos(2 * 2 * M_PI * phase); + + // Calculate ecliptic latitude from nodal (draconic) phase. + double latPhase = (jDate - MOON_LATITUDE_OFFSET) / MOON_LATITUDE_PERIOD; + latPhase -= floor(latPhase); + latitude = 5.1 * sin(2 * M_PI * latPhase); + + // Calculate ecliptic longitude from sidereal motion. + double longPhase = (jDate - MOON_LONGITUDE_OFFSET) / MOON_LONGITUDE_PERIOD; + longPhase -= floor(longPhase); + longitude = 360 * longPhase + + 6.3 * sin(2 * M_PI * distancePhase) + + 1.3 * sin(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase) + + 0.7 * sin(2 * 2 * M_PI * phase); + if (longitude > 360) + longitude -= 360; + + // Select the Zodiac name. + zodiacName = zodiacNames[0]; + for (int i = 0; i < sizeof(zodiacAngles) / sizeof(float); i++) { + if (longitude < zodiacAngles[i]) { + zodiacName = zodiacNames[i]; + break; + } + } +} + +// Determine Julian date from Unix time. +// Provides marginally accurate results with older Arduino 4-byte double. +double +MoonPhase::julianDate(time_t t) { + return (t / 86400.0L + 2440587.5); +} diff --git a/src/MoonPhase.h b/src/MoonPhase.h new file mode 100644 index 0000000..b63d1f5 --- /dev/null +++ b/src/MoonPhase.h @@ -0,0 +1,33 @@ +#ifndef MoonPhase_h +#define MoonPhase_h + +#include + +#define MOON_SYNODIC_PERIOD 29.530588853 // Period of moon cycle in days. +#define MOON_SYNODIC_OFFSET 2451550.26 // Reference cycle offset in days. +#define MOON_DISTANCE_PERIOD 27.55454988 // Period of distance oscillation +#define MOON_DISTANCE_OFFSET 2451562.2 +#define MOON_LATITUDE_PERIOD 27.212220817 // Latitude oscillation +#define MOON_LATITUDE_OFFSET 2451565.2 +#define MOON_LONGITUDE_PERIOD 27.321582241 // Longitude oscillation +#define MOON_LONGITUDE_OFFSET 2451555.8 + +class MoonPhase { + public: + double jDate; + double phase; // 0 - 1, 0.5 = full + double age; // Age in days of current cycle + double fraction; // Fraction of illuminated disk + double distance; // Moon distance in earth radii + double latitude; // Moon ecliptic latitude + double longitude; // Moon ecliptic longitude + const char *phaseName; // New, Full, etc. + const char *zodiacName; // Constellation + + MoonPhase(); + void calculate(time_t); + + private: + double julianDate(time_t); +}; +#endif