/* N3EMO Orbit Simulator routines */ /* Copyright (C) 1986 Robert W. Berger May be used for non-commercial purposes without prior written permission. */ #include #include #define PI 3.14159265 #define PI2 (PI*2) #define MinutesPerDay (24*60.0) #define SecondsPerDay (60*MinutesPerDay) #define HalfSecond (0.5/SecondsPerDay) #define EarthRadius 6378.16 /* Kilometers */ #define EarthFlat (1/298.25) /* Earth Flattening Coeff. */ #define SiderealSolar 1.0027379093 #define DegreesPerRadian (180/PI) #define RadiansPerDegree (PI/180) #define ABS(x) ((x) < 0 ? (-(x)) : (x)) #define SQR(x) ((x)*(x)) #define RefYear 79 #define RefSidereal 0.27518504 #define RefDay 0 /* Day of week */ char *MonthNames[] = { "Jan","Feb","Mar","Apr","May","Jun","Jul", "Aug","Sep","Oct","Nov","Dec" }; int MonthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31}; char *DayNames[] = { "Sunday","Monday","Tuesday","Wednesday","Thursday", "Friday","Saturday"}; /* Solve Kepler's equation */ /* Inputs: */ /* MeanAnomaly Time since last perigee, in radians. */ /* PI2 = one complete orbit. */ /* Eccentricity Eccentricity of orbit's ellipse. */ /* Output: */ /* TrueAnomaly Angle between perigee, geocenter, and */ /* current position. */ double Kepler(MeanAnomaly,Eccentricity) register double MeanAnomaly,Eccentricity; { register double E; /* Eccentric Anomaly */ register double Error; register double TrueAnomaly; E = MeanAnomaly; /* Initial guess */ do { Error = (E - Eccentricity*sin(E) - MeanAnomaly) / (1 - Eccentricity*cos(E)); E -= Error; } while (ABS(Error) >= 0.000001); if (ABS(E-PI) < 0.000001) TrueAnomaly = PI; else TrueAnomaly = 2*atan(sqrt((1+Eccentricity)/(1-Eccentricity)) *tan(E/2)); if (TrueAnomaly < 0) TrueAnomaly += PI2; return TrueAnomaly; } GetSubSatPoint(EpochTime,EpochRAAN,EpochArgPerigee,Inclination, Eccentricity,RAANPrecession,PerigeePrecession,Time,TrueAnomaly, Latitude,Longitude) double EpochTime,EpochRAAN,EpochArgPerigee,Inclination,Eccentricity; double RAANPrecession,PerigeePrecession,Time; double TrueAnomaly,*Longitude,*Latitude; { double RAAN,ArgPerigee; int i; ArgPerigee = EpochArgPerigee + (Time-EpochTime)*PerigeePrecession; *Latitude = asin(sin(Inclination)*sin(ArgPerigee+TrueAnomaly)); RAAN = EpochRAAN - (Time-EpochTime)*RAANPrecession; *Longitude = -acos(cos(TrueAnomaly+ArgPerigee)/cos(*Latitude)); if ((Inclination > PI/2 && *Latitude < 0) || (Inclination < PI/2 && *Latitude > 0)) *Longitude = -*Longitude; *Longitude += RAAN; /* Convert from celestial to terrestrial coordinates */ *Longitude -= PI2*(Time*SiderealSolar + RefSidereal); /* Make West be positive */ *Longitude = -*Longitude; /* i = floor(Longitude/2*pi) */ i = *Longitude/PI2; if(i < 0) i--; *Longitude -= i*PI2; } GetPrecession(SemiMajorAxis,Eccentricity,Inclination, RAANPrecession,PerigeePrecession) double SemiMajorAxis,Eccentricity,Inclination; double *RAANPrecession,*PerigeePrecession; { *RAANPrecession = 9.95*pow(EarthRadius/SemiMajorAxis,3.5) * cos(Inclination) / SQR(1-SQR(Eccentricity)) * RadiansPerDegree; *PerigeePrecession = 4.97*pow(EarthRadius/SemiMajorAxis,3.5) * (5*SQR(cos(Inclination))-1) / SQR(1-SQR(Eccentricity)) * RadiansPerDegree; } GetBearings(SiteLat,SiteLong,SiteAltitude, SatLat,SatLong,Radius,Azimuth,Elevation,Range) double SiteLat,SiteLong,SiteAltitude,SatLat,SatLong,Radius; double *Azimuth,*Elevation,*Range; { double SinSiteLat,sinSiteLong,SinSatLat,SinSatLong; double CosSiteLat,cosSiteLong,CosSatLat,CosSatLong; double CosBeta,SinBeta; double LongDiff; SinSiteLat = sin(SiteLat); sinSiteLong = sin(SiteLong); CosSiteLat = cos(SiteLat); cosSiteLong = cos(SiteLong); SinSatLat = sin(SatLat); SinSatLong = sin(SatLong); CosSatLat = cos(SatLat); CosSatLong = cos(SatLong); LongDiff = SiteLong - SatLong; CosBeta = SinSiteLat*SinSatLat+CosSiteLat*CosSatLat*cos(LongDiff); SinBeta = sqrt(1-SQR(CosBeta)); *Azimuth = acos((SinSatLat- SinSiteLat*CosBeta)/CosSiteLat/SinBeta); if (LongDiff < -PI) LongDiff += PI2; if (LongDiff > PI) LongDiff -= PI2; if (LongDiff < 0) *Azimuth = PI2 - *Azimuth; /* Convert to geocentric radius */ SiteAltitude += EarthRadius*(1-EarthFlat/2+EarthFlat/2*cos(2*SiteLat)); *Elevation = atan((Radius*CosBeta-(SiteAltitude)) /(Radius*SinBeta)); *Range = sqrt(SQR(Radius) + SQR(SiteAltitude) -2*Radius*SiteAltitude*CosBeta); } SPrintDate(Str,Day) char *Str; { int Month,Year,DayOfWeek; DayOfWeek = (Day-RefDay) % 7; Year = RefYear; while (Day <= 0) { Year -= 1; if (Year%4 == 0) Day += 366; else Day += 365; } while ((Year%4 == 0 && Day > 366) || (Year%4 != 0 && Day > 365)) { if (Year%4 == 0) Day -= 366; else Day -= 365; Year += 1; } if (Year%4 == 0) MonthDays[1] += 1; /* Leap year */ Month = 0; while (Day > MonthDays[Month]) { Day -= MonthDays[Month]; Month += 1; } sprintf(Str,"%s %d %s %d",DayNames[DayOfWeek],Day, MonthNames[Month],Year); if (Year%4 == 0) MonthDays[1] -= 1; /* Leap year */ } SPrintTime(Str,Time) char *Str; double Time; { int day,hours,minutes,seconds; day = Time; Time -= day; if (Time < 0) Time += 1.0; /* Correct for truncation problems with negatives */ hours = Time*24; Time -= hours/24.0; minutes = Time*MinutesPerDay; Time -= minutes/MinutesPerDay; seconds = Time*SecondsPerDay; seconds -= seconds/SecondsPerDay; sprintf(Str,"%02d%02d:%02d",hours,minutes,seconds); } PrintDate(OutFile,Day) FILE *OutFile; { char str[100]; SPrintDate(str,Day); fprintf(OutFile,"%s",str); } PrintTime(OutFile,Time) FILE *OutFile; double Time; { char str[100]; SPrintTime(str,Time); fprintf(OutFile,"%s",str); } /* Get the Day Number for a given date. January 1 of the reference year is day 1. Note that the Day Number may be negative, if the sidereal reference is in the future. */ double GetDay(Year,Month,Day) double Day; { int TmpYear; TmpYear = Year; while (TmpYear > RefYear) { TmpYear -= 1; if (TmpYear%4 == 0) Day += 366; else Day += 365; } while (TmpYear < RefYear) { if (TmpYear%4 == 0) Day -= 366; else Day -= 365; TmpYear += 1; } if (Year%4 == 0) MonthDays[1] += 1; /* Leap year */ while (Month > 1) { Month -= 1; Day += MonthDays[Month-1]; } if (Year%4 == 0) MonthDays[1] -= 1; /* Leap year */ return Day; }