|
| 1 | +// Calculate the phase and position of the moon for a given date. |
| 2 | +// The algorithm is simple and adequate for many purposes. |
| 3 | +// |
| 4 | +// This software was originally adapted to javascript by Stephen R. Schmitt |
| 5 | +// from a BASIC program from the 'Astronomical Computing' column of Sky & Telescope, |
| 6 | +// April 1994, page 86, written by Bradley E. Schaefer. |
| 7 | +// |
| 8 | +// Subsequently adapted from Stephen R. Schmitt's javascript to c++ for the Arduino |
| 9 | +// by Cyrus Rahman, this work is subject to Stephen Schmitt's copyright: |
| 10 | +// |
| 11 | +// Copyright 2004 Stephen R. Schmitt |
| 12 | +// You may use or modify this source code in any way you find useful, provided |
| 13 | +// that you agree that the author(s) have no warranty, obligations or liability. You |
| 14 | +// must determine the suitability of this source code for your use. |
| 15 | + |
| 16 | +#include <math.h> |
| 17 | +#include "MoonPhase.h" |
| 18 | + |
| 19 | +// Names of lunar phases |
| 20 | +static const char *phaseNames[] = {"New", "Evening Crescent", "First Quarter", |
| 21 | + "Waxing Gibbous", "Full", "Waning Gibbous", |
| 22 | + "Last Quarter", "Morning Crescent"}; |
| 23 | +// Names of Zodiac constellations |
| 24 | +static const char *zodiacNames[] = {"Pisces", "Aries", "Taurus", "Gemini", "Cancer", |
| 25 | + "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", |
| 26 | + "Capricorn", "Aquarius"}; |
| 27 | +// Ecliptic angles of Zodiac constellations |
| 28 | +static const float zodiacAngles[] = {33.18, 51.16, 93.44, 119.48, 135.30, 173.34, |
| 29 | + 224.17, 242.57, 271.26, 302.49, 311.72, 348.58}; |
| 30 | + |
| 31 | +// Constructor initialization. |
| 32 | +_MoonPhase::_MoonPhase() { |
| 33 | + jDate = 0; |
| 34 | + phase = 0; |
| 35 | + age = 0; |
| 36 | + fraction = 0; |
| 37 | + distance = 0; |
| 38 | + latitude = 0; |
| 39 | + longitude = 0; |
| 40 | + phaseName = zodiacName = ""; |
| 41 | +} |
| 42 | + |
| 43 | +// Determine the Moon Phase and orbital positions for the specified time. |
| 44 | +void |
| 45 | +_MoonPhase::calculate(time_t t) { |
| 46 | + jDate = _julianDate(t); |
| 47 | + |
| 48 | + // Calculate illumination (synodic) phase. |
| 49 | + // From number of days since new moon on Julian date MOON_SYNODIC_OFFSET |
| 50 | + // (1815UTC January 6, 2000), determine remainder of incomplete cycle. |
| 51 | + phase = (jDate - MOON_SYNODIC_OFFSET) / MOON_SYNODIC_PERIOD; |
| 52 | + phase -= floor(phase); |
| 53 | + |
| 54 | + // Calculate age and illumination fraction. |
| 55 | + age = phase * MOON_SYNODIC_PERIOD; |
| 56 | + fraction = (1.0 - cos(2 * M_PI * phase)) * 0.5; |
| 57 | + phaseName = phaseNames[(int)(phase * 8 + 0.5) % 8]; |
| 58 | + |
| 59 | + // Calculate distance from anomalistic phase. |
| 60 | + double distancePhase = (jDate - MOON_DISTANCE_OFFSET) / MOON_DISTANCE_PERIOD; |
| 61 | + distancePhase -= floor(distancePhase); |
| 62 | + distance = 60.4 - 3.3 * cos(2 * M_PI * distancePhase) |
| 63 | + - 0.6 * cos(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase) |
| 64 | + - 0.5 * cos(2 * 2 * M_PI * phase); |
| 65 | + |
| 66 | + // Calculate ecliptic latitude from nodal (draconic) phase. |
| 67 | + double latPhase = (jDate - MOON_LATITUDE_OFFSET) / MOON_LATITUDE_PERIOD; |
| 68 | + latPhase -= floor(latPhase); |
| 69 | + latitude = 5.1 * sin(2 * M_PI * latPhase); |
| 70 | + |
| 71 | + // Calculate ecliptic longitude from sidereal motion. |
| 72 | + double longPhase = (jDate - MOON_LONGITUDE_OFFSET) / MOON_LONGITUDE_PERIOD; |
| 73 | + longPhase -= floor(longPhase); |
| 74 | + longitude = 360 * longPhase |
| 75 | + + 6.3 * sin(2 * M_PI * distancePhase) |
| 76 | + + 1.3 * sin(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase) |
| 77 | + + 0.7 * sin(2 * 2 * M_PI * phase); |
| 78 | + if (longitude > 360) |
| 79 | + longitude -= 360; |
| 80 | + |
| 81 | + // Select the Zodiac name. |
| 82 | + zodiacName = zodiacNames[0]; |
| 83 | + for (int i = 0; i < sizeof(zodiacAngles) / sizeof(float); i++) { |
| 84 | + if (longitude < zodiacAngles[i]) { |
| 85 | + zodiacName = zodiacNames[i]; |
| 86 | + break; |
| 87 | + } |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +// Determine Julian date from Unix time. |
| 92 | +// Provides marginally accurate results with older Arduino 4-byte double. |
| 93 | +double |
| 94 | +_MoonPhase::_julianDate(time_t t) { |
| 95 | + return (t / 86400.0L + 2440587.5); |
| 96 | +} |
0 commit comments