/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* Gpredict: Real-time satellite tracking and orbit prediction program This unit is: Copyright (C) 1992-1999 Dr TS Kelso. Copyright (C) 2001 by N. Kyriazis Copyright (C) 2006 Alexandru Csete, OZ9AEC. Comments, questions and bugreports should be submitted via http://sourceforge.net/projects/groundstation/ More details can be found at the project home page: http://groundstation.sourceforge.net/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, visit http://www.fsf.org/ */ /* original header: */ /* Unit SGP_In */ /* Author: Dr TS Kelso */ /* Original Version: 1992 Jun 25 */ /* Current Revision: 1999 Nov 27 */ /* Version: 2.10 */ /* Copyright: 1992-1999, All Rights Reserved */ /* Ported to C by N. Kyriazis April 6 2001 */ #include #include #include "sgp4sdp4.h" /* Calculates the checksum mod 10 of a line from a TLE set and */ /* returns 1 if it compares with checksum in column 68, else 0.*/ /* tle_set is a character string holding the two lines read */ /* from a text file containing NASA format Keplerian elements. */ /* NOTE!!! The stuff about two lines is not quite true. The function assumes that tle_set[0] is the begining of the line and that there are 68 elements - see the consumer */ int Checksum_Good (char *tle_set) { int i, check_digit, value, checksum = 0; for (i = 0; i < 68; i++) { if ( (tle_set[i] >= '0') && (tle_set[i] <= '9') ) value = tle_set[i] - '0'; else if ( tle_set[i] == '-' ) value = 1; else value = 0; checksum += value; } /* End for(i = 0; i < 68; i++) */ checksum %= 10; check_digit = tle_set[68] - '0'; return (checksum == check_digit); } /* Function Checksums_Good */ /*------------------------------------------------------------------*/ /* Carries out various checks on a TLE set to verify its validity */ /* tle_set is a character string holding the two lines read */ /* from a text file containing NASA format Keplerian elements. */ int Good_Elements( char *tle_set ) { /* Verify checksum of both lines of a TLE set */ if ( !Checksum_Good(&tle_set[0]) || !Checksum_Good(&tle_set[69]) ) return (0); /* Check the line number of each line */ if ( (tle_set[0] != '1') || (tle_set[69] != '2') ) return (0); /* Verify that Satellite Number is same in both lines */ if ( strncmp( &tle_set[2], &tle_set[71], 5 ) != 0 ) return (0); /* Check that various elements are in the right place */ if ( (tle_set[ 23] != '.') || (tle_set[ 34] != '.') || (tle_set[ 80] != '.') || (tle_set[ 89] != '.') || (tle_set[106] != '.') || (tle_set[115] != '.') || (tle_set[123] != '.') || (strncmp(&tle_set[61], " 0 ", 3) != 0) ) return (0); return (1); } /* Function Good_Elements */ /*------------------------------------------------------------------*/ /* Converts the strings in a raw two-line element set */ /* to their intended numerical values. No processing */ /* of these values is done, e.g. from deg to rads etc. */ /* This is done in the select_ephemeris() function. */ void Convert_Satellite_Data (char *tle_set, tle_t *tle) { char buff[15]; /** Decode Card 1 **/ /* Satellite's catalogue number */ strncpy (buff, &tle_set[2], 5); buff[5] = '\0'; tle->catnr = atoi (buff); /* International Designator for satellite */ strncpy (tle->idesg, &tle_set[9], 8); tle->idesg[8] = '\0'; /* Epoch time; this is the complete, unconverted epoch. */ strncpy (buff, &tle_set[18], 14); buff[14] = '\0'; // tle->epoch = atof (buff); tle->epoch = g_ascii_strtod (buff, NULL); /* Now, convert the epoch time into year, day and fraction of day, according to: YYDDD.FFFFFFFF */ /* Epoch year; we assume > 2000 ... */ strncpy (buff, &tle_set[18], 2); buff[2] = '\0'; tle->epoch_year = 2000 + atoi (buff); /* Epoch day */ strncpy (buff, &tle_set[20], 3); buff[3] = '\0'; tle->epoch_day = atoi (buff); /* Epoch fraction of day */ buff[0] = '0'; strncpy (&buff[1], &tle_set[23], 9); buff[10] = '\0'; tle->epoch_fod = g_ascii_strtod (buff, NULL); /* Satellite's First Time Derivative */ strncpy (buff, &tle_set[33], 10); buff[10] = '\0'; tle->xndt2o = g_ascii_strtod (buff, NULL); /* Satellite's Second Time Derivative */ strncpy (buff, &tle_set[44], 1); buff[1] = '.'; strncpy (&buff[2], &tle_set[45], 5); buff[7] = 'E'; strncpy (&buff[8], &tle_set[50], 2); buff[10] = '\0'; tle->xndd6o = g_ascii_strtod (buff, NULL); /* Satellite's bstar drag term FIXME: How about buff[0] ???? */ strncpy (buff, &tle_set[53], 1); buff[1] = '.'; strncpy (&buff[2], &tle_set[54], 5); buff[7] = 'E'; strncpy (&buff[8], &tle_set[59], 2); buff[10] = '\0'; tle->bstar = g_ascii_strtod (buff, NULL); /* Element Number */ strncpy (buff, &tle_set[64], 4); buff[4] = '\0'; tle->elset = atoi (buff); /** Decode Card 2 **/ /* Satellite's Orbital Inclination (degrees) */ strncpy (buff, &tle_set[77], 8); buff[8] = '\0'; tle->xincl = g_ascii_strtod (buff, NULL); /* Satellite's RAAN (degrees) */ strncpy (buff, &tle_set[86], 8); buff[8] = '\0'; tle->xnodeo = g_ascii_strtod (buff, NULL); /* Satellite's Orbital Eccentricity */ buff[0] = '.'; strncpy (&buff[1], &tle_set[95], 7); buff[8] = '\0'; tle->eo = g_ascii_strtod (buff, NULL); /* Satellite's Argument of Perigee (degrees) */ strncpy (buff, &tle_set[103], 8); buff[8] = '\0'; tle->omegao = g_ascii_strtod (buff, NULL); /* Satellite's Mean Anomaly of Orbit (degrees) */ strncpy (buff, &tle_set[112], 8); buff[8] = '\0'; tle->xmo = g_ascii_strtod (buff, NULL); /* Satellite's Mean Motion (rev/day) */ strncpy (buff, &tle_set[121], 10); buff[10] = '\0'; tle->xno = g_ascii_strtod (buff, NULL); /* Satellite's Revolution number at epoch */ strncpy (buff, &tle_set[132], 5); buff[5] = '\0'; tle->revnum = g_ascii_strtod (buff, NULL); } /* Procedure Convert_Satellite_Data */ /*------------------------------------------------------------------*/ int Get_Next_Tle_Set (char line[3][80], tle_t *tle) { int idx, /* Index for loops and arrays */ chr; /* Used for inputting characters */ char tle_set[139]; /* Two lines of a TLE set */ /* set status to unknown by sefault */ tle->status = OP_STAT_UNKNOWN; /* Read the satellite's name */ for (idx = 0 ; idx < 25; idx++) { chr = line[0][idx]; if ( (chr != CR) && (chr != LF) && (chr != '\0')) { /* avoid escaping & */ if (chr == '&') { tle->sat_name[idx] = '/'; continue; } /* check for operational status encoded in name */ if ((idx < 23) && (chr == '[') && (line[0][idx+2] == ']') && ((line[0][idx+1] == '+') || (line[0][idx+1] == '-') || (line[0][idx+1] == 'P') || (line[0][idx+1] == 'B') || (line[0][idx+1] == 'S') || (line[0][idx+1] == 'X'))) { /* get operational status */ switch (line[0][idx+1]) { case '+': tle->status = OP_STAT_OPERATIONAL; break; case '-': tle->status = OP_STAT_NONOP; break; case 'P': tle->status = OP_STAT_PARTIAL; break; case 'B': tle->status = OP_STAT_STDBY; break; case 'S': tle->status = OP_STAT_SPARE; break; case 'X': tle->status = OP_STAT_EXTENDED; break; default: tle->status = OP_STAT_UNKNOWN; break; } /* terminate sat_name string */ tle->sat_name[idx] = '\0'; /* force loop exit */ idx = 25; } else { /* no operational status in name, go on */ tle->sat_name[idx] = chr; } } else { /* strip off trailing spaces */ while ((chr = line[0][--idx]) == ' '); tle->sat_name[++idx] = '\0'; break; } } /* Read in first line of TLE set */ strncpy (tle_set, line[1], 70); /* Read in second line of TLE set and terminate string */ strncpy (&tle_set[69], line[2], 70); tle_set[138] = '\0'; /* Check TLE set and abort if not valid */ if( !Good_Elements(tle_set) ) return (-2); /* Convert the TLE set to orbital elements */ Convert_Satellite_Data ( tle_set, tle ); return (1); } /*------------------------------------------------------------------*/ /* Selects the apropriate ephemeris type to be used */ /* for predictions according to the data in the TLE */ /* It also processes values in the tle set so that */ /* they are apropriate for the sgp4/sdp4 routines */ void select_ephemeris (sat_t *sat) { double ao,xnodp,dd1,dd2,delo,temp,a1,del1,r1; /* Preprocess tle set */ sat->tle.xnodeo *= de2ra; sat->tle.omegao *= de2ra; sat->tle.xmo *= de2ra; sat->tle.xincl *= de2ra; temp = twopi/xmnpda/xmnpda; /* store mean motion before conversion */ sat->meanmo = sat->tle.xno; sat->tle.xno = sat->tle.xno * temp * xmnpda; sat->tle.xndt2o *= temp; sat->tle.xndd6o = sat->tle.xndd6o * temp / xmnpda; sat->tle.bstar /= ae; /* Period > 225 minutes is deep space */ dd1 = (xke / sat->tle.xno); dd2 = tothrd; a1 = pow (dd1, dd2); r1 = cos (sat->tle.xincl); dd1 = (1.0 - sat->tle.eo * sat->tle.eo); temp = ck2 * 1.5f * (r1*r1 * 3.0 - 1.0) / pow (dd1, 1.5); del1 = temp / (a1*a1); ao = a1 * (1.0 - del1 * (tothrd * 0.5 + del1 * (del1 * 1.654320987654321 + 1.0))); delo = temp / (ao*ao); xnodp = sat->tle.xno / (delo + 1.0); /* Select a deep-space/near-earth ephemeris */ if (twopi/xnodp/xmnpda >= .15625) sat->flags |= DEEP_SPACE_EPHEM_FLAG; else sat->flags &= ~DEEP_SPACE_EPHEM_FLAG; return; } /* End of select_ephemeris() */ /*------------------------------------------------------------------*/