Let's discuss how we can use just a real time clock (RTC) like the DS1307 modules which are available all over the internet to calculate and display local Sidereal Time.
I had real trouble calculating sidereal time on paper and by using excel and other methods and I spent a great deal of time trying to get the arduino to calculate it and failed miserably. I managed to get close by reverse engineering a javascript applet which applied the formula below:
Current Julian Day (JN) = floor(365.25*(y+4716)) + floor(30.6001*(m+1)) + d - 13 -1524.5 + UTC/24.0;
Where floor is a mathematical function which essentially means use the largest integer...
y = year
m = month
d = day
ut = universal co-ordinated time or UTC
The Javascript function I forked for the arduino is below:
function JulDay (d, m, y, u){ if (y<1900) y=y+1900 if (m<=2) {m=m+12; y=y-1} A = Math.floor(y/100); JD = Math.floor(365.25*(y+4716)) + Math.floor(30.6001*(m+1)) + d - 13 -1524.5 + u/24.0; return JD
}
Essentially what it does is:
Given the current date made up of YYYY/MM/DD and the current time in UTC calculate the current Julian Day Number with respect to the current time.
So the arduino function needs to perform as follows:
Get the current date and time.
Process the year - if the year is less than 1900 then add 1900 to the value for year
Process the month and year - if the month is January or February add 12 months to the value for month and subtract one off the value for year.
Calculate A - Divide the value for year by 100 and use the largest integer value found as the result.
Calculate the Julian Date using all of the above values found and print the result.
I then connected a tiny RTC real time clock module to the I2C pins on the arduino R3.
Here are the circuit connections for those that are interested.
RTC Arduino Uno R3
SCL ------> Pin A4
SDA ------> Pin A5
VCC ------> Pin 5V
GND ------> Pin 0V
RTC Module connected to Arduino Clone |
I then set the date and time on the RTC module using the time.H example included in the arduino example files and used the processing sketch to set the DS1307 using the serial connection and my PC's time.
I then wrote some arduino 'C' code which matches the functionality of the javascript function.
That wasn't too hard to implement:
void calcJulian()
{
int d1 = day();
int m1 = month();
int y1 = year();
int Hr1 = hour();
int Mn1 = minute();
int Sc1 = second();
float A1;
double JDN4;
if ( y1 <= 1900 )
{
y1 = y1 + 1900;
}
if (m1 <= 2)
{
m1 = m1 + 12;
y1 = y1 - 1;
}
A1 = floor(y1 / 100);
JDN4 = floor( 365.25* ( y1 + 4716 )) + floor( 30.6001 * ( m1 + 1 )) + d1 - 13 - 1524.5;
Serial.print("Julian Day Number: ");
Serial.print(JDN4,2);
Serial.println();
}
The only issue is that for some reason whenever I added the code required to include the current time parameter the results were incorrect.
I also tried several other methods which I also found were incorrect.
The extra code required to calculate the current JD number and not the JD number for the current date at 00:00:00 is:
Hr1 = day() / 24;
Mn1 = minute / 60;
Sc1 = second / 3600;
UT = Hr1 + Mn1 + Sc1;
JD = JDN4 + UT;
Calculating Sidereal Time
But in the spirit of not giving in to mere trifles of poor programming I looked about the internet to see if anyone else had attempted to calculate sidereal time. There were lots of people who have tried this and some have managed it! Most used a look up table for the Julian Year to achieve the result required. One stood out...
The best implementation...in my opinion is here:
The function of interest is here:
// ********************************************************************************** //
// GREENWICH & LOCAL SIDEREAL TIME CALCULATIONS
// ********************************************************************************** //
// based on "ASTR 310 - Observational Astronomy: Formula for Greenwich Sidereal Time (GST)"
// see http://www.astro.umd.edu/~jph/GST_eqn.pdf formulas
void doSiderealCalc() {
// UTC calculation
DateTime now = RTC.now(); // current time
DateTime utcTime (now.unixtime() - TZ*3600); // adjust to GMT
utc = (float)utcTime.hour() + (float)utcTime.minute()/60.0 + (float)utcTime.second()/3600.0; // decimal form
// calculate G (based on extrapolation)
int g = (utcTime.year() - 2000);
int leap = int((g+1.0)/4.0); // number of leap years since 2000
int nleap = g-leap; // number of non-leap years since 2000
double G = g2000 + (float)leap*lc + (float)nleap*nc; // number of days
// calculate nd
int nd = doNumDays(utcTime.year(), utcTime.month(), utcTime.day());
// calculate GST and Local Sidereal Time (LST)
GST = G + (dc*nd) + (tc*utc) + fudge; // Grenwich Sidereal Time
LST = GST + 24.0 + (float)(LONGITUDE/360*siderealday); // adjust for longitude (longitude portion of siderail day
while(LST>24.0) { LST -= 24.0; } // adjust to bring into 0-24 hours
dh = int( LST ); // translate into hours, ...
dm = int( (LST - (float)dh)*60.0 ); //... mins and ...
ds = int( (LST - (float)dh - (float)dm/60.0)*3600.0 ); //... seconds
}
// number of days of month (m) and date (d) since beginning of year (y)
int doNumDays(int y, int m, int d) {
int v=0;
byte leapyear = ((y-2000)%4 == 0)? 1 : 0;
switch(m) {
case 12: v += 30; // Dec
case 11: v += 31; // Nov
case 10: v += 30; // Oct
case 9: v += 31; // Sep
case 8: v += 31; // Aug
case 7: v += 30; // Jul
case 6: v += 31; // Jun
case 5: v += 30; // May
case 4: v += 31; // Apr
case 3: v += 28 + leapyear; // May (if year is leapyear, add extra day after February)
case 2: v += 31; break; // Feb
}
return v+d; // days from Jan 1 of given year
}
I may also implement the function correctly from here:
http://www.astro.umd.edu/~jph/GST_eqn.pdf
Helpfully the author has shared the entire code (arduino sketch) on their blog - Nice bloke! I have also shared my version of it here - I have updated the code to remove the LCD display section and updated the daylight savings function. The latitude and longitude are hard coded for Manchester, UK. These values will have to be changed to calculate sidereal time for your location and the whole thing relies on the real time clock being set to the accurate local time.
Sidereal Code - Working
I'm actually over the moon (heh great pun!) that someone managed this as I was beginning, after hours of trying and several attempts, to wonder if the lack of floating point precision with the arduino was going to be a factor....Thankfully it was not.
The next post will discuss using a GPS module to receive the current UTC time, update the RTC module and then calculate local sidereal time using the latitude and longitude and then display it on a 20x4 Display.
Helpfully the author has shared the entire code (arduino sketch) on their blog - Nice bloke! I have also shared my version of it here - I have updated the code to remove the LCD display section and updated the daylight savings function. The latitude and longitude are hard coded for Manchester, UK. These values will have to be changed to calculate sidereal time for your location and the whole thing relies on the real time clock being set to the accurate local time.
Sidereal Code - Working
If it is to be compiled then a copy of the RTClib.h library will be required from here:
I'm actually over the moon (heh great pun!) that someone managed this as I was beginning, after hours of trying and several attempts, to wonder if the lack of floating point precision with the arduino was going to be a factor....Thankfully it was not.
The next post will discuss using a GPS module to receive the current UTC time, update the RTC module and then calculate local sidereal time using the latitude and longitude and then display it on a 20x4 Display.
Take care - Langster!
No comments:
Post a Comment