#include /*----------------------------------------------------------------------------*/ double factorial_div( double value, int x) { if(!x) return 1; else { while( x > 1) { value = value / x--; } } return value; } /*----------------------------------------------------------------------------*/ double powerd( double x, int y) { int i=0; double ans=1.0; if(!y) return 1.000; else { while( i < y) { i++; ans = ans * x; } } return ans; } /*----------------------------------------------------------------------------*/ double SIN( double x) { int i=0; int j=1; int sign=1; double y1 = 0.0; double diff = 1000.0; if (x < 0.0) { x = -1 * x; sign = -1; } while ( x > 360.0*M_PI/180) { x = x - 360*M_PI/180; } if( x > (270.0 * M_PI / 180) ) { sign = sign * -1; x = 360.0*M_PI/180 - x; } else if ( x > (180.0 * M_PI / 180) ) { sign = sign * -1; x = x - 180.0 *M_PI / 180; } else if ( x > (90.0 * M_PI / 180) ) { x = 180.0 *M_PI / 180 - x; } while( powerd( diff, 2) > 1.0E-16 ) { i++; diff = j * factorial_div( powerd( x, (2*i -1)) ,(2*i -1)); y1 = y1 + diff; j = -1 * j; } return ( sign * y1 ); } /*----------------------------------------------------------------------------*/ double COS(double x) { return SIN(90 * M_PI / 180 - x); } /*----------------------------------------------------------------------------*/ double ATAN( double x) { int i=0; /* counter for terms in binomial series */ int j=1; /* sign of nth term in series */ int k=0; int sign = 1; /* sign of the input x */ double y = 0.0; /* the output */ double deltay = 1.0; /* the value of the next term in the series */ double addangle = 0.0; /* used if arctan > 22.5 degrees */ if (x < 0.0) { x = -1 * x; sign = -1; } while( x > 0.3249196962 ) { k++; x = (x - 0.3249196962) / (1 + x * 0.3249196962); } addangle = k * 18.0 *M_PI/180; while( powerd( deltay, 2) > 1.0E-16 ) { i++; deltay = j * powerd( x, (2*i -1)) / (2*i -1); y = y + deltay; j = -1 * j; } return (sign * (y + addangle) ); } double ASIN(double x) { return 2 * ATAN( x / (1 + std::sqrt(1.0 - x*x))); } double Radians( double number ) { return number*M_PI/180; } double Deg( double number ) { return number*180/M_PI; } double Rev( double number ) { return number - std::floor( number / 360.0 ) * 360; } double calcElevation( double SatLon, double SiteLat, double SiteLon, int Height_over_ocean = 0 ) { double a0=0.58804392, a1=-0.17941557, a2=0.29906946E-1, a3=-0.25187400E-2, a4=0.82622101E-4, f = 1.00 / 298.257, // Earth flattning factor r_sat=42164.57, // Distance from earth centre to satellite r_eq=6378.14, // Earth radius sinRadSiteLat=SIN(Radians(SiteLat)), cosRadSiteLat=COS(Radians(SiteLat)), Rstation = r_eq / ( std::sqrt( 1.00 - f*(2.00-f)*sinRadSiteLat*sinRadSiteLat ) ), Ra = (Rstation+Height_over_ocean)*cosRadSiteLat, Rz= Rstation*(1.00-f)*(1.00-f)*sinRadSiteLat, alfa_rx=r_sat*COS(Radians(SatLon-SiteLon)) - Ra, alfa_ry=r_sat*SIN(Radians(SatLon-SiteLon)), alfa_rz=-Rz, alfa_r_north=-alfa_rx*sinRadSiteLat + alfa_rz*cosRadSiteLat, alfa_r_zenith=alfa_rx*cosRadSiteLat + alfa_rz*sinRadSiteLat, El_geometric=Deg(ATAN( alfa_r_zenith/std::sqrt(alfa_r_north*alfa_r_north+alfa_ry*alfa_ry))), x = std::fabs(El_geometric+0.589), refraction=std::fabs(a0+a1*x+a2*x*x+a3*x*x*x+a4*x*x*x*x), El_observed = 0.00; if (El_geometric > 10.2) El_observed = El_geometric+0.01617*(COS(Radians(std::fabs(El_geometric)))/SIN(Radians(std::fabs(El_geometric))) ); else El_observed = El_geometric+refraction; if (alfa_r_zenith < -3000) El_observed=-99; return El_observed; } double calcAzimuth(double SatLon, double SiteLat, double SiteLon, int Height_over_ocean=0) { double f = 1.00 / 298.257, // Earth flattning factor r_sat=42164.57, // Distance from earth centre to satellite r_eq=6378.14, // Earth radius sinRadSiteLat=SIN(Radians(SiteLat)), cosRadSiteLat=COS(Radians(SiteLat)), Rstation = r_eq / ( std::sqrt( 1 - f*(2-f)*sinRadSiteLat*sinRadSiteLat ) ), Ra = (Rstation+Height_over_ocean)*cosRadSiteLat, Rz = Rstation*(1-f)*(1-f)*sinRadSiteLat, alfa_rx = r_sat*COS(Radians(SatLon-SiteLon)) - Ra, alfa_ry = r_sat*SIN(Radians(SatLon-SiteLon)), alfa_rz = -Rz, alfa_r_north = -alfa_rx*sinRadSiteLat + alfa_rz*cosRadSiteLat, Azimuth = 0.00; if (alfa_r_north < 0) Azimuth = 180+Deg(ATAN(alfa_ry/alfa_r_north)); else Azimuth = Rev(360+Deg(ATAN(alfa_ry/alfa_r_north))); return Azimuth; } double calcDeclination( double SiteLat, double Azimuth, double Elevation) { return Deg( ASIN(SIN(Radians(Elevation)) * SIN(Radians(SiteLat)) + COS(Radians(Elevation)) * COS(Radians(SiteLat)) + COS(Radians(Azimuth)) ) ); } double calcSatHourangle( double SatLon, double SiteLat, double SiteLon ) { double Azimuth=calcAzimuth(SatLon, SiteLat, SiteLon ), Elevation=calcElevation( SatLon, SiteLat, SiteLon ), a = - COS(Radians(Elevation)) * SIN(Radians(Azimuth)), b = SIN(Radians(Elevation)) * COS(Radians(SiteLat)) - COS(Radians(Elevation)) * SIN(Radians(SiteLat)) * COS(Radians(Azimuth)), // Works for all azimuths (northern & southern hemisphere) returnvalue = 180 + Deg(ATAN(a/b)); if ( Azimuth > 270 ) { returnvalue = ( (returnvalue-180) + 360 ); if (returnvalue>360) returnvalue = 360 - (returnvalue-360); } if ( Azimuth < 90 ) returnvalue = ( 180 - returnvalue ); return returnvalue; }