Cmath in library error

Hello, I want an Arduino Nano Every to calculate the sunrise and -set for a given time, and I found a nice library that does that: GitHub - buelowp/sunset: Calculate Sunrise and Sunset and the phase of the moon accurately based on date and geographic position
Now my problem is that I get an error when compiling:

<In file included from C:\Users...\Documents\Arduino\ProjectMMM - RGB leds\ProjectMMM - RGB leds.ino:15:0:
C:\Users...\Documents\Arduino\libraries\sunset-1.1.7\src/sunset.h:29:10: fatal error: cmath: No such file or directory
#include
^~~~~~~
compilation terminated.

exit status 1

Compilation error: exit status 1>

I guess that the library uses the library cmath, but it isn't imported on the Arduino. I haven't found yet how to resolve this, I hope someone can help.

Please post the code, using code tags.

This code, by a forum member, works well:

// Arduino library version of sunrise/sunset calculations by 'jurs' based on:
// A simple C++ program calculating the sunrise and sunset for
// the current date and a set location (latitude,longitude)
// e-mail: jjlammi@yahoo.com
// C++ program calculating the sunrise and sunset for
// the current date and a constant location(latitude,longitude)
// Jarmo Lammi 1999 - 2004
// Last update
// Jan 3rd, 2004 - change to compile with gcc-3.3.2 by Stephan Wynhoff
// http://wynhoff.home.cern.ch/wynhoff/weather/gex.html
// It compiles well also with old gcc version 2.95.4 20011002 (Debian prerelease)
// Try compiling in Linux with command g++ -o rscalc rscalc.cc
// Also the time formats are tidy now.

#define SUNDIAMETER 0.53  // Sun diameter in degrees
#define AIRREFRACTION (34.0/60.0) // athmospheric refraction in degrees

void setup() {
Serial.begin(9600);
while(!Serial);
double myLat = 40.0;  //south latitude negative
double myLon = -100.0; //west longitude negative
int TZ = -7 ; //west negative
int sunrise,sunset,dawn,dusk;
sunCalc(2021, 1, 31, TZ, myLat, myLon, &sunrise, &sunset, &dawn, &dusk);
char buf[30];
snprintf(buf,sizeof(buf),"Sunrise %02d:%02d, Sunset %02d:%02d",sunrise/60,sunrise%60,sunset/60,sunset%60);
Serial.println(buf);
}

double FNday (int y, int m, int d, float h) 
{
  //   Get the days to J2000
  //   h is UT in decimal hours
  //   FNday only works between 1901 to 2099 - see Meeus chapter 7
  long int count = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
  // type casting necessary on PC DOS and TClite to avoid overflow
  count+= (long int)y*367;
  return (double)count - 730531.5 + h/24.0;
}

double FNrange (double x) 
{
  //  the function returns an angle in the range 0 to 2*PI
  double b = x / TWO_PI;
  double a = TWO_PI * (b - (long)(b));
  if (a < 0) a = TWO_PI + a;
  return a;
}

double f0(double lat, double declin) 
{
  // Calculating the hourangle
  double fo,dfo;
  // Correction: different sign at S HS
  dfo = DEG_TO_RAD*(0.5*SUNDIAMETER + AIRREFRACTION); if (lat < 0.0) dfo = -dfo;
  fo = tan(declin + dfo) * tan(lat*DEG_TO_RAD);
  if (fo>0.99999) fo=1.0; // to avoid overflow //
  fo = asin(fo) + PI/2.0;
  return fo;
}

double f1(double lat, double declin) 
{
  // Calculating the hourangle for twilight times
  double fi,df1;
  // Correction: different sign at S HS
  df1 = DEG_TO_RAD * 6.0; if (lat < 0.0) df1 = -df1;
  fi = tan(declin + df1) * tan(lat*DEG_TO_RAD);
  if (fi>0.99999) fi=1.0; // to avoid overflow //
  fi = asin(fi) + PI/2.0;
  return fi;
}

double FNsun (double d, double &L) 
{
  //   Find the ecliptic longitude of the Sun
  double g;
  //   mean longitude of the Sun
  L = FNrange(280.461 * DEG_TO_RAD + .9856474 * DEG_TO_RAD * d);

  //   mean anomaly of the Sun
  g = FNrange(357.528 * DEG_TO_RAD + .9856003 * DEG_TO_RAD * d);

  //   Ecliptic longitude of the Sun
  return FNrange(L + 1.915 * DEG_TO_RAD * sin(g) + .02 * DEG_TO_RAD * sin(2 * g));
};


void sunCalc(int year, int month, int day, int timezone, double latitude, double longitude, int *sunrise, int *sunset, int *dawn, int *dusk)
// calculates times of morning dawn, sunrise, sunset, evening dusk
{
  double L, daylen;
  double h = 12; // assume sun position at high noon
  double d = FNday(year, month, day, h);

  //   Use FNsun to find the ecliptic longitude of the Sun
  double lambda = FNsun(d, L);

  //   Obliquity of the ecliptic
  double obliq = 23.439 * DEG_TO_RAD - .0000004 * DEG_TO_RAD * d;

  //   Find the RA and DEC of the Sun
  double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
  double delta = asin(sin(obliq) * sin(lambda));

  // Find the Equation of Time
  // in minutes
  // Correction suggested by David Smith
  double LL = L - alpha;
  if (L < PI) LL += TWO_PI;
  double equation = 1440.0 * (1.0 - LL / TWO_PI);
  double ha = f0(latitude,delta);
  double hb = f1(latitude,delta);
  double twx = hb - ha; // length of twilight in radians
  twx = 12.0*twx/PI;    // length of twilight in hours
  // Conversion of angle to hours and minutes //
  daylen = RAD_TO_DEG*ha/7.5;
  if (daylen<0.0001) {daylen = 0.0;}
  // arctic winter //

  double riset = 12.0 - 12.0 * ha/PI + timezone - longitude/15.0 + equation/60.0;
  double settm = 12.0 + 12.0 * ha/PI + timezone - longitude/15.0 + equation/60.0;
 // double noont = riset + 12.0 * ha/PI;
  double altmax = 90.0 + delta * RAD_TO_DEG - latitude; 
  // Correction for S HS suggested by David Smith
  // to express altitude as degrees from the N horizon
  if (latitude < delta * RAD_TO_DEG) altmax = 180.0 - altmax;

  if (riset > 24.0) riset-= 24.0;
  if (settm > 24.0) settm-= 24.0;
  
  double twam = riset - twx;      // morning twilight begin
  double twpm = settm + twx;      // evening twilight end

  *sunrise=round(riset*60); //minutes past midnight
  *sunset=round(settm*60);
  *dawn=round(twam*60);
  *dusk=round(twpm*60);
}

