/** \brief SGP4SDP4 driver for doing AOS/LOS calculations. * \param sat Pointer to the satellite data. * \param qth Pointer to the QTH data. * \param t The time for calculation (Julian Date) * */ void predict_calc (sat_t *sat, qth_t *qth, gdouble t) { obs_set_t obs_set; geodetic_t sat_geodetic; geodetic_t obs_geodetic; double age; obs_geodetic.lon = qth->lon * de2ra; obs_geodetic.lat = qth->lat * de2ra; obs_geodetic.alt = qth->alt / 1000.0; obs_geodetic.theta = 0; sat->jul_utc = t; sat->tsince = (sat->jul_utc - sat->jul_epoch) * xmnpda; /* call the norad routines according to the deep-space flag */ if (sat->flags & DEEP_SPACE_EPHEM_FLAG) SDP4 (sat, sat->tsince); else SGP4 (sat, sat->tsince); Convert_Sat_State (&sat->pos, &sat->vel); /* get the velocity of the satellite */ Magnitude (&sat->vel); sat->velo = sat->vel.w; Calculate_Obs (sat->jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set); Calculate_LatLonAlt (sat->jul_utc, &sat->pos, &sat_geodetic); while (sat_geodetic.lon < -pi) sat_geodetic.lon += twopi; while (sat_geodetic.lon > (pi)) sat_geodetic.lon -= twopi; sat->az = Degrees (obs_set.az); sat->el = Degrees (obs_set.el); sat->range = obs_set.range; sat->range_rate = obs_set.range_rate; sat->ssplat = Degrees (sat_geodetic.lat); sat->ssplon = Degrees (sat_geodetic.lon); sat->alt = sat_geodetic.alt; sat->ma = Degrees (sat->phase); sat->ma *= 256.0/360.0; sat->phase = Degrees (sat->phase); /* same formulas, but the one from predict is nicer */ //sat->footprint = 2.0 * xkmper * acos (xkmper/sat->pos.w); sat->footprint = 12756.33 * acos (xkmper / (xkmper+sat->alt)); age = sat->jul_utc - sat->jul_epoch; sat->orbit = (long) floor((sat->tle.xno * xmnpda/twopi + age * sat->tle.bstar * ae) * age + sat->tle.xmo/twopi) + sat->tle.revnum - 1; }
/** \brief Calculate satellite visibility. * \param sat The satellite structure. * \param qth The QTH * \param jul_utc The time at which the visibility should be calculated. * \return The visiblity code. * */ sat_vis_t get_sat_vis (sat_t *sat, qth_t *qth, gdouble jul_utc) { gboolean sat_sun_status; gdouble sun_el; gdouble threshold; gdouble eclipse_depth; sat_vis_t vis = SAT_VIS_NONE; vector_t zero_vector = {0,0,0,0}; geodetic_t obs_geodetic; /* Solar ECI position vector */ vector_t solar_vector=zero_vector; /* Solar observed az and el vector */ obs_set_t solar_set; /* FIXME: could be passed as parameter */ obs_geodetic.lon = qth->lon * de2ra; obs_geodetic.lat = qth->lat * de2ra; obs_geodetic.alt = qth->alt / 1000.0; obs_geodetic.theta = 0; Calculate_Solar_Position (jul_utc, &solar_vector); Calculate_Obs (jul_utc, &solar_vector, &zero_vector, &obs_geodetic, &solar_set); if (Sat_Eclipsed (&sat->pos, &solar_vector, &eclipse_depth)) { /* satellite is eclipsed */ sat_sun_status = FALSE; } else { /* satellite in sunlight => may be visible */ sat_sun_status = TRUE; } if (sat_sun_status) { sun_el = Degrees (solar_set.el); /* FIXME */ /* threshold = (gdouble) sat_cfg_get_int (SAT_CFG_INT_PRED_TWILIGHT_THLD); */ threshold = (gdouble) -6; if (sun_el <= threshold && sat->el >= 0.0) vis = SAT_VIS_VISIBLE; else vis = SAT_VIS_DAYLIGHT; } else vis = SAT_VIS_ECLIPSED; return vis; }
void Calculate_RADec_and_Obs ( double _time, vector_t *pos, vector_t *vel, geodetic_t *geodetic, obs_astro_t *obs_set) { /* Reference: Methods of Orbit Determination by */ /* Pedro Ramon Escobal, pp. 401-402 */ double phi,theta,sin_theta,cos_theta,sin_phi,cos_phi, az,el,Lxh,Lyh,Lzh,Sx,Ex,Zx,Sy,Ey,Zy,Sz,Ez,Zz, Lx,Ly,Lz,cos_delta,sin_alpha,cos_alpha; obs_set_t obs; Calculate_Obs(_time,pos,vel,geodetic,&obs); /* if( isFlagSet(VISIBLE_FLAG) ) {*/ az = obs.az; el = obs.el; phi = geodetic->lat; theta = FMod2p(ThetaG_JD(_time) + geodetic->lon); sin_theta = sin(theta); cos_theta = cos(theta); sin_phi = sin(phi); cos_phi = cos(phi); Lxh = -cos(az) * cos(el); Lyh = sin(az) * cos(el); Lzh = sin(el); Sx = sin_phi * cos_theta; Ex = -sin_theta; Zx = cos_theta * cos_phi; Sy = sin_phi * sin_theta; Ey = cos_theta; Zy = sin_theta*cos_phi; Sz = -cos_phi; Ez = 0; Zz = sin_phi; Lx = Sx*Lxh + Ex * Lyh + Zx*Lzh; Ly = Sy*Lxh + Ey * Lyh + Zy*Lzh; Lz = Sz*Lxh + Ez * Lyh + Zz*Lzh; obs_set->dec = ArcSin(Lz); /* Declination (radians)*/ cos_delta = sqrt(1 - Sqr(Lz)); sin_alpha = Ly / cos_delta; cos_alpha = Lx / cos_delta; obs_set->ra = AcTan(sin_alpha,cos_alpha); /* Right Ascension (radians)*/ obs_set->ra = FMod2p(obs_set->ra); /*}*/ /*if*/ } /* Procedure Calculate_RADec */
void Calculate_RADec(double time, const double pos[3], const double vel[3], geodetic_t *geodetic, vector_t *obs_set) { /* Reference: Methods of Orbit Determination by */ /* Pedro Ramon Escobal, pp. 401-402 */ double phi, theta, sin_theta, cos_theta, sin_phi, cos_phi, az, el, Lxh, Lyh, Lzh, Sx, Ex, Zx, Sy, Ey, Zy, Sz, Ez, Zz, Lx, Ly, Lz, cos_delta, sin_alpha, cos_alpha; Calculate_Obs(time,pos,vel,geodetic,obs_set); az=obs_set->x; el=obs_set->y; phi=geodetic->lat; theta=FMod2p(ThetaG_JD(time)+geodetic->lon); sin_theta=sin(theta); cos_theta=cos(theta); sin_phi=sin(phi); cos_phi=cos(phi); Lxh=-cos(az)*cos(el); Lyh=sin(az)*cos(el); Lzh=sin(el); Sx=sin_phi*cos_theta; Ex=-sin_theta; Zx=cos_theta*cos_phi; Sy=sin_phi*sin_theta; Ey=cos_theta; Zy=sin_theta*cos_phi; Sz=-cos_phi; Ez=0.0; Zz=sin_phi; Lx=Sx*Lxh+Ex*Lyh+Zx*Lzh; Ly=Sy*Lxh+Ey*Lyh+Zy*Lzh; Lz=Sz*Lxh+Ez*Lyh+Zz*Lzh; obs_set->y=ArcSin(Lz); /* Declination (radians) */ cos_delta=sqrt(1.0-Sqr(Lz)); sin_alpha=Ly/cos_delta; cos_alpha=Lx/cos_delta; obs_set->x=AcTan(sin_alpha,cos_alpha); /* Right Ascension (radians) */ obs_set->x=FMod2p(obs_set->x); }
/** \brief Initialise satellite data. * \param sat The satellite to initialise. * \param qth Optional QTH info, use (0,0) if NULL. * * This function calculates the satellite data at t = 0, ie. epoch time * The function is called automatically by gtk_sat_data_read_sat. */ void gtk_sat_data_init_sat (sat_t *sat, qth_t *qth) { geodetic_t obs_geodetic; obs_set_t obs_set; geodetic_t sat_geodetic; double jul_utc, age; g_return_if_fail (sat != NULL); jul_utc = Julian_Date_of_Epoch (sat->tle.epoch); // => tsince = 0.0 sat->jul_epoch = jul_utc; /* initialise observer location */ if (qth != NULL) { obs_geodetic.lon = qth->lon * de2ra; obs_geodetic.lat = qth->lat * de2ra; obs_geodetic.alt = qth->alt / 1000.0; obs_geodetic.theta = 0; } else { obs_geodetic.lon = 0.0; obs_geodetic.lat = 0.0; obs_geodetic.alt = 0.0; obs_geodetic.theta = 0; } /* execute computations */ if (sat->flags & DEEP_SPACE_EPHEM_FLAG) SDP4 (sat, 0.0); else SGP4 (sat, 0.0); /* scale position and velocity to km and km/sec */ Convert_Sat_State (&sat->pos, &sat->vel); /* get the velocity of the satellite */ Magnitude (&sat->vel); sat->velo = sat->vel.w; Calculate_Obs (jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set); Calculate_LatLonAlt (jul_utc, &sat->pos, &sat_geodetic); while (sat_geodetic.lon < -pi) sat_geodetic.lon += twopi; while (sat_geodetic.lon > (pi)) sat_geodetic.lon -= twopi; sat->az = Degrees (obs_set.az); sat->el = Degrees (obs_set.el); sat->range = obs_set.range; sat->range_rate = obs_set.range_rate; sat->ssplat = Degrees (sat_geodetic.lat); sat->ssplon = Degrees (sat_geodetic.lon); sat->alt = sat_geodetic.alt; sat->ma = Degrees (sat->phase); sat->ma *= 256.0/360.0; sat->footprint = 2.0 * xkmper * acos (xkmper/sat->pos.w); age = 0.0; sat->orbit = (long) floor((sat->tle.xno * xmnpda/twopi + age * sat->tle.bstar * ae) * age + sat->tle.xmo/twopi) + sat->tle.revnum - 1; /* orbit type */ sat->otype = get_orbit_type (sat); }
/* Main program */ int main(void) { /* TLE source file */ char tle_file[] = "./rax.txt"; /* Observer's geodetic co-ordinates. */ /* Lat North, Lon East in rads, Alt in km */ geodetic_t obs_geodetic = {0.7368, -1.4615, 0.251, 0.0}; /* Two-line Orbital Elements for the satellite */ tle_t tle ; /* Zero vector for initializations */ vector_t zero_vector = {0,0,0,0}; /* Satellite position and velocity vectors */ vector_t vel = zero_vector; vector_t pos = zero_vector; /* Satellite Az, El, Range, Range rate */ vector_t obs_set; /* Solar ECI position vector */ vector_t solar_vector = zero_vector; /* Solar observed azi and ele vector */ vector_t solar_set; /* Calendar date and time (UTC) */ struct tm utc; /* Satellite's predicted geodetic position */ geodetic_t sat_geodetic; double tsince, /* Time since epoch (in minutes) */ jul_epoch, /* Julian date of epoch */ jul_utc, /* Julian UTC date */ eclipse_depth = 0, /* Depth of satellite eclipse */ /* Satellite's observed position, range, range rate */ sat_azi, sat_ele, sat_range, sat_range_rate, /* Satellites geodetic position and velocity */ sat_lat, sat_lon, sat_alt, sat_vel, /* Solar azimuth and elevation */ sun_azi, sun_ele; /* Used for storing function return codes */ int flg; char ephem[5], /* Ephemeris in use string */ sat_status[12]; /* Satellite eclipse status */ /* Input one (first!) TLE set from file */ flg = Input_Tle_Set(tle_file, &tle); /* Abort if file open fails */ if( flg == -1 ) { printf(" File open failed - Exiting!\n"); exit(-1); } /* Print satellite name and TLE read status */ printf(" %s: ", tle.sat_name); if( flg == -2 ) { printf("TLE set bad - Exiting!\n"); exit(-2); } else printf("TLE set good - Happy Tracking!\n"); /* Printout of tle set data for tests if needed */ /* printf("\n %s %s %i %i %i\n" " %14f %10f %8f %8f\n" " %8f %8f %9f %8f %8f %12f\n", tle.sat_name, tle.idesg, tle.catnr, tle.elset, tle.revnum, tle.epoch, tle.xndt2o, tle.xndd6o, tle.bstar, tle.xincl, tle.xnodeo, tle.eo, tle.omegao, tle.xmo, tle.xno); */ /** !Clear all flags! **/ /* Before calling a different ephemeris */ /* or changing the TLE set, flow control */ /* flags must be cleared in main(). */ ClearFlag(ALL_FLAGS); /** Select ephemeris type **/ /* Will set or clear the DEEP_SPACE_EPHEM_FLAG */ /* depending on the TLE parameters of the satellite. */ /* It will also pre-process tle members for the */ /* ephemeris functions SGP4 or SDP4 so this function */ /* must be called each time a new tle set is used */ select_ephemeris(&tle); do /* Loop */ { /* Get UTC calendar and convert to Julian */ UTC_Calendar_Now(&utc); jul_utc = Julian_Date(&utc); /* Convert satellite's epoch time to Julian */ /* and calculate time since epoch in minutes */ jul_epoch = Julian_Date_of_Epoch(tle.epoch); tsince = (jul_utc - jul_epoch) * xmnpda; /* Copy the ephemeris type in use to ephem string */ if( isFlagSet(DEEP_SPACE_EPHEM_FLAG) ) strcpy(ephem,"SDP4"); else strcpy(ephem,"SGP4"); /* Call NORAD routines according to deep-space flag */ if( isFlagSet(DEEP_SPACE_EPHEM_FLAG) ) SDP4(tsince, &tle, &pos, &vel); else SGP4(tsince, &tle, &pos, &vel); /* Scale position and velocity vectors to km and km/sec */ Convert_Sat_State( &pos, &vel ); /* Calculate velocity of satellite */ Magnitude( &vel ); sat_vel = vel.w; /** All angles in rads. Distance in km. Velocity in km/s **/ /* Calculate satellite Azi, Ele, Range and Range-rate */ Calculate_Obs(jul_utc, &pos, &vel, &obs_geodetic, &obs_set); /* Calculate satellite Lat North, Lon East and Alt. */ Calculate_LatLonAlt(jul_utc, &pos, &sat_geodetic); /* Calculate solar position and satellite eclipse depth */ /* Also set or clear the satellite eclipsed flag accordingly */ Calculate_Solar_Position(jul_utc, &solar_vector); Calculate_Obs(jul_utc,&solar_vector,&zero_vector,&obs_geodetic,&solar_set); if( Sat_Eclipsed(&pos, &solar_vector, &eclipse_depth) ) SetFlag( SAT_ECLIPSED_FLAG ); else ClearFlag( SAT_ECLIPSED_FLAG ); /* Copy a satellite eclipse status string in sat_status */ if( isFlagSet( SAT_ECLIPSED_FLAG ) ) strcpy( sat_status, "Eclipsed" ); else strcpy( sat_status, "In Sunlight" ); /* Convert and print satellite and solar data */ sat_azi = Degrees(obs_set.x); sat_ele = Degrees(obs_set.y); sat_range = obs_set.z; sat_range_rate = obs_set.w; sat_lat = Degrees(sat_geodetic.lat); sat_lon = Degrees(sat_geodetic.lon); sat_alt = sat_geodetic.alt; sun_azi = Degrees(solar_set.x); sun_ele = Degrees(solar_set.y); printf("\n Date: %02d/%02d/%04d UTC: %02d:%02d:%02d Ephemeris: %s" "\n Azi=%6.1f Ele=%6.1f Range=%8.1f Range Rate=%6.2f" "\n Lat=%6.1f Lon=%6.1f Alt=%8.1f Vel=%8.3f" "\n Stellite Status: %s - Depth: %2.3f" "\n Sun Azi=%6.1f Sun Ele=%6.1f\n", utc.tm_mday, utc.tm_mon, utc.tm_year, utc.tm_hour, utc.tm_min, utc.tm_sec, ephem, sat_azi, sat_ele, sat_range, sat_range_rate, sat_lat, sat_lon, sat_alt, sat_vel, sat_status, eclipse_depth, sun_azi, sun_ele); sleep(1); } /* End of do */ while( 1 ); /* This stops Compaq ccc 'unreachcode' warning! */ return(0); } /* End of main() */