Function updates variables haphazardly

I am using a solar position algorithm which I have downloaded from a reputable academic website. I have coupled this to a DS1307RTC to provide me with the current time (using a library for the specific RTC).

I calculate the co-ordinates of the sun each minute from the algorithm from an input from the RTC. I subtract the previous co-ordinate from the new one to determine the change in position.

However, this change in position is often just zero (to 6 decimal points) and I cannot understand why. The change in position alternates between 0 and the correct difference in position. And every now and then I get 0 a few times in a row.

I have reference values and I know that the difference is never 0. I’m not sure if I maybe need to add delays to make sure everything is executed correctly? My code is below:

tm.Minute and tm.Second are outputs from the RTC library function.

 if (tm.Minute == min_counter && tm.Second == 0)
  {
    Serial.print("UT: ");
    Serial.println(UT, 6);

    Serial.print("Zenith: "); 
    Calc_Zen =  Calculate_Zenith();
    Serial.println(Calc_Zen, 6);

    Serial.print("Azimuth: ");
    Calc_Az =  Calculate_Azimuth();
    Serial.println(Calc_Az, 6);
    
    

    Serial.print("Old Azimuth: ");
    Serial.println(Calc_Az_Old, 6);

    Serial.print("----> Az dif: ");
    Az_dif = (Calc_Az - Calc_Az_Old);
    Serial.println(Az_dif, 6);
    Serial.println("-------------------");
    min_counter += 1;
    if (min_counter > 59)
    {
      min_counter = 0;
    }

  }
Calc_Az_Old = Calc_Az;

Thank you for any help!

Without knowing the types of the variables - likely where your problem lies - we cannot help you. Post all your code.

The fact that we see code like:

Serial.println(Calc_Zen, 6);

suggests that you are trying to print Calc_Zen with 6 decimal places, which only make sense with a float data type. Keep in mind that a float only has 6 or 7 digits of precision. Anything after that is just a guess on the part of the compiler. Could that be part of your problem?

with out the full code its impossible to say whats going on.

you could try multiplying the number by 10000 then doing the calculation then dividing by the same number to see if a number is being rounded off somewhere in the code.

Sorry i thought it would be too long. Anyway, here it is:

/
//-----------------------------------------------------------------
// Libraries to include
//-----------------------------------------------------------------
#include <DS1307RTC.h>
#include <Wire.h>
#include <Time.h>
#include "math.h"
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Solar tracking definitions
//-----------------------------------------------------------------
//input data:
double UT;
int Day;
int Month;
int Year;
double Dt;
double Longitude = 0.21787; //in radians
double Latitude = 0.73117; //in radians
double Pressure = 1.0;  //in atmospheres
double Temperature = 20;  //in deg C

//output data
double RightAscension;
double Declination;
double HourAngle;
double Zenith;
double Azimuth;

//auxiliary
double t, te, wte, s1, c1, s2, c2, s3, c3, s4, c4,
       sp, cp, sd, cd, sH, cH, se0, ep, De, lambda, epsi,
       sl, cl, se, ce, L, nu, Dlam;
double yt, mt;

//defined by me
double a = 0, Calc_Zen, Calc_Az, Calc_Az_Old, Old_Az, Az_dif, Hall_A_Count = 0;
double min_counter = 10; // The minute value the Azimuth calcualtion will look for from the RTC
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Arduino pin definitions
//-----------------------------------------------------------------
//digital in
const int Hall_A = 3;
const int PWM = 4;
const int DIR = 5;


