picplanner/src/calculations.c

352 wiersze
15 KiB
C

#include <calculations.h>
/* TODO
* Azimuth and Elevation are wrong in the calculation of the position of the Milky Way */
/* Convert degree to radiant */
double calc_deg_rad (double deg) {
return M_PI/180*deg;
}
/* Convert radiant to degree */
double calc_rad_deg (double rad) {
return 180/M_PI*rad;
}
int times_to_zone (int day_utc, int hour_utc, int day_local, int hour_local){
int time_zone;
if (day_utc == day_local){
time_zone = hour_local - hour_utc;
}
else{
if (abs(day_utc-day_local)>1){
if (day_utc < day_local){
day_local = day_utc-1;
}
else{
day_local = day_utc+1;
}
}
time_zone = 24*(day_local-day_utc)+(hour_local-hour_utc);
}
return time_zone;
}
void utc_zone_to_time (int *time_utc, int *time_local){
int sign = *(time_utc+5)/abs(*(time_utc+5));
*time_local=*time_utc;
*(time_local+1)=*(time_utc+1);
*(time_local+2)=*(time_utc+2);
*(time_local+3)=*(time_utc+3);
*(time_local+4)=*(time_utc+4);
*(time_local+5)=*(time_utc+5);
*(time_local+3) = *(time_utc+3)+*(time_utc+5);
if (*(time_local+3)>24 || *(time_local+3) < 0){ /* Test if hours are still inside the same day */
*(time_local+3) = (*(time_local+3)+24)%24;
*(time_local+2) = *(time_utc+2)+sign;
if (*(time_local+2) > max_day_in_month (*(time_utc+1), *(time_utc)) || *(time_local+2) < 1){ /* Test if days are still inside the same month */
*(time_local+2) = (*(time_local+2)-1)%max_day_in_month (*(time_utc+1)+sign, *(time_utc))+1; /* -1 and +1 necessary due to mod calculations */
*(time_local+1) = *(time_utc+1)+sign;
if (*(time_local+1) > 12 || *(time_local+1) < 1){ /* Test if months are still inside the same year */
*(time_local+1) = (*(time_local+1)-1)%12+1;
*(time_local) = *(time_utc)+sign;
}
}
}
}
void time_to_utc (int *time_local, int *time_utc){
int sign = *(time_utc+5)/abs(*(time_utc+5));
*time_utc=*time_local;
*(time_utc+1)=*(time_local+1);
*(time_utc+2)=*(time_local+2);
*(time_utc+3)=*(time_local+3);
*(time_utc+4)=*(time_local+4);
*(time_local+5)=*(time_utc+5);
*(time_utc+3) = *(time_local+3)-*(time_utc+5);
if (*(time_utc+3) > 24 || *(time_utc+3) < 0){
*(time_utc+3) = (*(time_utc+3)+24)%24;
*(time_utc+2) = *(time_utc+2)+sign;
if (*(time_utc+2) > max_day_in_month (*(time_local+1), *(time_local)) || *(time_utc+2) < 1){
*(time_utc+2) = (*(time_utc+2)-1)%max_day_in_month (*(time_local+1)+sign, *(time_local))+1;
*(time_utc+1) = *(time_local+1)+sign;
if (*(time_utc+1) > 12 || *(time_utc+1) < 1){
*(time_utc+1) = (*(time_local+1)-1)%12+1;
*(time_utc) = *(time_local)+sign;
}
}
}
}
int max_day_in_month (int month, int year){
int max_days = 30;
/* check which month is set */
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
max_days = 31;
break;
case 2:
/* definition of a leap year: Every fourth year is a leap year expect if year%100 is 0 e.g. 1900
* but every year where year%400 is 0 is a leap year again e.g. 2000 */
if ((year%4==0 && year%100!=0) || year%400==0) {
max_days = 29;
}
else {
max_days = 28;
}
break;
}
return max_days;
}
/* Get current time and date and return as a pointer to an array */
void calc_time_utc (int *time_utc)
{
time_t t;
struct tm tmp_local;
struct tm *tmp;
t = time(&t);
tmp = localtime(&t);
memcpy(&tmp_local, tmp, sizeof(struct tm));
tmp = gmtime(&t);
int time_zone = times_to_zone (tmp->tm_mday, tmp->tm_hour, tmp_local.tm_mday, tmp_local.tm_hour);
g_print ("UTC: %02d:%02d - %d.%d.%d, Time zone: %d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_mday, tmp->tm_mon+1, tmp->tm_year+1900, time_zone);
*(time_utc) = tmp->tm_year+1900;
*(time_utc+1) = tmp->tm_mon+1;
*(time_utc+2) = tmp->tm_mday;
*(time_utc+3) = tmp->tm_hour;
*(time_utc+4) = tmp->tm_min;
*(time_utc+5) = time_zone;
}
/* Calculate the Julian Day */
void calc_jd (int *time_utc, double *time_jd)
{
float year = *time_utc;
float month = *(time_utc+1);
double day = *(time_utc+2);
float hour = *(time_utc+3);
float min = *(time_utc+4);
/* g_print ("Minute: %f, Hour: %f, Day: %f, Month: %f, Year: %f\n",min,hour,day,month,year); */
/* calculate a float type day number which is direct proportional to the time went by */
day += (hour + min/60.)/24.;
/*g_print("Day JD: %f\n", day);*/
if (month<=2){
year --;
month += 12;
}
*time_jd = (int)(365.25*(year+4716.)) + (int)(30.6001*(month+1.)) - (int)(year/100.) + (int)(year/400.) + day + 2. - 1524.5;
/* g_print ("Julian Day: %f, Day JD: %f, hour JD %f\n", *time_jd, day, hour); */
/*Explanation:
* There are 5 main parts in this calculation.
* 1. The first question is if our month is in January or February.
* This is necessary because if we have a leap year we should first add the extra day in March not allready in January or February.
* We than simply see January and February as the 13th or 14th month of the last year.
*
* 2. The secont main part is the expression "(int)(365.25*(year+4716))" and partly combined with the " - 1524.5".
* This mainly results from the definition of the Julian Day which is defined to be zero at the 1. January of -4712 at 12 UT
* Due to step 1 this would lead to a negativ year. To avoid this we define the 0 point 4 years earlier and substrate these 1461 days.
* To get then the right amount of days on the 1st of March 4712 at 00:00 we have to add these "lost" days which ar 59.5.
* It is 59.5 and not 58.5 because the year -4712 was also a leap year.
* The (int) definition is necessary because we only want to add a day every 4 years. The int gets rid of the .25 .50 or .75.
*
* 3. (int)(30.6001*(month+1)): This part is not as obvios as the rest of the calculation. This formular is an "estimation" function of the days passed until the given month.
* Due to step 1 we don't need to look at January and February so let's start with March. How many days have passed in March since the "beginning" of the year.
* Where the beginning is March it selfe. It is 0. How many days have passed on 1st of April? 31. The following months are
* 61, 92, 122, 153, 184, 214, 245, 275, 306 and 337 on 1. February. The first of March is then again 0.
* We can receive these values also whith the equation (int)(30.6*(month+1)-122). Due to "errors" in floating point arithmetic 30.6 can not be represented in binary
* and can lead for example in april to 152.999998 which is in (int) 152 and not 153. Therefore we do not multiply by 30.6 and use 30.6001 instead.
*
* 4. The adding of the days (+ day) should be obvious. BUT we have to calculate (+ day - 1) because if we have the 3rd of Oktober for example in principle it is
* the 2nd of Oktober + a few hous.
*
* 5. 2 - (int)(year/100) + (int)(year/400): In the gregorian calendar we have every 4 years a leap year (step 2) but every 100th year we do NOT have a leap year
* but every 400th year it is still a leap year. This is to compensate the rotation around the Sun more precise. This is calculated by "- (int)(year/100) + (int)(year/400)"
* The 2 is an offset because at JD 0 the Gregorian calendar did not exist at this time. It was defined that the 5. Oktober 1582 is the 15. Oktober 1582. If we calculate
* the JD of this date with the Julian calendar we see a offset of two days to the same JD calculated with the Gregorian calendar. This is where the 2 comes from.
* Just keep in mind that the Julian Day is not the same as the Julian Date!
*
* --> combining all of this leads to the above formula.
*/
}
/* Calculate the Sidereal time in degree (German: Sternzeit) */
void calc_sidereal_time(float longitude, double *time_jd, double *sidereal_time) {
float hours_passed;
double jd_sidereal;
/* Julian date at 0 UT at the current date */
if (*time_jd - (int)*time_jd >= 0.5){
jd_sidereal = (int)(*time_jd) + 0.5;
}
else{
jd_sidereal = (int)(*time_jd) - 0.5;
}
hours_passed = 24*(*time_jd-jd_sidereal);
/*g_print("hours_passed %f\n", hours_passed);*/
double T = (jd_sidereal - 2451545)/36525;
/* This formular calculatest the amount of 100 years since the fundamental epoche J2000 (1.1.2000)
* This formular is NOT allowed to get julian days which end on .5 (00:00), because the formular below only considers the rotation around the sun NOT its' own prcession.
* So we only want to know in which "direktion" we look every day at 00:00 in Greenwich in comparison to the "fixed" stars. */
*sidereal_time = 100.46061837 + T*(36000.770053608 + T*(0.000387933 - T/38710000.0)) + longitude + hours_passed*1.00273790935*15;
*sidereal_time = remainder(*sidereal_time, 360);
/* g_print("time_jd: %f, sidereal_time %f, hours_passed: %f\n", *time_jd, *sidereal_time, hours_passed); */
/* This formula for the sidereal time is not that easy to explain and strongly based on numerical calculations which do not allow analytical arguments.
* For further details I recommend reading the reports of the International Atronomical Union (IAU) and the publications from P. K. Seidelmann from 1981.
*
* Short: The first part: "100.46061837 + T*(36000.770053608 + T*(0.000387933 - T/38710000))" calculates the startime at 00:00 in Greenwich.
* The first offset at 100.46061837 degree is due to its definition to the 1.1.2000 which was the offset at this spesific date (fundamental epoch J2000).
*
* The first linear part T*36000.770053608 is also quite easily to anderstand. At 00:00 every day the earth had to spin about 361 degree to be at the same
* position towards the sun due to the rotation around the sun. This means every day at 00:00 we look about 1 degree differently to a fixed star then the day
* bevore at the same time. In one year this is 360 degree and in 100 years this is 36000 degree.
* The quadratic and cubic parts are due to different effects like the precission and nutation of the ecliptic.
* --> more detailed explanations where these terms come from may follow. If someone knows the answer PLEASE tell me!
*
* The adding of the longitude is to get the correct sidereal time at the location of interest. This is necessary because the sidereal time
* is not the same around the globe.
*
* The adding of the time multiplied by "1.00273790935" is necessary because a classical day is more than a 360 degree rotation of the earth.
* This can be explained because we can see the same star at the skye one time more often than the sun due to the earth rotating around the sun.
* The precise time can not be took into account in the calculation of T as mentioned above.
* It has to be multiplied by 15 to receive an angle (360/24=15).*/
}
void calc_coordinates_sun(double time_jd, float *coordinates_sun){
float right_ascension;
float declination;
double T;
double mean_longitude;
double mean_anomaly;
double equation_of_center;
double ecliptic_longitude;
double ecliptic;
T = (time_jd-2451545.0)/36525;
mean_longitude = 280.46645 + (36000.76983 + 0.0003032*T)*T;
mean_anomaly = 357.52910 + (35999.05030 - (0.0001559 - 0.00000048*T)*T)*T;
equation_of_center = (1.914600 - (0.004817 - 0.000014*T)*T)*sin(calc_deg_rad (mean_anomaly))
+ (0.019993 - 0.000101*T)*sin(2*calc_deg_rad (mean_anomaly))
+ (0.00029)*sin(3*calc_deg_rad (mean_anomaly));
ecliptic_longitude = mean_longitude + equation_of_center;
ecliptic = 23.43928 + 0.01301*T;
ecliptic_longitude = calc_deg_rad (ecliptic_longitude);
ecliptic = calc_deg_rad (ecliptic);
right_ascension = atan2 (cos(ecliptic)*sin(ecliptic_longitude), cos(ecliptic_longitude));
declination = asin (sin(ecliptic)*sin(ecliptic_longitude));
*coordinates_sun = calc_rad_deg (right_ascension);
*(coordinates_sun+1) = calc_rad_deg (declination);
}
void calc_coordinates_moon(double time_jd, float *coordinates_moon){
float right_ascension;
float declination;
double T;
double mean_anomaly;
double mean_longitude; /* ecliptic longitude? */
double mean_distance;
double longitude_moon;
double latitude_moon;
double ecliptic;
T = (time_jd-2451545.0)/36525;
mean_longitude = 218.316 + (13.176396*36525) * T;
mean_anomaly = 134.963 + (13.064993*36525) * T;
mean_distance = 93.272 + (13.229350*36525) * T;
longitude_moon = mean_longitude + 6.289 * sin(calc_deg_rad (mean_anomaly));
latitude_moon = 5.128 * sin(calc_deg_rad(mean_distance));
/*double distance_moon;
distance_moon = 385001. - 20905. * cos(calc_deg_rad(mean_anomaly)); Useful for super moon calculation?*/
ecliptic = calc_deg_rad(23.43928 + 0.01301*T);
longitude_moon = calc_deg_rad (longitude_moon);
latitude_moon = calc_deg_rad (latitude_moon);
right_ascension = atan2(cos(ecliptic)*sin(longitude_moon)-sin(ecliptic)*tan(latitude_moon), cos(longitude_moon));
declination = asin(cos(ecliptic)*sin(latitude_moon)+sin(ecliptic)*cos(latitude_moon)*sin(longitude_moon));
/* g_print("time_jd: %f, ecliptic: %f, longitude_moon: %f, latitude_moon: %f, right_ascension %f\n", time_jd, ecliptic, longitude_moon, latitude_moon, right_ascension); */
*coordinates_moon = calc_rad_deg (right_ascension);
*(coordinates_moon+1) = calc_rad_deg (declination);
}
/* Convert between the rotation coordinate system and the horizontal coordinate system */
void calc_convert_rotation_horizontal(float right_ascension, float declination, float latitude, double time_sidereal, float *coordinates)
{
latitude = calc_deg_rad (latitude);
right_ascension = calc_deg_rad (right_ascension);
declination = calc_deg_rad(declination);
time_sidereal = calc_deg_rad (time_sidereal);
float azimuth, elevation;
float x = -cos(latitude)*sin(declination)+sin(latitude)*cos(declination)*cos(time_sidereal-right_ascension);
float y = cos(declination)*sin(time_sidereal-right_ascension);
if (x < 0 && y <= 0){
azimuth = atan(y/x);
}
else if (x < 0 && y > 0){
azimuth = atan(y/x)+2*M_PI;
}
else if (x > 0){
azimuth = atan(y/x)+M_PI;
}
else if (x == 0 && y < 0){
azimuth = M_PI/2;
}
else if (x == 0 && y > 0){
azimuth = -3*M_PI/2;
}
else{
azimuth = 0;
g_print("Error calculating azimuth!");
}
elevation = asin( sin(latitude)*sin(declination) + cos(latitude)*cos(declination)*cos(time_sidereal-right_ascension) );
/* TODO
* explanation missing!!
* */
/* g_print("Latitude %f, RA %f, dec %f, time_sidereal %f, azimuth %f, elevation %f\n", latitude, right_ascension, declination, time_sidereal, azimuth, elevation); */
azimuth = calc_rad_deg (azimuth);
elevation = calc_rad_deg (elevation);
*coordinates = azimuth;
*(coordinates+1) = elevation;
/*g_print("Azimuth: %f, Elevation: %f\n", azimuth, elevation);*/
}