1
0
Fork 0
sattools/src/tle2rv.c

647 lines
14 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "sgdp4h.h"
#include "satutl.h"
#include <getopt.h>
#define LIM 128
#define XKE 0.07436680 // Guassian Gravitational Constant
#define XKMPER 6378.135
#define AE 1.0
#define XMNPDA 1440.0
#define R2D 180.0/M_PI
#define D2R M_PI/180.0
extern double SGDP4_jd0;
// Nutation series
static const struct
{
int nm1, nm, nf, nd, nn;
double s, st;
double c, ct;
} nut[] = {
{0, 0, 0, 0, 1, -171996.0, -174.2, 92025.0, 8.9},
{0, 0, 0, 0, 2, 2062.0, 0.2, -895.0, 0.5},
{-2, 0, 2, 0, 1, 46.0, 0.0, -24.0, 0.0},
{2, 0, -2, 0, 0, 11.0, 0.0, 0.0, 0.0},
{-2, 0, 2, 0, 2, -3.0, 0.0, 1.0, 0.0},
{1, -1, 0, -1, 0, -3.0, 0.0, 0.0, 0.0},
{0, -2, 2, -2, 1, -2.0, 0.0, 1.0, 0.0},
{2, 0, -2, 0, 1, 1.0, 0.0, 0.0, 0.0},
{0, 0, 2, -2, 2, -13187.0, -1.6, 5736.0, -3.1},
{0, 1, 0, 0, 0, 1426.0, -3.4, 54.0, -0.1},
{0, 1, 2, -2, 2, -517.0, 1.2, 224.0, -0.6},
{0, -1, 2, -2, 2, 217.0, -0.5, -95.0, 0.3},
{0, 0, 2, -2, 1, 129.0, 0.1, -70.0, 0.0},
{2, 0, 0, -2, 0, 48.0, 0.0, 1.0, 0.0},
{0, 0, 2, -2, 0, -22.0, 0.0, 0.0, 0.0},
{0, 2, 0, 0, 0, 17.0, -0.1, 0.0, 0.0},
{0, 1, 0, 0, 1, -15.0, 0.0, 9.0, 0.0},
{0, 2, 2, -2, 2, -16.0, 0.1, 7.0, 0.0},
{0, -1, 0, 0, 1, -12.0, 0.0, 6.0, 0.0},
{-2, 0, 0, 2, 1, -6.0, 0.0, 3.0, 0.0},
{0, -1, 2, -2, 1, -5.0, 0.0, 3.0, 0.0},
{2, 0, 0, -2, 1, 4.0, 0.0, -2.0, 0.0},
{0, 1, 2, -2, 1, 4.0, 0.0, -2.0, 0.0},
{1, 0, 0, -1, 0, -4.0, 0.0, 0.0, 0.0},
{2, 1, 0, -2, 0, 1.0, 0.0, 0.0, 0.0},
{0, 0, -2, 2, 1, 1.0, 0.0, 0.0, 0.0},
{0, 1, -2, 2, 0, -1.0, 0.0, 0.0, 0.0},
{0, 1, 0, 0, 2, 1.0, 0.0, 0.0, 0.0},
{-1, 0, 0, 1, 1, 1.0, 0.0, 0.0, 0.0},
{0, 1, 2, -2, 0, -1.0, 0.0, 0.0, 0.0},
{0, 0, 2, 0, 2, -2274.0, -0.2, 977.0, -0.5},
{1, 0, 0, 0, 0, 712.0, 0.1, -7.0, 0.0},
{0, 0, 2, 0, 1, -386.0, -0.4, 200.0, 0.0},
{1, 0, 2, 0, 2, -301.0, 0.0, 129.0, -0.1},
{1, 0, 0, -2, 0, -158.0, 0.0, -1.0, 0.0},
{-1, 0, 2, 0, 2, 123.0, 0.0, -53.0, 0.0},
{0, 0, 0, 2, 0, 63.0, 0.0, -2.0, 0.0},
{1, 0, 0, 0, 1, 63.0, 0.1, -33.0, 0.0},
{-1, 0, 0, 0, 1, -58.0, -0.1, 32.0, 0.0},
{-1, 0, 2, 2, 2, -59.0, 0.0, 26.0, 0.0},
{1, 0, 2, 0, 1, -51.0, 0.0, 27.0, 0.0},
{0, 0, 2, 2, 2, -38.0, 0.0, 16.0, 0.0},
{2, 0, 0, 0, 0, 29.0, 0.0, -1.0, 0.0},
{1, 0, 2, -2, 2, 29.0, 0.0, -12.0, 0.0},
{2, 0, 2, 0, 2, -31.0, 0.0, 13.0, 0.0},
{0, 0, 2, 0, 0, 26.0, 0.0, -1.0, 0.0},
{-1, 0, 2, 0, 1, 21.0, 0.0, -10.0, 0.0},
{-1, 0, 0, 2, 1, 16.0, 0.0, -8.0, 0.0},
{1, 0, 0, -2, 1, -13.0, 0.0, 7.0, 0.0},
{-1, 0, 2, 2, 1, -10.0, 0.0, 5.0, 0.0},
{1, 1, 0, -2, 0, -7.0, 0.0, 0.0, 0.0},
{0, 1, 2, 0, 2, 7.0, 0.0, -3.0, 0.0},
{0, -1, 2, 0, 2, -7.0, 0.0, 3.0, 0.0},
{1, 0, 2, 2, 2, -8.0, 0.0, 3.0, 0.0},
{1, 0, 0, 2, 0, 6.0, 0.0, 0.0, 0.0},
{2, 0, 2, -2, 2, 6.0, 0.0, -3.0, 0.0},
{0, 0, 0, 2, 1, -6.0, 0.0, 3.0, 0.0},
{0, 0, 2, 2, 1, -7.0, 0.0, 3.0, 0.0},
{1, 0, 2, -2, 1, 6.0, 0.0, -3.0, 0.0},
{0, 0, 0, -2, 1, -5.0, 0.0, 3.0, 0.0},
{1, -1, 0, 0, 0, 5.0, 0.0, 0.0, 0.0},
{2, 0, 2, 0, 1, -5.0, 0.0, 3.0, 0.0},
{0, 1, 0, -2, 0, -4.0, 0.0, 0.0, 0.0},
{1, 0, -2, 0, 0, 4.0, 0.0, 0.0, 0.0},
{0, 0, 0, 1, 0, -4.0, 0.0, 0.0, 0.0},
{1, 1, 0, 0, 0, -3.0, 0.0, 0.0, 0.0},
{1, 0, 2, 0, 0, 3.0, 0.0, 0.0, 0.0},
{1, -1, 2, 0, 2, -3.0, 0.0, 1.0, 0.0},
{-1, -1, 2, 2, 2, -3.0, 0.0, 1.0, 0.0},
{-2, 0, 0, 0, 1, -2.0, 0.0, 1.0, 0.0},
{3, 0, 2, 0, 2, -3.0, 0.0, 1.0, 0.0},
{0, -1, 2, 2, 2, -3.0, 0.0, 1.0, 0.0},
{1, 1, 2, 0, 2, 2.0, 0.0, -1.0, 0.0},
{-1, 0, 2, -2, 1, -2.0, 0.0, 1.0, 0.0},
{2, 0, 0, 0, 1, 2.0, 0.0, -1.0, 0.0},
{1, 0, 0, 0, 2, -2.0, 0.0, 1.0, 0.0},
{3, 0, 0, 0, 0, 2.0, 0.0, 0.0, 0.0},
{0, 0, 2, 1, 2, 2.0, 0.0, -1.0, 0.0},
{-1, 0, 0, 0, 2, 1.0, 0.0, -1.0, 0.0},
{1, 0, 0, -4, 0, -1.0, 0.0, 0.0, 0.0},
{-2, 0, 2, 2, 2, 1.0, 0.0, -1.0, 0.0},
{-1, 0, 2, 4, 2, -2.0, 0.0, 1.0, 0.0},
{2, 0, 0, -4, 0, -1.0, 0.0, 0.0, 0.0},
{1, 1, 2, -2, 2, 1.0, 0.0, -1.0, 0.0},
{1, 0, 2, 2, 1, -1.0, 0.0, 1.0, 0.0},
{-2, 0, 2, 4, 2, -1.0, 0.0, 1.0, 0.0},
{-1, 0, 4, 0, 2, 1.0, 0.0, 0.0, 0.0},
{1, -1, 0, -2, 0, 1.0, 0.0, 0.0, 0.0},
{2, 0, 2, -2, 1, 1.0, 0.0, -1.0, 0.0},
{2, 0, 2, 2, 2, -1.0, 0.0, 0.0, 0.0},
{1, 0, 0, 2, 1, -1.0, 0.0, 0.0, 0.0},
{0, 0, 4, -2, 2, 1.0, 0.0, 0.0, 0.0},
{3, 0, 2, -2, 2, 1.0, 0.0, 0.0, 0.0},
{1, 0, 2, -2, 0, -1.0, 0.0, 0.0, 0.0},
{0, 1, 2, 0, 1, 1.0, 0.0, 0.0, 0.0},
{-1, -1, 0, 2, 1, 1.0, 0.0, 0.0, 0.0},
{0, 0, -2, 0, 1, -1.0, 0.0, 0.0, 0.0},
{0, 0, 2, -1, 2, -1.0, 0.0, 0.0, 0.0},
{0, 1, 0, 2, 0, -1.0, 0.0, 0.0, 0.0},
{1, 0, -2, -2, 0, -1.0, 0.0, 0.0, 0.0},
{0, -1, 2, 0, 1, -1.0, 0.0, 0.0, 0.0},
{1, 1, 0, -2, 1, -1.0, 0.0, 0.0, 0.0},
{1, 0, -2, 2, 0, -1.0, 0.0, 0.0, 0.0},
{2, 0, 0, 2, 0, 1.0, 0.0, 0.0, 0.0},
{0, 0, 2, 4, 2, -1.0, 0.0, 0.0, 0.0},
{0, 1, 0, 1, 0, 1.0, 0.0, 0.0, 0.0}
};
// Return x modulo y [0,y)
double
modulo (double x, double y)
{
x = fmod (x, y);
if (x < 0.0)
x += y;
return x;
}
// Present nfd
void
nfd_now (char *s)
{
time_t rawtime;
struct tm *ptm;
// Get UTC time
time (&rawtime);
ptm = gmtime (&rawtime);
sprintf (s, "%04d-%02d-%02dT%02d:%02d:%02d", ptm->tm_year + 1900,
ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min,
ptm->tm_sec);
return;
}
// Compute Julian Day from Date
double
date2mjd (int year, int month, double day)
{
int a, b;
double jd;
if (month < 3)
{
year--;
month += 12;
}
a = floor (year / 100.);
b = 2. - a + floor (a / 4.);
if (year < 1582)
b = 0;
if (year == 1582 && month < 10)
b = 0;
if (year == 1582 && month == 10 && day <= 4)
b = 0;
jd =
floor (365.25 * (year + 4716)) + floor (30.6001 * (month + 1)) + day + b -
1524.5;
return jd - 2400000.5;
}
// nfd2mjd
double
nfd2mjd (char *date)
{
int year, month, day, hour, min, sec;
double mjd, dday;
sscanf (date, "%04d-%02d-%02dT%02d:%02d:%02d", &year, &month, &day, &hour,
&min, &sec);
dday = day + hour / 24.0 + min / 1440.0 + sec / 86400.0;
mjd = date2mjd (year, month, dday);
return mjd;
}
// Nutation
void
nutation (double mjd, double *dpsi, double *deps, double *eps)
{
int i;
double t, t2, t3;
double d, m, m1, f, n;
double arg;
// Julian centuries
t = (mjd - 51544.5) / 36525.0;
t2 = t * t;
t3 = t2 * t;
// Angles
d =
modulo (297.85036 + 445267.111480 * t - 0.0019142 * t2 + t3 / 189474.0,
360.0) * D2R;
m =
modulo (357.52772 + 35999.050340 * t - 0.0001603 * t2 - t3 / 300000.0,
360.0) * D2R;
m1 =
modulo (134.96298 + 477198.867398 * t + 0.0086972 * t2 + t3 / 56250.0,
360.0) * D2R;
f =
modulo (93.27191 + 483202.017538 * t - 0.0036825 * t2 + t3 / 327270.0,
360.0) * D2R;
n =
modulo (125.04452 - 1934.136261 * t + 0.0020708 * t2 + t3 / 450000.0,
360.0) * D2R;
// Compute sums
*dpsi = 0.0;
*deps = 0.0;
for (i = 0; i < 106; i++)
{
arg =
nut[i].nd * d + nut[i].nm * m + nut[i].nm1 * m1 + nut[i].nf * f +
nut[i].nn * n;
*dpsi += (nut[i].s + nut[i].st * t) * sin (arg);
*deps += (nut[i].c + nut[i].ct * t) * cos (arg);
}
*dpsi *= 0.0001 / 3600 * D2R;
*deps *= 0.0001 / 3600 * D2R;
*eps = -46.8150 * t - 0.00059 * t2 + 0.001813 * t3;
*eps = (23.4392911 + *eps / 3600.0) * D2R;
return;
}
// Precession
void
precess (double mjd0, double mjd, double *zeta, double *z, double *theta)
{
double t0, t;
// Time in centuries
t0 = (mjd0 - 51544.5) / 36525.0;
t = (mjd - mjd0) / 36525.0;
// Precession angles
*zeta = (2306.2181 + 1.39656 * t0 - 0.000139 * t0 * t0) * t;
*zeta += (0.30188 - 0.000344 * t0) * t * t + 0.017998 * t * t * t;
*zeta *= D2R / 3600.0;
*z = (2306.2181 + 1.39656 * t0 - 0.000139 * t0 * t0) * t;
*z += (1.09468 + 0.000066 * t0) * t * t + 0.018203 * t * t * t;
*z *= D2R / 3600.0;
*theta = (2004.3109 - 0.85330 * t0 - 0.000217 * t0 * t0) * t;
*theta += -(0.42665 + 0.000217 * t0) * t * t - 0.041833 * t * t * t;
*theta *= D2R / 3600.0;
return;
}
// Set identity matrix
void
identity_matrix (double a[3][3])
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (i == j)
a[i][j] = 1.0;
else
a[i][j] = 0.0;
}
}
return;
}
// Rotate around x-axis
void
rotate_x (double phi, double a[3][3])
{
double s, c, a10, a11, a12, a20, a21, a22;
s = sin (phi);
c = cos (phi);
a10 = c * a[1][0] + s * a[2][0];
a11 = c * a[1][1] + s * a[2][1];
a12 = c * a[1][2] + s * a[2][2];
a20 = -s * a[1][0] + c * a[2][0];
a21 = -s * a[1][1] + c * a[2][1];
a22 = -s * a[1][2] + c * a[2][2];
a[1][0] = a10;
a[1][1] = a11;
a[1][2] = a12;
a[2][0] = a20;
a[2][1] = a21;
a[2][2] = a22;
return;
}
// Rotate around y-axis
void
rotate_y (double phi, double a[3][3])
{
double s, c, a00, a01, a02, a20, a21, a22;
s = sin (phi);
c = cos (phi);
a00 = c * a[0][0] - s * a[2][0];
a01 = c * a[0][1] - s * a[2][1];
a02 = c * a[0][2] - s * a[2][2];
a20 = s * a[0][0] + c * a[2][0];
a21 = s * a[0][1] + c * a[2][1];
a22 = s * a[0][2] + c * a[2][2];
a[0][0] = a00;
a[0][1] = a01;
a[0][2] = a02;
a[2][0] = a20;
a[2][1] = a21;
a[2][2] = a22;
return;
}
// Rotate around z-axis
void
rotate_z (double phi, double a[3][3])
{
double s, c, a00, a01, a02, a10, a11, a12;
s = sin (phi);
c = cos (phi);
a00 = c * a[0][0] + s * a[1][0];
a01 = c * a[0][1] + s * a[1][1];
a02 = c * a[0][2] + s * a[1][2];
a10 = -s * a[0][0] + c * a[1][0];
a11 = -s * a[0][1] + c * a[1][1];
a12 = -s * a[0][2] + c * a[1][2];
a[0][0] = a00;
a[0][1] = a01;
a[0][2] = a02;
a[1][0] = a10;
a[1][1] = a11;
a[1][2] = a12;
return;
}
// Matrix multiply
void
matrix_multiply (double a[3][3], double b[3][3], double c[3][3])
{
int i, j, k;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
c[i][j] = 0.0;
for (k = 0; k < 3; k++)
c[i][j] += a[i][k] * b[k][j];
}
}
return;
}
// Vector multiply
void
vector_multiply_in_place (double a[3][3], double b[3])
{
int i, j, k;
double c[3];
for (i = 0; i < 3; i++)
{
c[i] = 0.0;
for (j = 0; j < 3; j++)
c[i] += a[i][j] * b[j];
}
for (i = 0; i < 3; i++)
b[i] = c[i];
return;
}
// Vector multiply
void
vector_multiply (double a[3][3], double b[3], double c[3])
{
int i, j, k;
for (i = 0; i < 3; i++)
{
c[i] = 0.0;
for (j = 0; j < 3; j++)
c[i] += a[i][j] * b[j];
}
return;
}
// Transpose
void
matrix_transpose (double a[3][3], double b[3][3])
{
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
b[i][j] = a[j][i];
return;
}
// Dot product
double
dot_product (double a[3], double b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
// Magnitude
double
magnitude (double a[3])
{
return sqrt (dot_product (a, a));
}
// Cross product
void
cross_product (double a[3], double b[3], double c[3])
{
c[0] = a[1] * b[2] - a[2] * b[1];
c[1] = a[2] * b[0] - a[0] * b[2];
c[2] = a[0] * b[1] - a[1] * b[0];
return;
}
// ICRS to TEME conversion
void
icrs_to_teme (double mjd, double a[3][3])
{
int i, j;
double dpsi, deps, eps, z, theta, zeta, h;
double p[3][3], n[3][3], q[3][3], b[3][3];
// Precession
precess (51544.5, mjd, &zeta, &z, &theta);
identity_matrix (p);
rotate_z (-zeta, p);
rotate_y (theta, p);
rotate_z (-z, p);
// Nutation
nutation (mjd, &dpsi, &deps, &eps);
identity_matrix (n);
rotate_x (eps, n);
rotate_z (-dpsi, n);
rotate_x (-eps - deps, n);
// Equation of equinoxes
identity_matrix (q);
rotate_z (dpsi * cos (eps + deps), q);
// Multiply matrices (left to right)
matrix_multiply (q, n, b);
matrix_multiply (b, p, a);
return;
}
void
usage (void)
{
printf ("tle2rv c:i:t:m:efh\n\n");
printf ("-c Catalog to load [classfd.tle]\n");
printf ("-i Object to convert [all]\n");
printf ("-t Epoch (YYYY-mm-ddThh:mm:ss)\n");
printf ("-m Epoch (MJD)\n");
printf ("-e Use TLE epoch\n");
printf ("-j J2000 output\n");
printf ("-g GMAT output (J2000)\n");
printf ("-h This help\n");
return;
}
int
main (int argc, char *argv[])
{
int imode, arg, satno = 0, useepoch = 0, format = 0, gmat = 0;
FILE *file;
char *env;
char tlefile[LIM], nfd[32];
double mjd;
xyz_t r, v;
orbit_t orb;
double rr[3], vv[3], e[3][3], et[3][3];
// Get environment variable
env = getenv ("ST_TLEDIR");
sprintf (tlefile, "%s/classfd.tle", env);
// Set date
nfd_now (nfd);
mjd = nfd2mjd (nfd);
// Decode options
while ((arg = getopt (argc, argv, "c:i:t:m:hejg")) != -1)
{
switch (arg)
{
case 't':
strcpy (nfd, optarg);
mjd = nfd2mjd (nfd);
break;
case 'm':
mjd = atof (optarg);
break;
case 'e':
useepoch = 1;
break;
case 'j':
format = 1;
break;
case 'g':
gmat = 1;
break;
case 'c':
strcpy (tlefile, optarg);
break;
case 'i':
satno = atoi (optarg);
break;
case 'h':
usage ();
return 0;
break;
default:
usage ();
return 0;
}
}
// Open file
file = fopen (tlefile, "r");
while (read_twoline (file, satno, &orb) == 0)
{
// Propagate
imode = init_sgdp4 (&orb);
// Use epoch instead of user supplied date
if (useepoch == 1)
mjd = SGDP4_jd0 - 2400000.5;
// Compute position and velocity
imode = satpos_xyz (mjd + 2400000.5, &r, &v);
// Output
if (format == 0 && gmat == 0)
printf ("%05d %14.8lf %f %f %f %f %f %f TEME\n", orb.satno, mjd, r.x,
r.y, r.z, v.x, v.y, v.z);
// To vectors
rr[0] = r.x;
rr[1] = r.y;
rr[2] = r.z;
vv[0] = v.x;
vv[1] = v.y;
vv[2] = v.z;
// Matrices
icrs_to_teme (mjd, e);
matrix_transpose (e, et);
// Transform
vector_multiply_in_place (et, rr);
vector_multiply_in_place (et, vv);
// Output J2000
if (format == 1 && gmat == 0)
printf ("%05d %14.8lf %f %f %f %f %f %f J2000\n", orb.satno, mjd,
rr[0], rr[1], rr[2], vv[0], vv[1], vv[2]);
// GMAT output
if (gmat == 1)
{
printf ("UTCModJulian = %14.8lf\n", mjd - 29999.5);
printf ("CoordinateSystem = EarthMJ2000Eq\n");
printf ("X = %lf\n", rr[0]);
printf ("Y = %lf\n", rr[1]);
printf ("Z = %lf\n", rr[2]);
printf ("VX = %lf\n", vv[0]);
printf ("VY = %lf\n", vv[1]);
printf ("VZ = %lf\n", vv[2]);
}
}
fclose (file);
return 0;
}