//-----------------------------------------------------------------
// Default Arduino setup function - runs once
//-----------------------------------------------------------------
void setup() {

  Serial.begin(9600);
  while (!Serial) ; // wait for serial
  delay(200);
  Serial.println("DS1307RTC Read Test");
  Serial.println("-------------------");

  Calc_Az_Old = 0;

  pinMode(Hall_A, INPUT);
  pinMode(PWM, OUTPUT);
  pinMode(DIR, OUTPUT);


  digitalWrite(DIR, LOW);

}
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Default Arduino loop function - runs continuously
//-----------------------------------------------------------------
void loop() {

  //-----------------------------------------------------------------
  //Time Keeping function
  //-----------------------------------------------------------------

  tmElements_t tm;

  if (RTC.read(tm))
  {
    Serial.print("Ok, Time = ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);

    UT = (tm.Hour + ((double)1 / (double)3600) * (tm.Minute * 60 + tm.Second));
    Serial.print(" , UT: ");
    Serial.print(UT, 5);

    Serial.print(" , Date (D/M/Y) = ");
    Serial.print(tm.Day);
    Day = tm.Day;
    Serial.write('/');
    Serial.print(tm.Month);
    Month = tm.Month;
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
    Year = tmYearToCalendar(tm.Year);

    Dt = (96.4 + 0.567 * (Year - 2061));

  }
  else
  {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
  //-----------------------------------------------------------------

  //-----------------------------------------------------------------
  //Check to see if a new Azimuth position needs to be calculated
  //-----------------------------------------------------------------

  if (tm.Minute == min_counter && tm.Second >= 0 && tm.Second < 1)
  {
    Serial.print("UT: ");
    Serial.println(UT, 6);

    Serial.print("Zenith: ");  
    Calc_Zen =  Calculate_Zenith();
    Serial.println(Calc_Zen, 6);

    Serial.print("Azimuth: ");
    Calc_Az =  Calculate_Azimuth();
    Serial.println(Calc_Az, 6);    
    

    Serial.print("Old Azimuth: ");
    Serial.println(Calc_Az_Old, 6);

    Serial.print("----> Az dif: ");
    Az_dif = (Calc_Az - Calc_Az_Old);
    Serial.println(Az_dif, 6);
    Serial.println("-------------------");

//    int Hall_A_state = digitalRead(Hall_A);
//    digitalWrite(PWM, HIGH);
//
//    while (a < 20) {
//      int Hall_A_state = digitalRead(Hall_A);
//      if (Hall_A_state == LOW) {
//
//        a += 1;
//        Serial.print("a = ");
//        Serial.println(a, 1);
//
//      }
//
//      if ( a == 20) {
//        digitalWrite(PWM, LOW);
//        break;
//      }
//    }
//
//    a = 0;

    min_counter += 1;
    if (min_counter > 59)
    {
      min_counter = 0;
    }

  }
  //-----------------------------------------------------------------

  Calc_Az_Old = Calc_Az;
  

}
//-----------------------------------------------------------------

//-----------------------------------------------------------------
double Calculate_Azimuth()
//-----------------------------------------------------------------
{

  if (Month <= 2) {
    mt = Month + 12;
    yt = Year - 1;
  } else {
    mt = Month;
    yt = Year;
  }

  t = double(int(365.25 * double(yt - 2000)) + int(30.6001 * double(mt + 1)) - int(0.01 * double(yt)) + Day) + 0.0416667 * UT - 21958.0;
  te = t + 1.1574e-5 * Dt;

  wte = 0.0172019715 * te;

  s1 = sin(wte);
  c1 = cos(wte);
  s2 = 2.0 * s1 * c1;
  c2 = (c1 + s1) * (c1 - s1);
  s3 = s2 * c1 + c2 * s1;
  c3 = c2 * c1 - s2 * s1;

  L = 1.7527901 + 1.7202792159e-2 * te + 3.33024e-2 * s1 - 2.0582e-3 * c1 + 3.512e-4 * s2 - 4.07e-5 * c2 + 5.2e-6 * s3 - 9e-7 * c3 - 8.23e-5 * s1 * sin(2.92e-5 * te) + 1.27e-5 * sin(1.49e-3 * te - 2.337) + 1.21e-5 * sin(4.31e-3 * te + 3.065) + 2.33e-5 * sin(1.076e-2 * te - 1.533) + 3.49e-5 * sin(1.575e-2 * te - 2.358) + 2.67e-5 * sin(2.152e-2 * te + 0.074) + 1.28e-5 * sin(3.152e-2 * te + 1.547) + 3.14e-5 * sin(2.1277e-1 * te - 0.488);

  nu = 9.282e-4 * te - 0.8;
  Dlam = 8.34e-5 * sin(nu);
  lambda = L + PI + Dlam;

  epsi = 4.089567e-1 - 6.19e-9 * te + 4.46e-5 * cos(nu);

  sl = sin(lambda);
  cl = cos(lambda);
  se = sin(epsi);
  ce = sqrt(1 - se * se);

  RightAscension = atan2(sl * ce, cl);
  if (RightAscension < 0.0)
    RightAscension += PI * 2;

  Declination = asin(sl * se);

  HourAngle = 1.7528311 + 6.300388099 * t + Longitude - RightAscension + 0.92 * Dlam;
  HourAngle = fmod(HourAngle + PI, PI * 2) - PI;
  if (HourAngle < -PI) HourAngle += PI * 2;



  sp = sin(Latitude);
  cp = sqrt((1 - sp * sp));
  sd = sin(Declination);
  cd = sqrt(1 - sd * sd);
  sH = sin(HourAngle);
  cH = cos(HourAngle);
  se0 = sp * sd + cp * cd * cH;
  ep = asin(se0) - 4.26e-5 * sqrt(1.0 - se0 * se0);
  Azimuth = atan2(sH, cH * sp - sd * cp / cd);

  if (ep > 0.0)
    De = (0.08422 * Pressure) / ((273.0 + Temperature) * tan(ep + 0.003138 / (ep + 0.08919)));
  else
    De = 0.0;

  Zenith = PI * 0.5 - ep - De;

  return (Azimuth * (180 / PI) + 180);

}
//-----------------------------------------------------------------

//-----------------------------------------------------------------
void print2digits(int number)
//-----------------------------------------------------------------
{
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}
//-----------------------------------------------------------------

I took out the calculate Zenith function as I did not have enough space to post. It is identical to the calculate Azimuth function, just with a different return variable (stupid way to do it I know, but easier in my case).

The commented section on the Hall sensor is also providing me with issues, but it is something else so I won’t ask it here.

@Econjack I have defined those variables as doubles which i saw somewhere is the same precision as float for Arduino? I did a quick test now with those variables defined as float (a,Calc_Zen, Calc_Az, Calc_Az_Old, Old_Az, Az_dif, Hall_A_Count) and I still get the same issue.

My RTC is about 6 second off with my PC time, I’m not sure if that is potentially and issue?

Thank you!

My RTC is about 6 second off with my PC time, I'm not sure if that is potentially and issue?

How could it be? The Arduino has no way of knowing if the clock is accurate.

I don't like the delay(1000); call in there. You could miss a time when second should be 0. Keep track of the previous second value. Calculate values only when the value for second is now 0 but was not 0 before.

You can use Serial.print() to print out intermediate values, to see where the problem occurs.

PaulS:
How could it be? The Arduino has no way of knowing if the clock is accurate.

There was no other obvious reason to me why the code wasn't behaving as I expected it to.

PaulS:
I don't like the delay(1000); call in there. You could miss a time when second should be 0. Keep track of the previous second value. Calculate values only when the value for second is now 0 but was not 0 before.

I have tried without the delay as well as checking for only a second value. I also copy-pasted the function to calculate Azimuth and edited every variable name to spit out an Azimuth old value (ie from one minute prior to the current time) and I still get the same problem.

I have also checked that the code is entering each function.

is it wise to mix doubles and ints in the same maths line

this line

  t = double(int(365.25 * double(yt - 2000)) + int(30.6001 * double(mt + 1)) - int(0.01 * double(yt)) + Day) + 0.0416667 * UT - 21958.0;

if you add a print after this line then copy the line using all doubles and print after the line are the prints the same?

Computer maths are a pain as they follow different rules but the order should not change once its running (answer may be wrong but it should always be wrong.)
This sounds like something is being rounded off during a calculation, Once the rounding error goes the other way then it makes a jump in the readings

I would be more interested in the result after the zero readings when serial printing. That should show if something was skipped or if there was a correction

e.g

0.001234
0.001234
0.000000......maybe a missed reading
0.001234

or

0.001234
0.001234
0.000000.... maybe a rounding error
0.002345...correction to the error
0.001234

  t = double(int(365.25 * double(yt - 2000)) + int(30.6001 * double(mt + 1)) - int(0.01 * double(yt)) + Day) + 0.0416667 * UT - 21958.0;

After I've finally had some sleep I also figured that this is where the problem might be. This function was copied directly from a C++ function written by the algorithms developer so I didn't want to alter it myself.

The reason for the int's is to round down the value down toward zero. Maybe this is not the correct way to do it in Arduino?

I am going to check a different way of doing it now.

I tried using this definition as opposed to the previous one (t is already defined as a double):

  int Yr_var, M_var, D_var;
  double yt_var, mt_var, Day_var;

  yt_var = (yt - 2000);
  Yr_var = (365.25 * yt_var);

  mt_var = (mt + 1);
  M_var = (30.6001 * mt_var);

  Day_var = (yt + Day);
  D_var = 0.01 * Day_var;

  t = Yr_var + M_var - D_var + 0.0416667 * UT - 21958.0;

The error hasn't changed...

Never omit portions of your code to keep it from being "too long".

Post your entire sketch. The whole thing. If it is too long to fit in the body of a post, then post it as an attachment.