Use a decent library:
https://github.com/MarScaper/ephemeris

Oh, thought the <> did it, and I didn't realise it hadn't put the error in a code block, my bad!

In file included from C:\Users...\Documents\Arduino\ProjectMMM - RGB leds\ProjectMMM - RGB leds.ino:15:0:
C:\Users...\Documents\Arduino\libraries\sunset-1.1.7\src/sunset.h:29:10: fatal error: cmath: No such file or directory
#include
^~~~~~~
compilation terminated.

exit status 1

Compilation error: exit status 1

As mentioned in the library's readme, it only supports 32-bit boards, and requires C++14. It won't work on an 8-bit AVR.

1 Like

The library you mentioned is complete overkill for what I'm trying to achieve, and will not work on the Nano Every:

Due to VSOP87 and ELP2000 implementation, code needs too much flash memory for classic Arduinos (Uno, etc).

Ok, I'll try that. Is there a way I can use that code without dumping it in my (already not organised) code file?

Have you tried the Wokwi simulator?

I did actually, but I quickly stopped as I needed transistors in my circuit and decided to than just not use that simulator, as transistors are not supported. What would you recommond using it for?

What do you need the sunrise/set times for?

It's for a school project. We need to do something with LEDs, and decided we'll make a suntracker. Therefor I want to know the sunrise/-set time, and then just divide that time between the amount of LEDs, and during sunrise/-set do some fancy colours.

That's not really related to my question though, so I didn't include that in the original post.

Why not just use the Solar Position library? It does that tracking for you.
https://github.com/KenWillmott/SolarPosition
Yes, I wrote it.

In AVR, the transcendental function library is math.h:
https://www.nongnu.org/avr-libc/user-manual/group__avr__math.html

I already took a look at it, and it's a neat library, but doesn't have the sunset and sunrise times in it, meaning I need to do more coding to make it work. And eh, C++ is not my strongest language, so I don't look forward to modifying someone elses code I only halfly understand to make it do what I need.

Wow, a library that actually expects that you will do some coding. Who has any use for that?

Okay. Just kidding. But

  1. You don't have to modify the library at all
  2. It's easy to determine sunrise/set. It's just when the elevation is around zero degrees.

However, backing up a bit, you said you only needed rise/set times to calculate daylight percentage. But you don't need that if you already know where the sun is.

I understand the impulse. But you could… code carefully, separating functionality enough so that the need for transistors is a wholly owned enterprise and can be stubbed in, simulated as it were or not in the simulation.

You could get entire blocks of hair pulling development working without touching any hardware.

Besides, it is a good idea to sorta do that anyway.

You may see quite a bit of not doing that, long-ish programs with no organization, no possibility of getting pieces working, however, then combing them with only minor issues left.

I once did most of the work with C using regular Hello World programs on the big rig.

Then I shifted to one or the other of the excellent online C/C++ compilers.

Then some time ago now shifted again to doing a huge amount of the hard work in the wokwi.

Which is quite faithful, and although no transistors, does have a crap-ton of sim hardware that can often cover those needs as well.

a7

I know I sound lazy there, but jremington already posted a code that calculated the time there.
Your solution of determining when the elevation is zero could work, but won't that bring in a big loop of going over the same code a lot of times to get an accurate number? I'd like to get a precision of around 3 minutes, so that would be 20 iterations per hour, and you need to go on, at least in summer, till 10PM before finding sunset. That's iterating 200x over the same code, which seems inefficient.
Maybe my morning brain will be able to modify some equations to get the nullpoints from the function though.

About your third thought, that is kinda true, but you still need to project your sun down to the flat line of LEDs we have. That means dividing your day into 7 (our amount of LEDs) equal parts. That comes down to basically calculating sunrise and sunset, and dividing the time in between in 7.

I understand, but those transistors will be the most important part of the hardware-side of things. The Arduino only has room for 2 RGB LEDs, and we'll do 7 with the help of transistors. Not being able to simulate those is in my eyes a big constraint, because all the other things that happen will be just software, and can be confirmed in an IDE.

You don't need transistors to control LEDs in a simulator, because you can't burn out simulated port pins.

OK, but have you heard of so-called smart pixels, or smart LEDs or neopixels?

You can get strips, rings, matrices and individual smart LEDs.

You could hang 100 LEDs off one pin.

You could write a function that handled seven LEDs, done any way at all.

Et cetera.

a7

I appreciate the help and advice on simulating the Arduino, but we're drifting quite far appart from the original subject. I'd like to stay on the software - sunrise - side of things please :slight_smile: