From 166316e0c5216baf66006d11561f1c012ccaf834 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 30 Sep 2023 23:34:02 +0200 Subject: [PATCH 1/2] fix for #3400 replace low_accuracy math functions (sint_t, cos_t, atan_t, ...) with standard libm functions that have higher accuracy. --- wled00/ntp.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 1d867846..471e5f07 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -412,8 +412,8 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse //1. first calculate the day of the year float N1 = 275 * month / 9; float N2 = (month + 9) / 12; - float N3 = (1 + floor_t((year - 4 * floor_t(year / 4) + 2) / 3)); - float N = N1 - (N2 * N3) + day - 30; + float N3 = (1.0f + floorf((year - 4 * floorf(year / 4) + 2.0f) / 3.0f)); + float N = N1 - (N2 * N3) + day - 30.0f; //2. convert the longitude to hour value and calculate an approximate time float lngHour = lon / 15.0f; @@ -423,37 +423,37 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse float M = (0.9856f * t) - 3.289f; //4. calculate the Sun's true longitude - float L = fmod_t(M + (1.916f * sin_t(DEG_TO_RAD*M)) + (0.02f * sin_t(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); + float L = fmodf(M + (1.916f * sinf(DEG_TO_RAD*M)) + (0.02f * sinf(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); //5a. calculate the Sun's right ascension - float RA = fmod_t(RAD_TO_DEG*atan_t(0.91764f * tan_t(DEG_TO_RAD*L)), 360.0f); + float RA = fmodf(RAD_TO_DEG*atan(0.91764f * tan(DEG_TO_RAD*L)), 360.0f); //5b. right ascension value needs to be in the same quadrant as L - float Lquadrant = floor_t( L/90) * 90; - float RAquadrant = floor_t(RA/90) * 90; + float Lquadrant = floorf( L/90) * 90; + float RAquadrant = floorf(RA/90) * 90; RA = RA + (Lquadrant - RAquadrant); //5c. right ascension value needs to be converted into hours RA /= 15.0f; //6. calculate the Sun's declination - float sinDec = 0.39782f * sin_t(DEG_TO_RAD*L); - float cosDec = cos_t(asin_t(sinDec)); + float sinDec = 0.39782f * sinf(DEG_TO_RAD*L); + float cosDec = cosf(asinf(sinDec)); //7a. calculate the Sun's local hour angle - float cosH = (sin_t(DEG_TO_RAD*ZENITH) - (sinDec * sin_t(DEG_TO_RAD*lat))) / (cosDec * cos_t(DEG_TO_RAD*lat)); - if (cosH > 1 && !sunset) return 0; // the sun never rises on this location (on the specified date) - if (cosH < -1 && sunset) return 0; // the sun never sets on this location (on the specified date) + float cosH = (sinf(DEG_TO_RAD*ZENITH) - (sinDec * sinf(DEG_TO_RAD*lat))) / (cosDec * cosf(DEG_TO_RAD*lat)); + if ((cosH > 1.0f) && !sunset) return 0; // the sun never rises on this location (on the specified date) + if ((cosH < -1.0f) && sunset) return 0; // the sun never sets on this location (on the specified date) //7b. finish calculating H and convert into hours - float H = sunset ? RAD_TO_DEG*acos_t(cosH) : 360 - RAD_TO_DEG*acos_t(cosH); + float H = sunset ? RAD_TO_DEG*acosf(cosH) : 360 - RAD_TO_DEG*acosf(cosH); H /= 15.0f; //8. calculate local mean time of rising/setting float T = H + RA - (0.06571f * t) - 6.622f; //9. adjust back to UTC - float UT = fmod_t(T - lngHour, 24.0f); + float UT = fmodf(T - lngHour, 24.0f); // return in minutes from midnight return UT*60; From 1c3fdb73fb46f26144691e2e397c04436d526e12 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 1 Oct 2023 19:04:30 +0200 Subject: [PATCH 2/2] optimization: only use "float" math functions - saves 5KB flash and some RAM -allow to build with -D WLED_USE_UNREAL_MATH, to restore old behaviour and save another 6KB flash --- platformio.ini | 2 ++ wled00/ntp.cpp | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9fbcb0a4..f3caa585 100644 --- a/platformio.ini +++ b/platformio.ini @@ -352,6 +352,7 @@ platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA + ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} [env:esp07] @@ -605,6 +606,7 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= -DARDUINO_USB_DFU_ON_BOOT=0 -DLOLIN_WIFI_FIX ; seems to work much better with this -D WLED_USE_PSRAM + ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 6792 bytes FLASH -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 -D LEDPIN=16 diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 471e5f07..c9c4874b 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -2,6 +2,21 @@ #include "wled.h" #include "fcn_declare.h" +// on esp8266, building with `-D WLED_USE_UNREAL_MATH` saves around 7Kb flash and 1KB RAM +// warning: causes errors in sunset calculations, see #3400 +#if defined(WLED_USE_UNREAL_MATH) +#define sinf sin_t +#define asinf asin_t +#define cosf cos_t +#define acosf acos_t +#define tanf tan_t +#define atanf atan_t +#define fmodf fmod_t +#define floorf floor_t +#else +#include +#endif + /* * Acquires time from NTP server */ @@ -426,7 +441,7 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse float L = fmodf(M + (1.916f * sinf(DEG_TO_RAD*M)) + (0.02f * sinf(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); //5a. calculate the Sun's right ascension - float RA = fmodf(RAD_TO_DEG*atan(0.91764f * tan(DEG_TO_RAD*L)), 360.0f); + float RA = fmodf(RAD_TO_DEG*atanf(0.91764f * tanf(DEG_TO_RAD*L)), 360.0f); //5b. right ascension value needs to be in the same quadrant as L float Lquadrant = floorf( L/90) * 90;