1
0
Fork 0
sattools/src/skymap.c

3977 lines
85 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <getopt.h>
#include <ctype.h>
#include <cpgplot.h>
#include <wcslib/cel.h>
#include "sgdp4h.h"
#include <giza.h>
#define LIM 384
#define MMAX 1024
#define D2R M_PI/180.0
#define R2D 180.0/M_PI
#define XKMPER 6378.135 // Earth radius in km
#define XKMPAU 149597879.691 // AU in km
#define FLAT (1.0/298.257)
#define STDMAG 6.0
long Isat = 0;
long Isatsel = 0;
extern double SGDP4_jd0;
struct map
{
double alpha0, delta0, ra0, de0, azi0, alt0, q;
double fov, mjd, gmst, w, wl, wb;
float length;
float minmag, maxmag, minrad, maxrad;
char orientation[LIM], projection[4], observer[32], camera[16];
char nfd[LIM], starfile[LIM], tlefile[LIM], iodfile[LIM], xyzfile[LIM];
char datadir[LIM], tledir[LIM];
float saltmin;
double lat, lng;
double h, sra, sde, sazi, salt;
float alt, timezone;
float fw, fh, agelimit;
int level, grid, site_id, plotstars, plotapex;
int leoflag, iodflag, iodpoint, visflag, planar, pssatno, psnr, xyzflag,
pflag, graves;
float psrmin, psrmax, rvis, width, height, nmax;
} m;
struct sat
{
long Isat;
char state[10];
float mag, age;
double jd;
double dx, dy, dz;
double x, y, z, vx, vy, vz;
double rsun, rearth, h;
double psun, pearth, p, phase;
double r, v, ra, de, vang;
double azi, alt, salt;
double rx, ry;
double rg, vg, azig, altg, rag, deg;
int illumg;
};
struct star
{
double ra, de;
float pmra, pmde;
float mag;
};
struct observation
{
int ssn, site;
char iod_line[LIM];
double mjd, ra, de, azi, alt;
double lng, lat;
float elv;
float dt, st, dr, sr, dx, dy, t;
int flag;
};
struct coeff_lr
{
int nd, nm, nm1, nf;
double sa, ca;
} clr[60];
struct coeff_b
{
int nd, nm, nm1, nf;
double sa;
} cb[60];
int fgetline (FILE *, char *, int);
double modulo (double, double);
void reverse (double, double, double *, double *);
void forward (double, double, double *, double *);
void init_plot (char *, float, float);
void skymap_plot_renew (void);
double gmst (double);
double dgmst (double);
void skymap_plothorizontal_grid ();
void skymap_plotequatorial_grid ();
void skymap_plotconstellations (char *);
void equatorial2horizontal (double, double, double, double *, double *);
void graves_equatorial2horizontal (double, double, double, double *,
double *);
void graves_horizontal2equatorial (double, double, double, double *,
double *);
void horizontal2equatorial (double, double, double, double *, double *);
void skymap_plotstars (char *);
void obspos_xyz (double, xyz_t *, xyz_t *);
void sunpos_xyz (double, xyz_t *, double *, double *);
void graves_xyz (double, xyz_t *, xyz_t *);
void skymap_plotsatellite (char *, int, double, double);
double date2mjd (int, int, double);
struct sat apparent_position (double);
long identify_satellite (char *, int, double, float, float);
int plot_skymap (void);
void rotate (int, float, float *, float *, float *);
int print_tle (char *, int);
void mjd2date (double mjd, char *date);
void dec2s (double x, char *s, int f, int len);
void precess (double mjd0, double ra0, double de0, double mjd, double *ra,
double *de);
double nfd2mjd (char *date);
void nfd_now (char *s);
double s2dec (char *s);
double doy2mjd (int year, double doy);
struct observation decode_iod_observation (char *iod_line);
void plot_iod (char *filename);
void get_site (int site_id);
void lunpos_xyz (double mjd, xyz_t * pos, double *ra, double *de);
void ecliptical2equatorial (double l, double b, double *ra, double *de);
void skymap_plotsun (void);
void skymap_plotmoon (void);
void mjd2date_iod (double mjd, char *date);
void dec2s_iod (double x, char *s, int type);
int giza_open_device_size_float (const char *, const char *, float, float,
int);
void
usage ()
{
printf ("Usage: skymap [OPTION]\n");
printf ("Visualize satellites on a map of the sky.\n\n");
printf
("-t, --time Date/time (yyyy-mm-ddThh:mm:ss.sss) [default: now]\n");
printf ("-c, --catalog TLE catalog file [default: satnogs.tle]\n");
printf ("-i, --id Satellite ID (NORAD) [default: all]\n");
printf ("-R, --ra R.A. [hh:mm:ss.sss]\n");
printf ("-D, --decl Decl. [+dd:mm:ss.ss]\n");
printf ("-A, --azimuth Azimuth (deg)\n");
printf ("-E, --elevation Elevation (deg)\n");
printf ("-w, --width Screen width\n");
printf ("-g, --height Screen height\n");
printf ("-n, --nmax nmax line resolution/speed (default 128)\n");
printf ("-S, --all-night All night\n");
printf ("-Q, --no-stars No stars\n");
printf
("-a, --all-objects Show all objects from catalog (default: LEO)\n");
printf ("-h, --help This help\n");
printf ("-s, --site Site (COSPAR)\n");
printf ("-d, --iod IOD observations\n");
printf ("-l, --length Trail length [default: 60s]\n");
printf ("-P, --planar-id planar search satellite ID\n");
printf ("-r, --planar-alt planar search altitude\n");
printf ("-V, --visibility-alt altitude for visibility contours\n");
printf ("-p, --positions-file File with xyz positions\n");
printf ("-L, --longitude manual site longitude (deg)\n");
printf ("-B, --latitude manual site latitude (deg)\n");
printf ("-H, --elevation manual site elevation (m)\n");
return;
}
void
interactive_usage ()
{
printf ("i Identify satellite\n");
printf ("\n");
printf ("f Select satellite\n");
printf ("a Select on age\n");
printf ("m Measure cursor RA/Dec, Alt/Azi\n");
printf ("\n");
printf ("G Toggle graves visibility (on/off)\n");
printf ("g Toggle grid (on/off)\n");
printf ("o Toggle orientation (horizontal/equatorial)\n");
printf ("P Toggle planar search\n");
printf ("p Toggle satellite name\n");
printf ("L Toggle satellite selection (All, LEO, HEO/GEO, none)\n");
printf ("v Toggle visibility contours\n");
printf ("F Toggle camera configuration (data/cameras.txt)\n");
printf ("Q Toggle plotting stars\n");
printf ("x Toggle plotting apex (GEO, HEO, NOSS)\n");
printf ("\n");
printf ("c Center on cursor\n");
printf ("z Center on zenith\n");
printf ("n Center on North\n");
printf ("s Center on South\n");
printf ("e Center on East\n");
printf ("w Center on West\n");
printf ("\n");
printf ("1-9 Zoom level\n");
printf ("+ Zoom in one level\n");
printf ("- Zoom out one level\n");
printf ("\n");
printf ("l Set integration length\n");
printf ("> Increase step size\n");
printf ("< Decrease step size\n");
printf ("\n");
printf (". Increase time by 1 step\n");
printf (", Decrease time by 1 step\n");
printf ("\n");
printf ("I Create IOD measurement for current time and position\n");
printf ("TAB Cycle IOD observations\n");
printf ("\n");
printf ("S Save observation position/time to schedule\n");
printf ("E Save observation end-time to schedule\n");
printf ("\n");
printf ("R Read catalog\n");
printf ("r Reset satellite selection/real time\n");
printf ("\n");
printf ("q quit\n");
}
void
init_skymap (void)
{
int i;
char *env, filename[128];
FILE *file;
// Default Map parameters
m.azi0 = 180;
m.alt0 = 90.0;
m.w = 120.0;
m.wl = 180.0;
m.wb = 180.0;
m.level = 1;
m.minmag = -2.0;
m.maxmag = 5.0;
m.maxrad = 2.0;
m.minrad = 0.02;
strcpy (m.orientation, "horizontal");
strcpy (m.starfile, "hip6mag.dat");
strcpy (m.projection, "STG");
m.lat = 0.0;
m.lng = 0.0;
m.alt = 0.0;
m.timezone = +0.0;
m.grid = 1;
m.length = 60.0;
m.mjd = -1.0;
m.leoflag = 1;
m.iodflag = 0;
m.xyzflag = 0;
m.visflag = 0;
m.planar = 0;
m.agelimit = -1.0;
m.saltmin = -6.0;
m.pflag = 1;
m.graves = 0;
m.plotstars = 1;
m.plotapex = 1;
m.width = 800;
m.height = 600;
m.nmax = 128;
// Default settings
strcpy (m.observer, "Unknown");
m.site_id = 0;
// Get environment variables
env = getenv ("ST_DATADIR");
if (env != NULL)
{
strcpy (m.datadir, env);
}
else
{
printf ("ST_DATADIR environment variable not found.\n");
}
env = getenv ("ST_COSPAR");
if (env != NULL)
{
get_site (atoi (env));
}
else
{
printf ("ST_COSPAR environment variable not found.\n");
}
env = getenv ("ST_TLEDIR");
if (env != NULL)
{
strcpy (m.tledir, env);
}
else
{
printf ("ST_TLEDIR environment variable not found.\n");
}
sprintf (m.tlefile, "%s/satnogs.tle", m.tledir);
// Read LR coefficients
sprintf (filename, "%s/data/moonLR.dat", m.datadir);
file = fopen (filename, "r");
for (i = 0; i < 60; i++)
fscanf (file, "%d %d %d %d %lf %lf", &clr[i].nd, &clr[i].nm, &clr[i].nm1,
&clr[i].nf, &clr[i].sa, &clr[i].ca);
fclose (file);
// Read B coefficients
sprintf (filename, "%s/data/moonB.dat", m.datadir);
file = fopen (filename, "r");
for (i = 0; i < 60; i++)
fscanf (file, "%d %d %d %d %lf", &cb[i].nd, &cb[i].nm, &cb[i].nm1,
&cb[i].nf, &cb[i].sa);
fclose (file);
return;
}
// Get observing site
void
get_site (int site_id)
{
int i = 0;
char line[LIM];
FILE *file;
int id;
double lat, lng;
float alt;
char abbrev[3], observer[64], filename[LIM];
sprintf (filename, "%s/data/sites.txt", m.datadir);
file = fopen (filename, "r");
if (file == NULL)
{
printf ("File with site information not found!\n");
return;
}
while (fgets (line, LIM, file) != NULL)
{
// Skip
if (strstr (line, "#") != NULL)
continue;
// Strip newline
line[strlen (line) - 1] = '\0';
// Read data
sscanf (line, "%4d %2s %lf %lf %f", &id, abbrev, &lat, &lng, &alt);
strcpy (observer, line + 38);
// Change to km
alt /= 1000.0;
if (id == site_id)
{
m.lat = lat;
m.lng = lng;
m.alt = alt;
m.site_id = id;
strcpy (m.observer, observer);
}
}
fclose (file);
return;
}
void
read_iod (char *filename, int iobs)
{
int i = 0;
char line[LIM];
FILE *file;
struct observation obs;
file = fopen (filename, "r");
// Read data
while (fgets (line, LIM, file) != NULL)
{
if (strlen (line) < 10)
continue;
if (strstr (line, "#") == NULL)
{
obs = decode_iod_observation (line);
if (i == iobs)
{
printf ("%s\n", obs.iod_line);
break;
}
i++;
}
}
fclose (file);
// Set parameters
get_site (obs.site);
m.mjd = obs.mjd;
m.ra0 = obs.ra;
m.de0 = obs.de;
strcpy (m.orientation, "equatorial");
m.level = 4;
return;
}
void
plot_apex (float h, float beta)
{
int i;
xyz_t obspos, obsvel;
xyz_t satpos;
double rr, theta, dx, dy, dz, r, ra, de, azi, alt, rx, ry;
obspos_xyz (m.mjd, &obspos, &obsvel);
rr = h + XKMPER;
cpgsci (3);
for (theta = 0.0; theta <= 360.0; theta += 1.0)
{
satpos.x = rr * cos (theta * D2R) * cos (beta * D2R);
satpos.y = rr * sin (theta * D2R) * cos (beta * D2R);
satpos.z = rr * sin (beta * D2R);
// Position differences
dx = satpos.x - obspos.x;
dy = satpos.y - obspos.y;
dz = satpos.z - obspos.z;
// Celestial position
r = sqrt (dx * dx + dy * dy + dz * dz);
ra = modulo (atan2 (dy, dx) * R2D, 360.0);
de = asin (dz / r) * R2D;
// Convert and project
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
if (theta == 0.0)
cpgmove ((float) rx, (float) ry);
else
{
cpgdraw ((float) rx, (float) ry);
cpgmove ((float) rx, (float) ry);
}
}
cpgsci (1);
return;
}
// Plot XYZ point
void
plot_xyz (double mjd0, char *filename)
{
struct sat s;
double jd, rsun, rearth, rsat;
double dx, dy, dz, dvx, dvy, dvz;
xyz_t satpos, obspos, obsvel, satvel, sunpos;
double sra, sde, mjd, mjd1;
FILE *file;
char line[LIM];
file = fopen (filename, "r");
while (fgetline (file, line, LIM) > 0)
{
sscanf (line, "%lf %lf %lf %lf", &mjd, &satpos.x, &satpos.y, &satpos.z);
if (mjd > mjd0)
break;
}
fclose (file);
// Get positions
obspos_xyz (mjd0, &obspos, &obsvel);
sunpos_xyz (mjd0, &sunpos, &sra, &sde);
// Age
s.age = 0.0;
// Sat positions
s.x = satpos.x;
s.y = satpos.y;
s.z = satpos.z;
s.vx = satvel.x;
s.vy = satvel.y;
s.vz = satvel.z;
// Sun position from satellite
dx = -satpos.x + sunpos.x;
dy = -satpos.y + sunpos.y;
dz = -satpos.z + sunpos.z;
// Distances
rsun = sqrt (dx * dx + dy * dy + dz * dz);
rearth =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y + satpos.z * satpos.z);
s.h = rearth - XKMPER;
// Angles
s.psun = asin (696.0e3 / rsun) * R2D;
s.pearth = asin (6378.135 / rearth) * R2D;
s.p =
acos ((-dx * satpos.x - dy * satpos.y -
dz * satpos.z) / (rsun * rearth)) * R2D;
// Visibility state
if (s.p - s.pearth < -s.psun)
strcpy (s.state, "eclipsed");
else if (s.p - s.pearth > -s.psun && s.p - s.pearth < s.psun)
strcpy (s.state, "umbra");
else if (s.p - s.pearth > s.psun)
strcpy (s.state, "sunlit");
// Position differences
dx = satpos.x - obspos.x;
dy = satpos.y - obspos.y;
dz = satpos.z - obspos.z;
dvx = satvel.x - obsvel.x;
dvy = satvel.y - obsvel.y;
dvz = satvel.z - obsvel.z;
// Celestial position
s.r = sqrt (dx * dx + dy * dy + dz * dz);
s.v = (dvx * dx + dvy * dy + dvz * dz) / s.r;
s.ra = modulo (atan2 (dy, dx) * R2D, 360.0);
s.de = asin (dz / s.r) * R2D;
// Phase
s.phase =
acos (((obspos.x - satpos.x) * (sunpos.x - satpos.x) +
(obspos.y - satpos.y) * (sunpos.y - satpos.y) + (obspos.z -
satpos.z) *
(sunpos.z - satpos.z)) / (rsun * s.r)) * R2D;
// Magnitude
if (strcmp (s.state, "sunlit") == 0)
s.mag =
STDMAG - 15.0 + 5 * log10 (s.r) - 2.5 * log10 (sin (s.phase * D2R) +
(M_PI -
s.phase * D2R) *
cos (s.phase * D2R));
else
s.mag = 15;
// Convert and project
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (mjd, s.ra, s.de, &s.azi, &s.alt);
forward (s.azi, s.alt, &s.rx, &s.ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (s.ra, s.de, &s.rx, &s.ry);
}
cpgsci (3);
cpgpt1 (s.rx, s.ry, 17);
cpgsch (0.6);
cpgtext (s.rx, s.ry, " xyz");
cpgsch (1.0);
cpgsci (1);
printf ("%s %6.3f %6.3f %.1f km\n", m.nfd, s.ra, s.de, s.r);
return;
}
// Write out the current position and time in IOD format
void
format_iod (double mjd, double ra, double de, int site)
{
char nfd[32];
double mjd0, ra0, de0;
char sra[16], sde[16];
// Get date/time
mjd2date_iod (mjd, nfd);
// Precess position to J2000
mjd0 = 51544.5;
precess (mjd, ra, de, mjd0, &ra0, &de0);
dec2s_iod (ra0 / 15.0, sra, 0);
dec2s_iod (de0, sde, 1);
// Print IOD line
printf ("99999 99 999A %04d G %s 17 25 %s%s 37 S\n", site, nfd, sra, sde);
return;
}
void
allnight (void)
{
int flag;
xyz_t sunpos;
double ra, de, azi, alt, alt0;
double mjd, mjdrise = -1.0, mjdset = -1.0;
char nfd[32];
// Find solar altitude at reference time
sunpos_xyz (m.mjd, &sunpos, &ra, &de);
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
// Sun below limit, find rise, then set
if (alt < m.saltmin)
{
for (flag = 0, mjd = m.mjd; mjd < m.mjd + 0.5; mjd += 1.0 / 86400)
{
sunpos_xyz (mjd, &sunpos, &ra, &de);
equatorial2horizontal (mjd, ra, de, &azi, &alt);
if (flag != 0)
{
if (alt > m.saltmin && alt0 <= m.saltmin)
mjdrise = mjd;
}
if (flag == 0)
flag = 1;
alt0 = alt;
}
for (flag = 0, mjd = m.mjd - 0.5; mjd < m.mjd; mjd += 1.0 / 86400)
{
sunpos_xyz (mjd, &sunpos, &ra, &de);
equatorial2horizontal (mjd, ra, de, &azi, &alt);
if (flag != 0)
{
if (alt < m.saltmin && alt0 >= m.saltmin)
mjdset = mjd;
}
if (flag == 0)
flag = 1;
alt0 = alt;
}
// Sun above limit, find set, and rise
}
else
{
for (flag = 0, mjd = m.mjd; mjd < m.mjd + 1.0; mjd += 1.0 / 86400)
{
sunpos_xyz (mjd, &sunpos, &ra, &de);
equatorial2horizontal (mjd, ra, de, &azi, &alt);
if (flag != 0)
{
if (alt > m.saltmin && alt0 <= m.saltmin)
mjdrise = mjd;
if (alt < m.saltmin && alt0 >= m.saltmin)
mjdset = mjd;
}
if (flag == 0)
flag = 1;
alt0 = alt;
}
}
m.mjd = mjdset;
mjd2date (m.mjd, m.nfd);
mjd2date (mjdrise, nfd);
printf ("%s %s\n", m.nfd, nfd);
return;
}
static int verbose_flag;
int
main (int argc, char *argv[])
{
int i, arg = 0, isite = 0;
double lat, lng;
float alt;
init_skymap ();
int c;
while (1)
{
static struct option long_options[] = {
{"time", required_argument, 0, 't'},
{"catalog", required_argument, 0, 'c'},
{"id", required_argument, 0, 'i'},
{"ra", required_argument, 0, 'R'},
{"decl", required_argument, 0, 'D'},
{"azimuth", required_argument, 0, 'A'},
{"elevation", required_argument, 0, 'E'},
{"site", required_argument, 0, 's'},
{"width", required_argument, 0, 'w'},
{"height", required_argument, 0, 'g'},
{"nmax", required_argument, 0, 'n'},
{"length", required_argument, 0, 'l'},
{"planar-id", required_argument, 0, 'P'},
{"planar-alt", required_argument, 0, 'r'},
{"visibility-alt", required_argument, 0, 'V'},
{"positions-file", required_argument, 0, 'p'},
{"longitude", required_argument, 0, 'L'},
{"latitude", required_argument, 0, 'B'},
{"elevation", required_argument, 0, 'H'},
{"iod", required_argument, 0, 'd'},
{"size", required_argument, 0, 'z'},
{"all-night", no_argument, 0, 'S'},
{"no-stars", no_argument, 0, 'Q'},
{"all-objects", no_argument, 0, 'a'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
int option_index = 0;
c =
getopt_long (argc, argv,
"t:c:i:R:D:A:E:s:w:g:n:l:P:r:V:p:L:B:H:d:SQah",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 't':
strcpy (m.nfd, optarg);
m.mjd = nfd2mjd (m.nfd);
m.iodpoint = -1;
break;
case 'S':
m.saltmin = atof (optarg);
allnight ();
break;
case 'L':
lng = (double) atof (optarg);
isite++;
break;
case 'B':
lat = (double) atof (optarg);
isite++;
break;
case 'H':
alt = atof (optarg);
isite++;
break;
case 'c':
strcpy (m.tlefile, optarg);
break;
case 'd':
strcpy (m.iodfile, optarg);
m.iodpoint = 0;
m.leoflag = 0;
read_iod (m.iodfile, m.iodpoint);
m.iodflag = 1;
m.level = 6;
break;
case 'l':
m.length = atof (optarg);
break;
case 's':
get_site (atoi (optarg));
break;
case 'i':
Isatsel = atoi (optarg);
m.leoflag = 0;
break;
case 'P':
m.planar = 1;
m.pssatno = atoi (optarg);
m.psrmin = 300;
m.psrmax = 1000;
m.psnr = 8;
break;
case 'p':
strcpy (m.xyzfile, optarg);
m.xyzflag = 1;
break;
case 'r':
m.psrmin = atof (optarg);
m.psrmax = atof (optarg);
m.psnr = 1;
break;
case 'V':
m.visflag = 1;
m.rvis = atof (optarg);
break;
case 'R':
m.ra0 = 15.0 * s2dec (optarg);
strcpy (m.orientation, "equatorial");
m.level = 5;
break;
case 'D':
m.de0 = s2dec (optarg);
strcpy (m.orientation, "equatorial");
m.level = 5;
break;
case 'A':
m.azi0 = modulo (atof (optarg) + 180.0, 360.0);
strcpy (m.orientation, "horizontal");
m.level = 3;
break;
case 'E':
m.alt0 = atof (optarg);
if (m.alt0 > 90.0)
m.alt0 = 90.0;
strcpy (m.orientation, "horizontal");
m.level = 3;
break;
case 'w':
m.width = atof (optarg);
break;
case 'g':
m.height = atof (optarg);
break;
case 'n':
m.nmax = atof (optarg);
break;
case 'Q':
m.plotstars = 0;
break;
case 'a':
m.leoflag = 0;
break;
case 'h':
usage ();
return 0;
break;
default:
abort ();
}
}
if (verbose_flag)
puts ("verbose flag is set");
if (optind < argc)
{
printf ("Invalid argument: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
abort ();
}
// Set manual site
if (isite == 3)
{
m.lat = lat;
m.lng = lng;
m.alt = alt / 1000.0;
m.site_id = 0;
strcpy (m.observer, "Manual observer");
}
init_plot ("/xs", m.width, m.height);
plot_skymap ();
cpgend ();
return 0;
}
void
plot_graves_visibility (void)
{
int i, j, k, nx = 32, ny = 8;
double azi, alt, ra, de;
double ax, ay, az, dr, dx, dy, dz, h, r, r1, r2, rx, ry;
xyz_t grvpos, grvvel, satpos, obspos, obsvel;
float azil[] =
{ -90, -80, -70, -60, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60,
70, 80, 90, 90, 90, 90, 90, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0, -10,
-20, -30,
-40, -50, -60, -70, -80, -90, -90, -90, -90, -90, -90
};
float altl[] =
{ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 20, 25, 30, 35, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40,
40, 40, 40, 35, 30, 25, 20, 15
};
// Get observer and solar position
graves_xyz (m.mjd, &grvpos, &grvvel);
obspos_xyz (m.mjd, &obspos, &obsvel);
cpgsci (2);
for (h = 300; h <= 1200; h += 100)
{
for (i = 0; i < sizeof (azil) / sizeof (azil[0]); i++)
{
graves_horizontal2equatorial (m.mjd, azil[i], altl[i], &ra, &de);
// Compute unit vector
ax = cos (ra * D2R) * cos (de * D2R);
ay = sin (ra * D2R) * cos (de * D2R);
az = sin (de * D2R);
// Find distance
for (k = 0, r1 = h; k < 20; k++)
{
dx = r1 * ax;
dy = r1 * ay;
dz = r1 * az;
satpos.x = grvpos.x + dx;
satpos.y = grvpos.y + dy;
satpos.z = grvpos.z + dz;
r =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y +
satpos.z * satpos.z);
dr = h + XKMPER - r;
if (dr < 1.0)
break;
r1 += dr;
}
// Compute observer distance
dx = satpos.x - obspos.x;
dy = satpos.y - obspos.y;
dz = satpos.z - obspos.z;
r2 = sqrt (dx * dx + dy * dy + dz * dz);
ra = modulo (atan2 (dy, dx) * R2D, 360.0);
de = asin (dz / r2) * R2D;
// Convert and project
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
if (i == 0)
cpgmove (rx, ry);
else
{
cpgdraw (rx, ry);
cpgmove (rx, ry);
}
}
}
cpgsci (1);
return;
}
// Plot visibility contours
void
plot_visibility (float h)
{
int i, j, k, nx = 300, ny = 200, nc;
float xmin, xmax, ymin, ymax;
double rx, ry, azi, alt, ra, de;
xyz_t obspos, obsvel, satpos, sunpos;
double dx, dy, dz, r, ax, ay, az, d, dr, sra, sde;
float rsun, rearth, psun, pearth, p, phase, mag;
char state[10];
float *cont, cmax;
float tr[6];
float c[] =
{ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0
};
// Allocate
cont = (float *) malloc (sizeof (float) * nx * ny);
// Limits
xmin = -1.5 * m.w;
xmax = 1.5 * m.w;
ymin = -m.w;
ymax = m.w;
// Transformation matrix
tr[2] = 0.0;
tr[1] = (xmax - xmin) / (float) nx;
tr[0] = xmin - 0.5 * tr[1];
tr[4] = 0.0;
tr[5] = (ymax - ymin) / (float) ny;
tr[3] = ymin - 0.5 * tr[5];
// Get observer and solar position
obspos_xyz (m.mjd, &obspos, &obsvel);
sunpos_xyz (m.mjd, &sunpos, &sra, &sde);
for (i = 0; i < nx; i++)
{
rx = xmin + (xmax - xmin) * (double) i / (double) (nx - 1);
for (j = 0; j < ny; j++)
{
ry = ymin + (ymax - ymin) * (double) j / (double) (ny - 1);
reverse (rx, ry, &azi, &alt);
// Skip low elevations
if (alt <= 0.0)
{
mag = 15.0;
}
else
{
horizontal2equatorial (m.mjd, azi, alt, &ra, &de);
// Compute unit vector
ax = cos (ra * D2R) * cos (de * D2R);
ay = sin (ra * D2R) * cos (de * D2R);
az = sin (de * D2R);
// Find distance
for (k = 0, d = h; k < 20; k++)
{
dx = d * ax;
dy = d * ay;
dz = d * az;
satpos.x = obspos.x + dx;
satpos.y = obspos.y + dy;
satpos.z = obspos.z + dz;
r =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y +
satpos.z * satpos.z);
dr = h + XKMPER - r;
if (dr < 1.0)
break;
d += dr;
}
// Sun position from satellite
dx = -satpos.x + sunpos.x;
dy = -satpos.y + sunpos.y;
dz = -satpos.z + sunpos.z;
// Distances
rsun = sqrt (dx * dx + dy * dy + dz * dz);
rearth =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y +
satpos.z * satpos.z);
// Angles
psun = asin (696.0e3 / rsun) * R2D;
pearth = asin (6378.135 / rearth) * R2D;
p =
acos ((-dx * satpos.x - dy * satpos.y -
dz * satpos.z) / (rsun * rearth)) * R2D;
p -= pearth;
// Visibility
if (p < -psun)
{
strcpy (state, "eclipsed");
cpgsci (14);
}
else if (p > -psun && p < psun)
{
strcpy (state, "umbra");
cpgsci (15);
}
else if (p > psun)
{
strcpy (state, "sunlit");
cpgsci (7);
}
// Phase
phase =
acos (((obspos.x - satpos.x) * (sunpos.x - satpos.x) +
(obspos.y - satpos.y) * (sunpos.y - satpos.y) +
(obspos.z - satpos.z) * (sunpos.z -
satpos.z)) / (rsun * d)) *
R2D;
// Magnitude
if (strcmp (state, "sunlit") == 0)
mag =
STDMAG - 15.0 + 5 * log10 (d) -
2.5 * log10 (sin (phase * D2R) +
(M_PI - phase * D2R) * cos (phase * D2R));
else
mag = 15;
}
k = i + nx * j;
cont[k] = mag;
}
}
// Find maximum contour value
for (i = 0, j = 0; i < nx * ny; i++)
{
if (cont[i] < 15.0)
{
if (j == 0 || cont[i] > cmax)
cmax = cont[i];
j++;
}
}
nc = (int) cmax + 1.0;
// Plot contours
cpgsci (7);
cpgcont (cont, nx, ny, 1, nx, 1, ny, c, nc, tr);
// Label contours
cpgsch (0.8);
for (i = 0; i < nc; i++)
{
sprintf (state, "%.0f", c[i]);
cpgconl (cont, nx, ny, 1, nx, 1, ny, c[i], tr, state, 300, 18);
}
cpgsch (1.0);
cpgsci (1);
return;
}
// Initialize plot
void
init_plot (char *psfile, float width, float height)
{
int i;
giza_open_device_size_float ("/xs", "skymap", width, height, 3);
cpgslw (1);
skymap_plot_renew ();
return;
}
// Add to schedule
void
schedule (char *nfd, double ra, double de, char *startstop)
{
FILE *file;
char sra[16], sde[16];
// Compute strings
dec2s (ra / 15.0, sra, 0, 5);
dec2s (de, sde, 0, 4);
printf ("%s %s %s %s\n", nfd, sra, sde, startstop);
// Open file
file = fopen ("schedule.txt", "a");
if (file == NULL)
{
printf ("Failed to create schedule.txt\n");
return;
}
fprintf (file, "%s %s %s %s %s\n", nfd, sra, sde, m.camera, startstop);
fclose (file);
return;
}
// Initialize plot
void
skymap_plot_renew (void)
{
char filename[LIM];
// Size limit
if (m.w > 120.0)
m.w = 120.0;
if (m.level == 1)
{
m.w = 120;
m.minmag = -2.0;
m.maxmag = 5.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/hip6mag.dat", m.datadir);
}
if (m.level == 2)
{
m.w = 90;
m.minmag = -1.5;
m.maxmag = 5.5;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/hip6mag.dat", m.datadir);
}
if (m.level == 3)
{
m.w = 60;
m.minmag = -1.0;
m.maxmag = 6.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/hip6mag.dat", m.datadir);
}
if (m.level == 4)
{
m.w = 30;
m.minmag = -0.5;
m.maxmag = 6.5;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tyc8mag.dat", m.datadir);
}
if (m.level == 5)
{
m.w = 20;
m.minmag = 0.0;
m.maxmag = 7.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tyc8mag.dat", m.datadir);
}
if (m.level == 6)
{
m.w = 10;
m.minmag = 1.0;
m.maxmag = 8.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tyc8mag.dat", m.datadir);
}
if (m.level == 7)
{
m.w = 5;
m.minmag = 2.0;
m.maxmag = 9.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tyc10mag.dat", m.datadir);
}
if (m.level == 8)
{
m.w = 2;
m.minmag = 3.0;
m.maxmag = 10.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tyc10mag.dat", m.datadir);
}
if (m.level == 9)
{
m.w = 1;
m.minmag = 3.0;
m.maxmag = 12.0;
m.maxrad = 2.0;
m.minrad = 0.02;
sprintf (m.starfile, "%s/data/tycho2.dat", m.datadir);
}
/*
// Star files
if (m.w>90.0 && m.w<=120.0) {
strcpy(m.starfile,"data/hip6mag.dat");
m.minmag=-2.0;
m.maxmag=4.5;
} else if (m.w>60.0 && m.w<=90.0) {
strcpy(m.starfile,"data/hip6mag.dat");
m.minmag=-2.0;
m.maxmag=5.0;
} else if (m.w>20.0 && m.w<=60.0) {
strcpy(m.starfile,"data/hip6mag.dat");
m.minmag=0.0;
m.maxmag=6.0;
} else if (m.w<=20.0) {
strcpy(m.starfile,"data/tyc8mag.dat");
m.minmag=2.0;
m.maxmag=8.0;
}
*/
return;
}
// Get a x and y from an AZI, ALT
void
forward (double alpha, double delta, double *x, double *y)
{
int i, status;
double phi, theta;
struct celprm cel;
// Initialize Reference Angles
celini (&cel);
if (strcmp (m.orientation, "horizontal") == 0)
{
cel.ref[0] = m.azi0;
cel.ref[1] = m.alt0;
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
cel.ref[0] = m.ra0;
cel.ref[1] = m.de0;
}
cel.ref[2] = 999.;
cel.ref[3] = 999.;
cel.flag = 0.;
strcpy (cel.prj.code, m.projection);
if (celset (&cel))
{
printf ("Error in Projection (celset)\n");
return;
}
cels2x (&cel, 1, 0, 1, 1, &alpha, &delta, &phi, &theta, x, y, &status);
// Flip equatorial axis
if (strcmp (m.orientation, "equatorial") == 0)
*x *= -1;
return;
}
// Get an AZI, ALT from x and y
void
reverse (double x, double y, double *alpha, double *delta)
{
int i, status;
double phi, theta;
struct celprm cel;
// Flip equatorial axis
if (strcmp (m.orientation, "equatorial") == 0)
x *= -1;
// Initialize Reference Angless
celini (&cel);
if (strcmp (m.orientation, "horizontal") == 0)
{
cel.ref[0] = m.azi0;
cel.ref[1] = m.alt0;
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
cel.ref[0] = m.ra0;
cel.ref[1] = m.de0;
}
cel.ref[2] = 999.;
cel.ref[3] = 999.;
cel.flag = 0.;
strcpy (cel.prj.code, m.projection);
if (celset (&cel))
{
printf ("Error in Projection (celset)\n");
return;
}
celx2s (&cel, 1, 0, 1, 1, &x, &y, &phi, &theta, alpha, delta, &status);
return;
}
// Greenwich Mean Sidereal Time
double
gmst (double mjd)
{
double t, gmst;
t = (mjd - 51544.5) / 36525.0;
gmst =
modulo (280.46061837 + 360.98564736629 * (mjd - 51544.5) +
t * t * (0.000387933 - t / 38710000), 360.0);
return gmst;
}
// Return x modulo y [0,y)
double
modulo (double x, double y)
{
x = fmod (x, y);
if (x < 0.0)
x += y;
return x;
}
// Read a line of maximum length int lim from file FILE into string s
int
fgetline (FILE * file, char *s, int lim)
{
int c, i = 0;
while (--lim > 0 && (c = fgetc (file)) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
// Plot field of view
void
skymap_plot_fov ()
{
int i, j, n = 50;
double rx, ry, azi, alt;
float x, y;
// double azi0[]={44.0,7.0,30.0,44.0,44.0};
// double alt0[]={16.0,16.0,60.0,60.0,16.0};
double azi0[] = { 45.0, 7.0, 7.0, 45.0, 45.0 };
double alt0[] = { 20.0, 20.0, 50.0, 50.0, 20.0 };
double azi1[] = { 150.0, 140.0, 140.0, 150.0, 150.0 };
double alt1[] = { 26.0, 26.0, 31.0, 31.0, 26.0 };
/*
for (i=0;i<sizeof(alt0)/sizeof(alt0[0])-1;i++) {
for (j=0;j<n;j++) {
azi=azi0[i]+(azi0[i+1]-azi0[i])*(float) j/(float) (n-1);
alt=alt0[i]+(alt0[i+1]-alt0[i])*(float) j/(float) (n-1);
azi+=180.0;
forward(azi,alt,&rx,&ry);
x=(float) rx;
y=(float) ry;
if (j==0)
cpgmove(x,y);
else {
cpgdraw(x,y);
cpgmove(x,y);
}
}
}
*/
for (i = 0; i < sizeof (alt1) / sizeof (alt1[0]) - 1; i++)
{
for (j = 0; j < n; j++)
{
azi =
azi1[i] + (azi1[i + 1] - azi1[i]) * (float) j / (float) (n - 1);
alt =
alt1[i] + (alt1[i + 1] - alt1[i]) * (float) j / (float) (n - 1);
azi += 180.0;
forward (azi, alt, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (j == 0)
cpgmove (x, y);
else
{
cpgdraw (x, y);
cpgmove (x, y);
}
}
}
return;
}
// Plot an horizontal grid
void
skymap_plothorizontal_grid ()
{
int i, j;
double rx, ry, azi, alt;
float x, y;
float sch;
int sci, sls, status;
FILE *file;
char line[LIM], filename[LIM];
// Get setup
cpgqch (&sch);
cpgqls (&sls);
cpgqci (&sci);
// Plot grid
cpgsci (15);
cpgsls (2);
// Altitudes
if (m.grid == 1)
{
for (alt = 0.0; alt <= 80.0; alt += 20.0)
{
for (i = 0; i < m.nmax; i++)
{
azi = 360.0 * (double) i / (double) (m.nmax - 1);
forward (azi, alt, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
}
// Azimuths
for (azi = 0.0; azi < 360.0; azi += 30.0)
{
for (i = 0; i < m.nmax; i++)
{
alt = 0.0 + 80.0 * (double) i / (double) (m.nmax - 1);
forward (azi, alt, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
}
}
cpgsci (1);
cpgsls (1);
// Plot horizon
for (i = 0; i < m.nmax; i++)
{
azi = 360.0 * (float) i / (float) (m.nmax - 1);
alt = 0.0;
forward (azi, alt, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgsci (255);
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
// Use real horizon
sprintf (filename, "%s/data/%04dhorizon.txt", m.datadir, m.site_id);
file = fopen (filename, "r");
if (file != NULL)
{
i = 0;
while (fgetline (file, line, LIM) > 0)
{
if (strlen (line) < 2)
{
i = 0;
continue;
}
status = sscanf (line, "%lf %lf", &azi, &alt);
forward (azi + 180.0, alt, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgsci (255);
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
i++;
}
fclose (file);
}
return;
}
// Plot an equatorial grid
void
skymap_plotequatorial_grid ()
{
int i, j;
double rx, ry, ra, de;
float x, y;
float sch;
int sci, sls;
// Get setup
cpgqch (&sch);
cpgqls (&sls);
cpgqci (&sci);
// Plot grid
cpgsci (15);
cpgsls (2);
// Declinations
if (m.grid == 1)
{
for (de = -80.0; de <= 80.0; de += 20.0)
{
for (i = 0; i < m.nmax; i++)
{
ra = 360.0 * (double) i / (double) (m.nmax - 1);
forward (ra, de, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
}
// Right ascensions
for (ra = 0.0; ra < 360.0; ra += 30.0)
{
for (i = 0; i < m.nmax; i++)
{
de = -80.0 + 160.0 * (double) i / (double) (m.nmax - 1);
forward (ra, de, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
}
}
cpgsci (1);
cpgsls (1);
// Plot equatorial
for (i = 0; i < m.nmax; i++)
{
ra = 360.0 * (float) i / (float) (m.nmax - 1);
de = 0.0;
forward (ra, de, &rx, &ry);
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
if (fabs (x) <= 1.5 * m.w && fabs (y) <= m.w)
{
cpgdraw (x, y);
cpgmove (x, y);
}
else
cpgmove (x, y);
}
return;
}
// Plot constellation lines
void
skymap_plotconstellations (char *filename)
{
int i, flag;
unsigned long tyc;
double rx, ry, azi, alt, alt1;
double ra, de, ra0, de0, mjd0 = 51544.5;
// double mjd0=48348.3125; // J1991.25
float x, y, x1, y1;
char line[LIM];
FILE *file;
cpgsci (4);
// Loop over file
file = fopen (filename, "r");
if (file == NULL)
{
printf ("Constellation file not found\n");
exit (1);
}
for (i = 0; fgetline (file, line, LIM) > 0; i++)
{
if (strchr (line, '#') != NULL)
continue;
sscanf (line, "%lu %i %lf %lf\n", &tyc, &flag, &ra0, &de0);
precess (mjd0, ra0, de0, m.mjd, &ra, &de);
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
x = (float) rx;
y = (float) ry;
if (i == 0)
cpgmove (x, y);
// if (fabs(x)<=m.w && fabs(y)<=m.w) {
if (flag == 0)
cpgmove (x, y);
if (flag == 1)
{
cpgdraw (x, y);
cpgmove (x, y);
}
// } else
// cpgmove(x,y);
}
fclose (file);
cpgsci (1);
return;
}
// Convert equatorial into horizontal coordinates
void
equatorial2horizontal (double mjd, double ra, double de, double *azi,
double *alt)
{
double h;
h = gmst (mjd) + m.lng - ra;
*azi =
modulo (atan2
(sin (h * D2R),
cos (h * D2R) * sin (m.lat * D2R) -
tan (de * D2R) * cos (m.lat * D2R)) * R2D, 360.0);
*alt =
asin (sin (m.lat * D2R) * sin (de * D2R) +
cos (m.lat * D2R) * cos (de * D2R) * cos (h * D2R)) * R2D;
return;
}
// Convert equatorial into horizontal coordinates
void
graves_equatorial2horizontal (double mjd, double ra, double de, double *azi,
double *alt)
{
double h;
float lat = 47.3480, lng = 5.5151;
h = gmst (mjd) + lng - ra;
*azi =
modulo (atan2
(sin (h * D2R),
cos (h * D2R) * sin (lat * D2R) -
tan (de * D2R) * cos (lat * D2R)) * R2D, 360.0);
*alt =
asin (sin (lat * D2R) * sin (de * D2R) +
cos (lat * D2R) * cos (de * D2R) * cos (h * D2R)) * R2D;
return;
}
// Convert horizontal into equatorial coordinates
void
horizontal2equatorial (double mjd, double azi, double alt, double *ra,
double *de)
{
double h;
h =
atan2 (sin (azi * D2R),
cos (azi * D2R) * sin (m.lat * D2R) +
tan (alt * D2R) * cos (m.lat * D2R)) * R2D;
*ra = modulo (gmst (mjd) + m.lng - h, 360.0);
*de =
asin (sin (m.lat * D2R) * sin (alt * D2R) -
cos (m.lat * D2R) * cos (alt * D2R) * cos (azi * D2R)) * R2D;
if (*ra < 0.0)
*ra += 360.0;
return;
}
// Convert horizontal into equatorial coordinates
void
graves_horizontal2equatorial (double mjd, double azi, double alt, double *ra,
double *de)
{
double h;
float lat = 47.3480, lng = 5.5151;
h =
atan2 (sin (azi * D2R),
cos (azi * D2R) * sin (lat * D2R) +
tan (alt * D2R) * cos (lat * D2R)) * R2D;
*ra = modulo (gmst (mjd) + lng - h, 360.0);
*de =
asin (sin (lat * D2R) * sin (alt * D2R) -
cos (lat * D2R) * cos (alt * D2R) * cos (azi * D2R)) * R2D;
if (*ra < 0.0)
*ra += 360.0;
return;
}
// Plot the stars
void
skymap_plotstars (char *filename)
{
int i, j;
unsigned long hip;
double rx, ry, azi, alt;
double ra, de, ra0, de0, mjd0 = 51544.5;
// double mjd0=48348.3125; // J1991.25
float x, y, vmag;
float rad;
char line[LIM];
FILE *file;
struct star s;
if (strstr (filename, "tycho2.dat") != NULL)
{
file = fopen (m.starfile, "rb");
while (!feof (file))
{
fread (&s, sizeof (struct star), 1, file);
vmag = s.mag;
ra0 = s.ra;
de0 = s.de;
if (vmag <= m.maxmag)
{
precess (mjd0, ra0, de0, m.mjd, &ra, &de);
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
x = (float) rx;
y = (float) ry;
// Star size
rad =
m.maxrad + (m.minrad - m.maxrad) * (vmag -
m.minmag) / (m.maxmag -
m.minmag);
rad *= m.w / 90.0;
cpgsci (255);
cpgcirc (x, y, rad);
}
}
fclose (file);
}
else
{
// Loop over file
file = fopen (filename, "r");
if (file == NULL)
{
printf ("Star file not found\n");
exit (1);
}
while (fgetline (file, line, LIM) > 0)
{
// Failed for Tycho files
// sscanf(line,"%i %lf %lf %f\n",&hip,&ra,&de,&vmag);
// Skipping star ID
sscanf (line + 13, "%lf %lf %f\n", &ra0, &de0, &vmag);
if (vmag <= m.maxmag)
{
precess (mjd0, ra0, de0, m.mjd, &ra, &de);
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
x = (float) rx;
y = (float) ry;
if (fabs (rx) < 0.02 && fabs (ry) < 0.02)
printf ("%lf %lf %lf %lf %f\n", ra0, de0, ra, de, vmag);
// Star size
rad =
m.maxrad + (m.minrad - m.maxrad) * (vmag -
m.minmag) / (m.maxmag -
m.minmag);
rad *= m.w / 90.0;
cpgsci (255);
cpgcirc (x, y, rad);
}
}
fclose (file);
}
return;
}
// Observer position
void
obspos_xyz (double mjd, xyz_t * pos, xyz_t * vel)
{
double ff, gc, gs, theta, s, dtheta;
s = sin (m.lat * D2R);
ff = sqrt (1.0 - FLAT * (2.0 - FLAT) * s * s);
gc = 1.0 / ff + m.alt / XKMPER;
gs = (1.0 - FLAT) * (1.0 - FLAT) / ff + m.alt / XKMPER;
theta = gmst (mjd) + m.lng;
dtheta = dgmst (mjd) * D2R / 86400;
pos->x = gc * cos (m.lat * D2R) * cos (theta * D2R) * XKMPER;
pos->y = gc * cos (m.lat * D2R) * sin (theta * D2R) * XKMPER;
pos->z = gs * sin (m.lat * D2R) * XKMPER;
vel->x = -gc * cos (m.lat * D2R) * sin (theta * D2R) * XKMPER * dtheta;
vel->y = gc * cos (m.lat * D2R) * cos (theta * D2R) * XKMPER * dtheta;
vel->z = 0.0;
return;
}
// Graves position
void
graves_xyz (double mjd, xyz_t * pos, xyz_t * vel)
{
double ff, gc, gs, theta, s, dtheta;
float lat = 47.3480, lng = 5.5151, alt = 0.1;
s = sin (lat * D2R);
ff = sqrt (1.0 - FLAT * (2.0 - FLAT) * s * s);
gc = 1.0 / ff + alt / XKMPER;
gs = (1.0 - FLAT) * (1.0 - FLAT) / ff + alt / XKMPER;
theta = gmst (mjd) + lng;
dtheta = dgmst (mjd) * D2R / 86400;
pos->x = gc * cos (lat * D2R) * cos (theta * D2R) * XKMPER;
pos->y = gc * cos (lat * D2R) * sin (theta * D2R) * XKMPER;
pos->z = gs * sin (lat * D2R) * XKMPER;
vel->x = -gc * cos (lat * D2R) * sin (theta * D2R) * XKMPER * dtheta;
vel->y = gc * cos (lat * D2R) * cos (theta * D2R) * XKMPER * dtheta;
vel->z = 0.0;
return;
}
// Plot satellite track
void
skymap_plotsatellite (char *filename, int satno, double mjd0, double dt)
{
orbit_t orb;
struct sat s;
int imode, flag, fflag, i;
FILE *fp = NULL;
xyz_t satpos, obspos, satvel, sunpos;
double mjd, jd, dx, dy, dz;
double rx, ry, ra, de, azi, alt, r, t;
float x, y;
char norad[7], satname[30], date[24];;
float isch;
float rsun, rearth, psun, pearth, p;
int priority[] = { 28888, 37348, 39232, 43941, 48247 };
char type[8];
// Open TLE file
fp = fopen (filename, "rb");
if (fp == NULL)
fatal_error ("File open failed for reading %s\n", filename);
// Read TLEs
while (read_twoline (fp, satno, &orb) == 0)
{
Isat = orb.satno;
imode = init_sgdp4 (&orb);
if (orb.rev >= 10.0)
strcpy (type, "LEO");
else if (orb.rev < 10.0 && orb.eqinc * R2D > 50.0 && orb.ecc > 0.5)
strcpy (type, "HEO");
else if (orb.rev < 10.0 && orb.eqinc * R2D <= 50.0 && orb.ecc > 0.5)
strcpy (type, "GTO");
else
strcpy (type, "GEO");
if (m.leoflag == 1 && strcmp (type, "LEO") != 0)
continue;
if (m.leoflag == 2 && strcmp (type, "HEO") != 0)
continue;
if (m.leoflag == 3 && strcmp (type, "GEO") != 0)
continue;
if (m.leoflag == 4 && strcmp (type, "GTO") != 0)
continue;
sprintf (norad, " %ld", Isat);
if (imode == SGDP4_ERROR)
continue;
for (flag = 0, fflag = 0, t = 0.0; t <= dt; t += 1.0)
{
mjd = mjd0 + t / 86400.0;
// Compute apparent position
s = apparent_position (mjd);
// Skip bogus positions
if (s.h > 300000)
continue;
if (m.agelimit > 0 && s.age < m.agelimit)
continue;
// Convert to float
x = (float) s.rx;
y = (float) s.ry;
// Visibility
if (s.p - s.pearth < -s.psun)
{
cpgsci (14);
}
else if (s.p - s.pearth > -s.psun && s.p - s.pearth < s.psun)
{
cpgsci (15);
}
else if (s.p - s.pearth > s.psun)
{
for (i = 0; i < sizeof (priority) / sizeof (priority[0]); i++)
{
if (Isat == priority[i])
{
cpgsci (2);
break;
}
else
{
if (s.salt < 0.0)
cpgsci (7);
else
cpgsci (8);
}
}
}
// Graves colouring
if (m.graves != 0)
{
if (s.illumg == 1)
cpgsci (2);
else
cpgsci (14);
}
// In field of view
if (fabs (x) < m.fw && fabs (y) < m.fh && fflag == 0)
{
mjd2date (mjd, date);
printf ("%.19s %05ld %6.1f %7.1f d %9.2f km %6.2f deg\n", date,
Isat, s.mag, s.age, s.r, s.phase);
fflag = 1;
}
// Plot satellites
if (flag == 0)
{
cpgsch (0.8);
if (s.age < 25)
cpgpt1 (x, y, 17);
else if (s.age < 50)
cpgpt1 (x, y, 4);
else
cpgpt1 (x, y, 6);
cpgsch (0.6);
// Print name if in viewport
if (fabs (x) < 1.5 * m.w && fabs (y) < m.w && x < 1.32 * m.w
&& y < 0.96 * m.w && m.pflag == 1)
cpgtext (x, y, norad);
cpgsch (isch);
cpgmove (x, y);
flag = 1;
}
else
{
cpgdraw (x, y);
cpgmove (x, y);
}
}
}
fclose (fp);
cpgsci (1);
return;
}
// Solar position
void
sunpos_xyz (double mjd, xyz_t * pos, double *ra, double *de)
{
double jd, t, l0, m, e, c, r;
double n, s, ecl;
jd = mjd + 2400000.5;
t = (jd - 2451545.0) / 36525.0;
l0 = modulo (280.46646 + t * (36000.76983 + t * 0.0003032), 360.0) * D2R;
m = modulo (357.52911 + t * (35999.05029 - t * 0.0001537), 360.0) * D2R;
e = 0.016708634 + t * (-0.000042037 - t * 0.0000001267);
c = (1.914602 + t * (-0.004817 - t * 0.000014)) * sin (m) * D2R;
c += (0.019993 - 0.000101 * t) * sin (2.0 * m) * D2R;
c += 0.000289 * sin (3.0 * m) * D2R;
r = 1.000001018 * (1.0 - e * e) / (1.0 + e * cos (m + c));
n = modulo (125.04 - 1934.136 * t, 360.0) * D2R;
s = l0 + c + (-0.00569 - 0.00478 * sin (n)) * D2R;
ecl =
(23.43929111 +
(-46.8150 * t - 0.00059 * t * t + 0.001813 * t * t * t) / 3600.0 +
0.00256 * cos (n)) * D2R;
*ra = atan2 (cos (ecl) * sin (s), cos (s)) * R2D;
*de = asin (sin (ecl) * sin (s)) * R2D;
pos->x = r * cos (*de * D2R) * cos (*ra * D2R) * XKMPAU;
pos->y = r * cos (*de * D2R) * sin (*ra * D2R) * XKMPAU;
pos->z = r * sin (*de * D2R) * XKMPAU;
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;
}
// 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;
}
// 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;
}
// Computes apparent position
struct sat
apparent_position (double mjd)
{
struct sat s;
double jd, rsun, rearth, rsat;
double dx, dy, dz, dvx, dvy, dvz, vtot;
xyz_t satpos, obspos, obsvel, satvel, sunpos, grvpos, grvvel;
double sra, sde, azi;
// Sat ID
s.Isat = Isat;
// Get Julian Date
jd = mjd + 2400000.5;
// Get positions
obspos_xyz (mjd, &obspos, &obsvel);
satpos_xyz (jd, &satpos, &satvel);
sunpos_xyz (mjd, &sunpos, &sra, &sde);
// Sun altitude
equatorial2horizontal (mjd, sra, sde, &azi, &s.salt);
// Age
s.age = jd - SGDP4_jd0;
// Sat positions
s.x = satpos.x;
s.y = satpos.y;
s.z = satpos.z;
s.vx = satvel.x;
s.vy = satvel.y;
s.vz = satvel.z;
// Sun position from satellite
dx = -satpos.x + sunpos.x;
dy = -satpos.y + sunpos.y;
dz = -satpos.z + sunpos.z;
// Distances
rsun = sqrt (dx * dx + dy * dy + dz * dz);
rearth =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y + satpos.z * satpos.z);
s.h = rearth - XKMPER;
// Angles
s.psun = asin (696.0e3 / rsun) * R2D;
s.pearth = asin (6378.135 / rearth) * R2D;
s.p =
acos ((-dx * satpos.x - dy * satpos.y -
dz * satpos.z) / (rsun * rearth)) * R2D;
// Visibility state
if (s.p - s.pearth < -s.psun)
strcpy (s.state, "eclipsed");
else if (s.p - s.pearth > -s.psun && s.p - s.pearth < s.psun)
strcpy (s.state, "umbra");
else if (s.p - s.pearth > s.psun)
strcpy (s.state, "sunlit");
// Position differences
dx = satpos.x - obspos.x;
dy = satpos.y - obspos.y;
dz = satpos.z - obspos.z;
dvx = satvel.x - obsvel.x;
dvy = satvel.y - obsvel.y;
dvz = satvel.z - obsvel.z;
// Celestial position
s.r = sqrt (dx * dx + dy * dy + dz * dz);
s.v = (dvx * dx + dvy * dy + dvz * dz) / s.r;
s.ra = modulo (atan2 (dy, dx) * R2D, 360.0);
s.de = asin (dz / s.r) * R2D;
// Angular velocity
vtot = sqrt (dvx * dvx + dvy * dvy + dvz * dvz);
s.vang = sqrt (vtot * vtot - s.v * s.v) / s.r * R2D;
// Phase
s.phase =
acos (((obspos.x - satpos.x) * (sunpos.x - satpos.x) +
(obspos.y - satpos.y) * (sunpos.y - satpos.y) + (obspos.z -
satpos.z) *
(sunpos.z - satpos.z)) / (rsun * s.r)) * R2D;
// Magnitude
if (strcmp (s.state, "sunlit") == 0)
s.mag =
STDMAG - 15.0 + 5 * log10 (s.r) - 2.5 * log10 (sin (s.phase * D2R) +
(M_PI -
s.phase * D2R) *
cos (s.phase * D2R));
else
s.mag = 15;
// Convert and project
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (mjd, s.ra, s.de, &s.azi, &s.alt);
forward (s.azi, s.alt, &s.rx, &s.ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (s.ra, s.de, &s.rx, &s.ry);
}
// Compute position at Graves
if (m.graves != 0)
{
graves_xyz (mjd, &grvpos, &grvvel);
dx = satpos.x - grvpos.x;
dy = satpos.y - grvpos.y;
dz = satpos.z - grvpos.z;
dvx = satvel.x - grvvel.x;
dvy = satvel.y - grvvel.y;
dvz = satvel.z - grvvel.z;
// Celestial position
s.rg = sqrt (dx * dx + dy * dy + dz * dz);
s.vg = (dvx * dx + dvy * dy + dvz * dz) / s.rg;
s.rag = modulo (atan2 (dy, dx) * R2D, 360.0);
s.deg = asin (dz / s.rg) * R2D;
graves_equatorial2horizontal (mjd, s.rag, s.deg, &s.azig, &s.altg);
// Illuminated?
if (s.altg >= 15.0 && s.altg <= 40.0
&& modulo (s.azig - 180.0, 360.0) >= 90.0
&& modulo (s.azig - 180.0, 360.0) <= 270.0)
s.illumg = 1;
else
s.illumg = 0;
}
else
{
s.illumg = 0;
}
return s;
}
// Planar search
void
planar_search (char *filename, int satno, float rmin, float rmax, int nr,
int graves)
{
int i, j, imode;
FILE *fp;
orbit_t orb;
kep_t K;
int withvel, rv;
double tsince, radius, jd;
double st, ct, sn, cn, si, ci, t;
xyz_t satpos, obspos, obsvel, sunpos, grvpos, grvvel;
double r, ra, de, dx, dy, dz, rsun, rearth, psun, pearth, p, azi, alt, rx,
ry, rx0, ry0, ra0, de0, rx1, ry1, altmax;
double sra, sde;
double rg, rag, deg, azig, altg;
float phase, mag, mmin;
char state[10];
int illumg;
// Open TLE file
fp = fopen (filename, "rb");
if (fp == NULL)
fatal_error ("File open failed for reading %s\n", filename);
// Read TLEs
while (read_twoline (fp, satno, &orb) == 0)
{
Isat = orb.satno;
imode = init_sgdp4 (&orb);
if (imode == SGDP4_ERROR)
continue;
}
fclose (fp);
// Get Julian Date
jd = m.mjd + 2400000.5;
// Get kepler
tsince = 1440.0 * (jd - SGDP4_jd0);
rv = sgdp4 (tsince, 1, &K);
// Angles
sn = sin (K.ascn);
cn = cos (K.ascn);
si = sin (K.eqinc);
ci = cos (K.eqinc);
// Loop over radii
for (j = 0; j < nr; j++)
{
if (nr > 1)
radius = rmin + (rmax - rmin) * (float) j / (float) (nr - 1);
else
radius = rmin;
// Loop over angles
for (i = 0, mmin = 15.0, altmax = 0.0; i < MMAX; i++)
{
t = 2.0 * M_PI * (double) i / (double) (MMAX - 1);
st = sin (K.theta + t);
ct = cos (K.theta + t);
satpos.x = -sn * ci * st + cn * ct;
satpos.y = cn * ci * st + sn * ct;
satpos.z = si * st;
satpos.x *= (radius + XKMPER);
satpos.y *= (radius + XKMPER);
satpos.z *= (radius + XKMPER);
// Get positions
obspos_xyz (m.mjd, &obspos, &obsvel);
sunpos_xyz (m.mjd, &sunpos, &sra, &sde);
// Sun position from satellite
dx = -satpos.x + sunpos.x;
dy = -satpos.y + sunpos.y;
dz = -satpos.z + sunpos.z;
// Distances
rsun = sqrt (dx * dx + dy * dy + dz * dz);
rearth =
sqrt (satpos.x * satpos.x + satpos.y * satpos.y +
satpos.z * satpos.z);
// Angles
psun = asin (696.0e3 / rsun) * R2D;
pearth = asin (6378.135 / rearth) * R2D;
p =
acos ((-dx * satpos.x - dy * satpos.y -
dz * satpos.z) / (rsun * rearth)) * R2D;
p -= pearth;
// Position differences
dx = satpos.x - obspos.x;
dy = satpos.y - obspos.y;
dz = satpos.z - obspos.z;
// Celestial position
r = sqrt (dx * dx + dy * dy + dz * dz);
ra = atan2 (dy, dx) * R2D;
de = asin (dz / r) * R2D;
// Convert and project
if (strcmp (m.orientation, "horizontal") == 0)
{
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
forward (azi, alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (ra, de, &rx, &ry);
}
// Visibility
if (p < -psun)
{
strcpy (state, "eclipsed");
cpgsci (14);
}
else if (p > -psun && p < psun)
{
strcpy (state, "umbra");
cpgsci (15);
}
else if (p > psun)
{
strcpy (state, "sunlit");
cpgsci (7);
}
// Phase
phase =
acos (((obspos.x - satpos.x) * (sunpos.x - satpos.x) +
(obspos.y - satpos.y) * (sunpos.y - satpos.y) + (obspos.z -
satpos.z)
* (sunpos.z - satpos.z)) / (rsun * r)) * R2D;
// Magnitude
if (strcmp (state, "sunlit") == 0)
mag =
STDMAG - 15.0 + 5 * log10 (r) - 2.5 * log10 (sin (phase * D2R) +
(M_PI -
phase * D2R) *
cos (phase * D2R));
else
mag = 15;
if (mag < mmin)
{
rx0 = rx;
ry0 = ry;
mmin = mag;
}
if (alt > 0.0 && alt > altmax && mag < 15.0)
{
rx1 = rx;
ry1 = ry;
altmax = alt;
}
// Compute position at Graves
printf ("compute position at graves");
if (graves != 0)
{
printf ("graves !=0");
graves_xyz (m.mjd, &grvpos, &grvvel);
dx = satpos.x - grvpos.x;
dy = satpos.y - grvpos.y;
dz = satpos.z - grvpos.z;
// Celestial position
rg = sqrt (dx * dx + dy * dy + dz * dz);
rag = modulo (atan2 (dy, dx) * R2D, 360.0);
deg = asin (dz / rg) * R2D;
graves_equatorial2horizontal (m.mjd, rag, deg, &azig, &altg);
// Illuminated?
if (altg >= 15.0 && altg <= 40.0
&& modulo (azig - 180.0, 360.0) >= 90.0
&& modulo (azig - 180.0, 360.0) <= 270.0)
cpgsci (2);
else
cpgsci (15);
}
if (i == 0)
cpgmove ((float) rx, (float) ry);
else
{
cpgdraw ((float) rx, (float) ry);
cpgmove ((float) rx, (float) ry);
}
cpgsci (1);
}
// Plot brightest point
if (graves == 0)
{
cpgsch (1.0);
cpgsci (7);
cpgpt1 ((float) rx0, (float) ry0, 4);
if (altmax > 0.0)
cpgpt1 ((float) rx1, (float) ry1, 17);
cpgsci (1);
}
}
return;
}
// Print TLE
int
print_tle (char *filename, int satno)
{
FILE *fp;
struct sat s;
orbit_t orb;
char line[LIM], pline[LIM];
int flag = 0;
// Open TLE file
fp = fopen (filename, "rb");
if (fp == NULL)
fatal_error ("File open failed for reading %s\n", filename);
// Read TLEs
while (fgetline (fp, line, LIM) > 0)
{
sscanf (line + 2, "%ld", &Isat);
if (line[0] == '1' && (long) Isat == satno)
{
printf ("\n%s%s", pline, line);
fgetline (fp, line, LIM);
printf ("%s\n", line);
flag = 1;
}
strcpy (pline, line);
}
fclose (fp);
return flag;
}
// Identify satellite
long
identify_satellite (char *filename, int satno, double mjd, float rx, float ry)
{
long Isatmin = 0;
int imode;
FILE *fp;
struct sat s, smin;
orbit_t orb;
float dr, drmin, agemin;
char line[LIM], pline[LIM];
char sra[16], sde[16];
float lat, lng;
double mjd0, ra0, de0;
// Open TLE file
fp = fopen (filename, "rb");
if (fp == NULL)
fatal_error ("File open failed for reading %s\n", filename);
// Read TLEs
while (read_twoline (fp, satno, &orb) == 0)
{
Isat = orb.satno;
imode = init_sgdp4 (&orb);
if (imode == SGDP4_ERROR)
continue;
// Compute apparent position
s = apparent_position (mjd);
// Offset
dr = sqrt (pow (rx - s.rx, 2) + pow (ry - s.ry, 2));
if (Isatmin == 0 || dr < drmin)
{
Isatmin = Isat;
drmin = dr;
smin = s;
}
}
fclose (fp);
// Latitude and longitude
lng = modulo (atan2 (smin.y, smin.x) * R2D - gmst (mjd), 360.0);
if (lng > 180.0)
lng -= 360.0;
if (lng < -180.0)
lng += 360.0;
lat = asin (smin.z / (smin.h + XKMPER)) * R2D;
// Print TLE
print_tle (filename, Isatmin);
printf ("Age: %.1f d\n\n", smin.age);
printf
("x: %+12.4lf km; vx: %+8.5f km/s\ny: %+12.4lf km; vy: %+8.5f km/s\nz: %+12.4lf km; vz: %+8.5f km/s\nr: %10.2lf km; v: %6.3f km/s\nl: %6.2lf; b: %6.2lf; h: %10.2lf km\n\n",
smin.x, smin.vx, smin.y, smin.vy, smin.z, smin.vz, smin.r, smin.v, lng,
lat, smin.h);
dec2s (smin.ra / 15.0, sra, 0, 5);
dec2s (smin.de, sde, 0, 4);
printf ("R.A.: %s Decl.: %s\n", sra, sde);
// Precess position to J2000
mjd0 = 51544.5;
precess (mjd, smin.ra, smin.de, mjd0, &ra0, &de0);
dec2s (ra0 / 15.0, sra, 0, 5);
dec2s (de0, sde, 0, 4);
printf ("R.A.: %s Decl.: %s (J2000)\n", sra, sde);
printf ("Azi.: %.1f Alt.: %.1f\n\n", modulo (smin.azi - 180.0, 360.0),
smin.alt);
printf ("Phase: %.2f\nMagnitude: %.2f\nAngular velocity: %.4f (deg/s)\n",
smin.phase, smin.mag, smin.vang);
return Isatmin;
}
double
parallactic_angle (double mjd, double ra, double de)
{
double h, q;
h = gmst (mjd) + m.lng - ra;
q =
atan2 (sin (h * D2R),
(tan (m.lat * D2R) * cos (de * D2R) -
sin (de * D2R) * cos (h * D2R))) * R2D;
if (fabs (m.lat - de) < 0.001)
q = 0.0;
return q;
}
void
skymap_plotmoon (void)
{
double rx, ry, ra, de, azi, alt;
xyz_t lunpos;
// Get moon position
lunpos_xyz (m.mjd, &lunpos, &ra, &de);
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
if (strcmp (m.orientation, "horizontal") == 0)
forward (azi, alt, &rx, &ry);
else if (strcmp (m.orientation, "equatorial") == 0)
forward (ra, de, &rx, &ry);
cpgsci (14);
if (m.w > 60.0)
cpgcirc ((float) rx, (float) ry, 2.0);
else
cpgcirc ((float) rx, (float) ry, 0.25);
cpgsci (1);
return;
}
void
skymap_plotsun (void)
{
double rx, ry;
if (strcmp (m.orientation, "horizontal") == 0)
forward (m.sazi, m.salt, &rx, &ry);
else if (strcmp (m.orientation, "equatorial") == 0)
forward (m.sra, m.sde, &rx, &ry);
cpgsci (7);
if (m.w > 60.0)
cpgcirc ((float) rx, (float) ry, 2.0);
else
cpgcirc ((float) rx, (float) ry, 0.25);
cpgsci (1);
return;
}
int
read_camera (int no)
{
int i = 0;
float f, f2;
char s[31];
FILE *file;
char line[LIM], filename[LIM];
sprintf (filename, "%s/data/cameras.txt", m.datadir);
file = fopen (filename, "r");
if (file == NULL)
{
printf ("File with camera information not found!\n");
return -1;
}
while (fgets (line, LIM, file) != NULL)
{
// Skip
if (strstr (line, "#") != NULL)
continue;
if (i == no)
{
f2 = -90;
// Retrieve complete line of selected camera parameters
sscanf (line, "%s %f %f %f %f %s %s %f %f", m.camera, &m.fw, &m.fh,
&f, &f, s, s, &f, &f2);
if (f2 >= 0)
{
// if Elevation is set, center map to camera position
m.azi0 = (double) f;
m.alt0 = (double) f2;
horizontal2equatorial (m.mjd, m.azi0, m.alt0, &m.ra0, &m.de0);
}
m.fw *= 0.5;
m.fh *= 0.5;
return 0;
}
i++;
}
fclose (file);
return -1;
}
// plot skymap
int
plot_skymap (void)
{
int redraw = 1, fov = 0, status;
float x, y;
char c, text[256], sra[16], sde[16], filename[LIM];
double ra, de, azi, alt, rx, ry;
xyz_t sunpos;
giza_set_colour_palette (1);
status = read_camera (fov);
if (status == -1)
{
fov = 0;
status = read_camera (fov);
}
for (;;)
{
if (redraw > 0)
{
// Get present mjd
if (m.mjd < 0.0)
{
nfd_now (m.nfd);
m.mjd = nfd2mjd (m.nfd);
}
// Get locations
if (strcmp (m.orientation, "horizontal") == 0)
horizontal2equatorial (m.mjd, m.azi0, m.alt0, &m.ra0, &m.de0);
else if (strcmp (m.orientation, "equatorial") == 0)
equatorial2horizontal (m.mjd, m.ra0, m.de0, &m.azi0, &m.alt0);
// Parallactic angle
m.q = parallactic_angle (m.mjd, m.ra0, m.de0);
// Get sun position
sunpos_xyz (m.mjd, &sunpos, &m.sra, &m.sde);
equatorial2horizontal (m.mjd, m.sra, m.sde, &m.sazi, &m.salt);
cpgscr (0, 0.0, 0.0, 0.0);
cpgeras ();
// Create window
cpgsvp (0.01, 0.99, 0.01, 0.99);
cpgwnad (-1.5 * m.w, 1.5 * m.w, -m.w, m.w);
// Set background
if (m.salt > 0.0)
cpgscr (0, 0.0, 0.0, 0.4);
else if (m.salt > -6.0)
cpgscr (0, 0.0, 0.0, 0.3);
else if (m.salt > -12.0)
cpgscr (0, 0.0, 0.0, 0.2);
else if (m.salt > -18.0)
cpgscr (0, 0.0, 0.0, 0.1);
else
cpgscr (0, 0.0, 0.0, 0.0);
cpgsci (0);
cpgrect (-1.5 * m.w, 1.5 * m.w, -m.w, m.w);
cpgsci (15);
cpgsch (1.0);
cpgbox ("BC", 0., 0, "BC", 0., 0);
cpgpt1 (0.0, 0.0, 2);
// Plot field-of-view
if (fov >= 0)
{
cpgsfs (2);
cpgrect (-m.fw, m.fw, -m.fh, m.fh);
cpgsfs (1);
}
// Top left string
cpgsch (0.8);
cpgsci (15);
mjd2date (m.mjd, m.nfd);
sprintf (text,
"%s UTC; %s (%04d) [%+.4f\\u\\(2218)\\d, %+.4f\\u\\(2218)\\d, %.0fm]",
m.nfd, m.observer, m.site_id, m.lat, m.lng,
m.alt * 1000.0);
cpgmtxt ("T", 0.6, 0.0, 0.0, text);
// Top right string
if (m.planar == 0)
{
if (Isatsel == 0)
{
if (m.leoflag == -1)
sprintf (text, "None");
else if (m.leoflag == 0)
sprintf (text, "All");
else if (m.leoflag == 1)
sprintf (text, "LEO");
else if (m.leoflag == 2)
sprintf (text, "HEO");
else if (m.leoflag == 3)
sprintf (text, "GEO");
else if (m.leoflag == 4)
sprintf (text, "GTO");
}
else if (Isatsel > 0)
{
sprintf (text, "%05d", (int) Isatsel);
}
else
{
strcpy (text, "");
}
}
else
{
if (Isatsel == 0)
{
if (m.leoflag == 0)
sprintf (text, "Planar search: %05d; All", m.pssatno);
else if (m.leoflag == 1)
sprintf (text, "Planar search: %05d; LEO", m.pssatno);
else if (m.leoflag == 2)
sprintf (text, "Planar search: %05d; HEO", m.pssatno);
else if (m.leoflag == 3)
sprintf (text, "Planar search: %05d; GEO", m.pssatno);
else if (m.leoflag == 4)
sprintf (text, "Planar search: %05d; GTO", m.pssatno);
}
else if (Isatsel > 0)
{
sprintf (text, "Planar search: %05d; %05d", m.pssatno,
(int) Isatsel);
}
else
{
sprintf (text, "Planar search: %05d", m.pssatno);
}
}
cpgmtxt ("T", 0.6, 1.0, 1.0, text);
// Bottom string
dec2s (m.ra0 / 15.0, sra, 0, 5);
dec2s (m.de0, sde, 0, 4);
sprintf (text,
"R:%s; D:%s; A: %.1f; E: %.1f; q: %.2f; S: %.1fx%.1f deg; L: %d; O: %s; m < %.1f; C: %s; l: %.0f s",
sra, sde, modulo (m.azi0 - 180.0, 360.0), m.alt0, m.q,
3.0 * m.w, 2.0 * m.w, m.level, m.orientation, m.maxmag,
m.camera, m.length);
cpgmtxt ("B", 1.0, 0.0, 0.0, text);
cpgsch (1.0);
// Plot everything
if (m.plotstars == 1)
{
sprintf (filename, "%s/data/constfig.dat", m.datadir);
skymap_plotconstellations (filename);
skymap_plotstars (m.starfile);
}
if (strcmp (m.orientation, "horizontal") == 0)
{
skymap_plothorizontal_grid ();
horizontal2equatorial (m.mjd, m.azi0, m.alt0, &m.ra0, &m.de0);
// skymap_plot_fov();
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
skymap_plotequatorial_grid ();
equatorial2horizontal (m.mjd, m.ra0, m.de0, &m.azi0, &m.alt0);
}
skymap_plotsun ();
skymap_plotmoon ();
if (m.plotapex == 1)
{
plot_apex (35786.0, 0.0);
plot_apex (39035, 63.4);
plot_apex (1100, 63.4);
// plot_apex(1100,63.4);
// plot_apex(1100,123.0);
plot_apex (800, 98.7);
plot_apex (1100, -63.4);
plot_apex (800, -98.7);
// plot_apex(480.0,141.7);
// plot_apex(400.0,40.0);
// plot_apex(320.0,38.0);
}
if (Isatsel >= 0 && m.leoflag >= 0)
{
cpgslw (1);
skymap_plotsatellite (m.tlefile, Isatsel, m.mjd, m.length);
}
}
// Reset redraw
redraw = 0;
// Plot planar search
if (m.planar == 1)
{
if (m.pssatno == 0)
printf ("Please select a satellite.\n");
else
planar_search (m.tlefile, m.pssatno, m.psrmin, m.psrmax, m.psnr,
m.graves);
}
// Plot IOD points
if (m.iodflag == 1)
plot_iod (m.iodfile);
// Plot XYZ position
if (m.xyzflag == 1)
plot_xyz (m.mjd, m.xyzfile);
// Plot visibility
if (m.visflag == 1 && strcmp (m.orientation, "horizontal") == 0)
plot_visibility (m.rvis);
// Graves visibility
if (m.graves == 2)
plot_graves_visibility ();
// Get time
cpgcurs (&x, &y, &c);
// Help
if (c == 'h' || c == 'H')
{
interactive_usage ();
}
// Toggle plotting stars
if (c == 'Q')
{
if (m.plotstars == 1)
m.plotstars = 0;
else if (m.plotstars == 0)
m.plotstars = 1;
redraw = 1;
}
// Toggle plotting apex
if (c == 'x')
{
if (m.plotapex == 1)
m.plotapex = 0;
else if (m.plotapex == 0)
m.plotapex = 1;
redraw = 1;
}
// Cycle IOD points
if (c == '\t')
{
m.iodpoint++;
read_iod (m.iodfile, m.iodpoint);
redraw = 1;
}
if (c == 'a')
{
printf ("Limit on age [d]: \n");
scanf ("%f", &m.agelimit);
redraw = 1;
}
// Toggle planar search
if (c == 'P')
{
if (m.planar == 0)
{
printf ("Provide altitude range (km): [min max num] ");
status = scanf ("%f %f %d", &m.psrmin, &m.psrmax, &m.psnr);
m.pssatno = Isatsel;
m.planar = 1;
}
else if (m.planar == 1)
{
m.pssatno = 0;
m.planar = 0;
}
redraw = 1;
}
// Toggle satellite name
if (c == 'p')
{
if (m.pflag == 1)
m.pflag = 0;
else if (m.pflag == 0)
m.pflag = 1;
redraw = 1;
continue;
}
// Toggle visibility contours
if (c == 'v')
{
if (m.visflag == 0)
{
printf ("Provide altitude (km): ");
status = scanf ("%f", &m.rvis);
m.visflag = 1;
}
else if (m.visflag == 1)
{
m.visflag = 0;
}
redraw = 1;
}
// Identify
if (c == 'i')
identify_satellite (m.tlefile, Isatsel, m.mjd, x, y);
// Read catalog
if (c == 'R')
{
printf ("TLE catalog name: ");
status = scanf ("%s", m.tlefile);
redraw = 1;
}
// Increase/decrease time
if (c == '.')
{
m.mjd += m.length / 86400.0;
redraw = 1;
}
if (c == ',')
{
m.mjd -= m.length / 86400.0;
redraw = 1;
}
// Increase/decrease step
if (c == '>')
{
m.length *= 2.0;
redraw = 2;
}
if (c == '<')
{
m.length /= 2.0;
redraw = 2;
}
// Reset
if (c == 'r')
{
Isatsel = 0;
m.length = 60.0;
m.mjd = -1.0;
m.iodpoint = -1;
redraw = 1;
}
if (c == 'l')
{
printf ("Enter integration length (s): ");
status = scanf ("%f", &m.length);
redraw = 1;
}
// Toggle focal length
if (c == 'F')
{
fov++;
status = read_camera (fov);
if (status == -1)
{
fov = 0;
status = read_camera (fov);
}
redraw = 1;
}
if (c == 'L')
{
if (Isatsel == 0)
{
m.leoflag++;
if (m.leoflag > 4)
m.leoflag = -1;
redraw = 1;
}
else
{
printf ("Unable, please reset satellite selection\n");
}
}
// Find satellite
if (c == 'f')
{
printf ("Enter NORAD Satellite number: ");
status = scanf ("%ld", &Isatsel);
if (Isatsel != 0 && !print_tle (m.tlefile, Isatsel))
{
printf ("Satellite %ld not found!\n", Isatsel);
Isatsel = -1;
}
redraw = 1;
}
// Measure
if (c == 'm')
{
if (strcmp (m.orientation, "horizontal") == 0)
{
reverse (x, y, &azi, &alt);
horizontal2equatorial (m.mjd, azi, alt, &ra, &de);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
reverse (x, y, &ra, &de);
equatorial2horizontal (m.mjd, ra, de, &azi, &alt);
}
printf ("RA: %10.4f Dec: %10.4f Azi: %10.4f Alt: %10.4f\n%f %f\n",
ra, de, modulo (azi - 180.0, 360.0), alt, x, y);
}
// Format IOD output
if (c == 'I')
format_iod (m.mjd, m.ra0, m.de0, m.site_id);
// Grid on/off
if (c == 'g')
{
if (m.grid == 1)
m.grid = 0;
else if (m.grid == 0)
m.grid = 1;
redraw = 1;
}
// Toggle Graves illumination
if (c == 'G')
{
m.graves++;
if (m.graves == 3)
m.graves = 0;
redraw = 1;
}
// Exit
if (c == 'q')
{
//cpgend (); // "Press RETURN for next page:"
exit (0);
}
// Recenter
if (c == 'c' || c == 'C')
{
if (strcmp (m.orientation, "horizontal") == 0)
{
reverse (x, y, &m.azi0, &m.alt0);
horizontal2equatorial (m.mjd, m.azi0, m.alt0, &m.ra0, &m.de0);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
reverse (x, y, &m.ra0, &m.de0);
horizontal2equatorial (m.mjd, m.ra0, m.de0, &m.azi0, &m.alt0);
}
printf ("Centered at: %8.4f %8.4f, %8.4f %8.4f\n", m.ra0, m.de0,
m.azi0, m.alt0);
redraw = 1;
}
// Add to schedule
if (c == 'S')
schedule (m.nfd, m.ra0, m.de0, "start");
// Add to schedule
if (c == 'E')
schedule (m.nfd, m.ra0, m.de0, "stop");
// Polar
if (c == 'z')
{
m.azi0 = 180.0;
m.alt0 = 90.0;
m.w = 120.0;
strcpy (m.orientation, "horizontal");
m.level = 1;
redraw = 1;
}
// South
if (c == 's')
{
m.azi0 = 0.0;
m.alt0 = 45.0;
strcpy (m.orientation, "horizontal");
m.level = 3;
redraw = 1;
}
// North
if (c == 'n')
{
m.azi0 = 180.0;
m.alt0 = 45.0;
strcpy (m.orientation, "horizontal");
m.level = 3;
redraw = 1;
}
// East
if (c == 'e')
{
m.azi0 = 270.0;
m.alt0 = 45.0;
strcpy (m.orientation, "horizontal");
m.level = 3;
redraw = 1;
}
// West
if (c == 'w')
{
m.azi0 = 90.0;
m.alt0 = 45.0;
strcpy (m.orientation, "horizontal");
m.level = 3;
redraw = 1;
}
// Orientation
if (c == 'o' || c == 'O')
{
if (strcmp (m.orientation, "horizontal") == 0)
{
strcpy (m.orientation, "equatorial");
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
strcpy (m.orientation, "horizontal");
}
redraw = 1;
}
// Level
if (isdigit (c))
{
m.level = c - '0';
redraw = 1;
}
// Zoom
if (c == '-' && m.level > 1)
{
m.level--;
redraw = 1;
}
if ((c == '+' || c == '=') && m.level < 9)
{
m.level++;
redraw = 1;
}
// renew
skymap_plot_renew ();
}
return 0;
}
// rotate vector
void
rotate (int axis, float angle, float *x, float *y, float *z)
{
float xx, yy, zz;
if (axis == 0)
{
xx = *x;
yy = *y * cos (angle * D2R) - *z * sin (angle * D2R);
zz = *z * cos (angle * D2R) + *y * sin (angle * D2R);
}
if (axis == 1)
{
xx = *x * cos (angle * D2R) - *z * sin (angle * D2R);
yy = *y;
zz = *z * cos (angle * D2R) + *x * sin (angle * D2R);
}
if (axis == 2)
{
xx = *x * cos (angle * D2R) - *y * sin (angle * D2R);
yy = *y * cos (angle * D2R) + *x * sin (angle * D2R);
zz = *z;
}
*x = xx;
*y = yy;
*z = zz;
return;
}
// Compute Date from Julian Day
void
mjd2date (double mjd, char *date)
{
double f, jd, dday;
int z, alpha, a, b, c, d, e;
int year, month, day, hour, min;
float sec, x;
jd = mjd + 2400000.5;
jd += 0.5;
z = floor (jd);
f = fmod (jd, 1.);
if (z < 2299161)
a = z;
else
{
alpha = floor ((z - 1867216.25) / 36524.25);
a = z + 1 + alpha - floor (alpha / 4.);
}
b = a + 1524;
c = floor ((b - 122.1) / 365.25);
d = floor (365.25 * c);
e = floor ((b - d) / 30.6001);
dday = b - d - floor (30.6001 * e) + f;
if (e < 14)
month = e - 1;
else
month = e - 13;
if (month > 2)
year = c - 4716;
else
year = c - 4715;
day = (int) floor (dday);
x = 24.0 * (dday - day);
x = 3600. * fabs (x) + 0.0001;
sec = fmod (x, 60.);
x = (x - sec) / 60.;
min = fmod (x, 60.);
x = (x - min) / 60.;
hour = x;
sec = floor (1000.0 * sec) / 1000.0;
sprintf (date, "%04d-%02d-%02dT%02d:%02d:%06.3f", year, month, day, hour,
min, sec);
return;
}
// Compute Date from Julian Day in IOD format
void
mjd2date_iod (double mjd, char *date)
{
double f, jd, dday;
int z, alpha, a, b, c, d, e;
int year, month, day, hour, min;
float sec, x, fsec;
jd = mjd + 2400000.5;
jd += 0.5;
z = floor (jd);
f = fmod (jd, 1.);
if (z < 2299161)
a = z;
else
{
alpha = floor ((z - 1867216.25) / 36524.25);
a = z + 1 + alpha - floor (alpha / 4.);
}
b = a + 1524;
c = floor ((b - 122.1) / 365.25);
d = floor (365.25 * c);
e = floor ((b - d) / 30.6001);
dday = b - d - floor (30.6001 * e) + f;
if (e < 14)
month = e - 1;
else
month = e - 13;
if (month > 2)
year = c - 4716;
else
year = c - 4715;
day = (int) floor (dday);
x = 24.0 * (dday - day);
x = 3600. * fabs (x) + 0.0001;
sec = fmod (x, 60.);
x = (x - sec) / 60.;
min = fmod (x, 60.);
x = (x - min) / 60.;
hour = x;
fsec = floor (1000.0 * (sec - floor (sec)));
sprintf (date, "%04d%02d%02d%02d%02d%02.0f%03.0f", (int) year, (int) month,
(int) day, (int) hour, (int) min, floor (sec), fsec);
return;
}
// Convert Decimal into Sexagesimal
void
dec2s (double x, char *s, int f, int len)
{
int i;
double sec, deg, min;
char sign;
char *form[] = { "::", ",,", "hms", " " };
sign = (x < 0 ? '-' : ' ');
x = 3600. * fabs (x);
sec = fmod (x, 60.);
x = (x - sec) / 60.;
min = fmod (x, 60.);
x = (x - min) / 60.;
// deg=fmod(x,60.);
deg = x;
if (len == 7)
sprintf (s, "%c%02i%c%02i%c%07.4f%c", sign, (int) deg, form[f][0],
(int) min, form[f][1], sec, form[f][2]);
if (len == 6)
sprintf (s, "%c%02i%c%02i%c%06.3f%c", sign, (int) deg, form[f][0],
(int) min, form[f][1], sec, form[f][2]);
if (len == 5)
sprintf (s, "%c%02i%c%02i%c%05.2f%c", sign, (int) deg, form[f][0],
(int) min, form[f][1], sec, form[f][2]);
if (len == 4)
sprintf (s, "%c%02i%c%02i%c%04.1f%c", sign, (int) deg, form[f][0],
(int) min, form[f][1], sec, form[f][2]);
if (len == 2)
sprintf (s, "%c%02i%c%02i%c%02i%c", sign, (int) deg, form[f][0],
(int) min, form[f][1], (int) floor (sec), form[f][2]);
return;
}
// Convert Decimal into Sexagesimal
void
dec2s_iod (double x, char *s, int type)
{
int i;
double sec, deg, min, fmin;
char sign;
sign = (x < 0 ? '-' : '+');
x = 60. * fabs (x);
min = fmod (x, 60.);
x = (x - min) / 60.;
// deg=fmod(x,60.);
deg = x;
if (type == 0)
fmin = floor (1000.0 * (min - floor (min)));
else
fmin = floor (100.0 * (min - floor (min)));
if (type == 0)
sprintf (s, "%02.0f%02.0f%03.0f", deg, floor (min), fmin);
else
sprintf (s, "%c%02.0f%02.0f%02.0f", sign, deg, floor (min), fmin);
return;
}
// Greenwich Mean Sidereal Time
double
dgmst (double mjd)
{
double t, dgmst;
t = (mjd - 51544.5) / 36525.0;
dgmst = 360.98564736629 + t * (0.000387933 - t / 38710000);
return dgmst;
}
// Precess a celestial position
void
precess (double mjd0, double ra0, double de0, double mjd, double *ra,
double *de)
{
double t0, t;
double zeta, z, theta;
double a, b, c;
// Angles in radians
ra0 *= D2R;
de0 *= D2R;
// 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;
a = cos (de0) * sin (ra0 + zeta);
b = cos (theta) * cos (de0) * cos (ra0 + zeta) - sin (theta) * sin (de0);
c = sin (theta) * cos (de0) * cos (ra0 + zeta) + cos (theta) * sin (de0);
*ra = (atan2 (a, b) + z) * R2D;
*de = asin (c) * R2D;
if (*ra < 360.0)
*ra += 360.0;
if (*ra > 360.0)
*ra -= 360.0;
return;
}
// Convert Sexagesimal into Decimal
double
s2dec (char *s)
{
double x;
float deg, min, sec;
char t[LIM];
strcpy (t, s);
deg = fabs (atof (strtok (t, " :")));
min = fabs (atof (strtok (NULL, " :")));
sec = fabs (atof (strtok (NULL, " :")));
x = (double) deg + (double) min / 60. + (double) sec / 3600.;
if (s[0] == '-')
x = -x;
return x;
}
// DOY to MJD
double
doy2mjd (int year, double doy)
{
int month, k = 2;
double day;
if (year % 4 == 0 && year % 400 != 0)
k = 1;
month = floor (9.0 * (k + doy) / 275.0 + 0.98);
if (doy < 32)
month = 1;
day =
doy - floor (275.0 * month / 9.0) + k * floor ((month + 9.0) / 12.0) +
30.0;
return date2mjd (year, month, day);
}
// Decode IOD Observations
struct observation
decode_iod_observation (char *iod_line)
{
int year, month, iday, hour, min;
int format, epoch, me, xe, sign;
int site_id;
double sec, ra, mm, ss, de, dd, ds, day, mjd0;
struct observation obs;
char secbuf[6], sn[2], degbuf[3];
// Strip newline
iod_line[strlen (iod_line) - 1] = '\0';
// Copy full line
strcpy (obs.iod_line, iod_line);
// Set usage
obs.flag = 1;
// Get SSN
sscanf (iod_line, "%5d", &obs.ssn);
// Get site
sscanf (iod_line + 16, "%4d", &obs.site);
// Decode date/time
sscanf (iod_line + 23, "%4d%2d%2d%2d%2d%5s", &year, &month, &iday, &hour,
&min, secbuf);
sec = atof (secbuf);
sec /= pow (10, strlen (secbuf) - 2);
day =
(double) iday + (double) hour / 24.0 + (double) min / 1440.0 +
(double) sec / 86400.0;
obs.mjd = date2mjd (year, month, day);
// Get uncertainty in time
sscanf (iod_line + 41, "%1d%1d", &me, &xe);
obs.st = (float) me *pow (10, xe - 8);
// Skip empty observations
if (strlen (iod_line) < 64 || (iod_line[54] != '+' && iod_line[54] != '-'))
obs.flag = 0;
// Get format, epoch
sscanf (iod_line + 44, "%1d%1d", &format, &epoch);
// Read position
sscanf (iod_line + 47, "%2lf%2lf%3lf%1s", &ra, &mm, &ss, sn);
sscanf (iod_line + 55, "%2lf%2lf%2s", &de, &dd, degbuf);
ds = atof (degbuf);
if (strlen (degbuf) == 1)
ds *= 10;
sign = (sn[0] == '-') ? -1 : 1;
sscanf (iod_line + 62, "%1d%1d", &me, &xe);
obs.sr = (float) me *pow (10, xe - 8);
// Decode position
switch (format)
{
// Format 1: RA/DEC = HHMMSSs+DDMMSS MX (MX in seconds of arc)
case 1:
ra += mm / 60 + ss / 36000;
de = sign * (de + dd / 60 + ds / 3600);
obs.sr /= 3600.0;
break;
// Format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc)
case 2:
ra += mm / 60 + ss / 60000;
de = sign * (de + dd / 60 + ds / 6000);
obs.sr /= 60.0;
break;
// Format 3: RA/DEC = HHMMmmm+DDdddd MX (MX in degrees of arc)
case 3:
ra += mm / 60 + ss / 60000;
de = sign * (de + dd / 100 + ds / 10000);
break;
// Format 7: RA/DEC = HHMMSSs+DDdddd MX (MX in degrees of arc)
case 7:
ra += mm / 60 + ss / 36000;
de = sign * (de + dd / 100 + ds / 10000);
break;
default:
printf ("%s\n", iod_line);
printf ("IOD Format not implemented\n");
obs.flag = 0;
break;
}
// Convert to degrees
ra *= 15.0;
// Get precession epoch
if (epoch == 0)
{
obs.ra = ra;
obs.de = de;
return obs;
}
else if (epoch == 4)
{
mjd0 = 33281.9235;
}
else if (epoch == 5)
{
mjd0 = 51544.5;
}
else
{
printf ("Observing epoch not implemented\n");
obs.flag = 0;
}
// Precess position
precess (mjd0, ra, de, obs.mjd, &obs.ra, &obs.de);
// Get horizontal position
equatorial2horizontal (obs.mjd, obs.ra, obs.de, &obs.azi, &obs.alt);
return obs;
}
void
plot_iod (char *filename)
{
int i = 0;
char line[LIM];
FILE *file;
struct observation obs;
double azi, alt, rx, ry;
float x, y;
cpgsci (2);
file = fopen (filename, "r");
// Read data
while (fgets (line, LIM, file) != NULL)
{
if (strstr (line, "#") == NULL)
{
obs = decode_iod_observation (line);
if (m.site_id == obs.site)
{
if (strcmp (m.orientation, "horizontal") == 0)
{
forward (obs.azi, obs.alt, &rx, &ry);
}
else if (strcmp (m.orientation, "equatorial") == 0)
{
forward (obs.ra, obs.de, &rx, &ry);
}
x = (float) rx;
y = (float) ry;
cpgpt1 (x, y, 4);
}
}
}
fclose (file);
cpgsci (1);
return;
}
// Moon position
void
lunpos_xyz (double mjd, xyz_t * pos, double *ra, double *de)
{
int i;
double t, t2, t3, t4;
double l1, d, m, m1, f, a1, a2, a3, e, ef;
double suml, sumb, sumr, arglr, argb;
double l, b, r;
// Julian Centuries
t = (mjd - 51544.5) / 36525.0;
// Powers of t
t2 = t * t;
t3 = t2 * t;
t4 = t3 * t;
// angles
l1 =
modulo (218.3164477 + 481267.88123421 * t - 0.0015786 * t2 +
t3 / 538841.0 - t4 / 65194000.0, 360.0) * D2R;
d =
modulo (297.8501921 + 445267.1114034 * t - 0.0018819 * t2 +
t3 / 545868.0 - t4 / 113065000.0, 360.0) * D2R;
m =
modulo (357.5291092 + 35999.0502909 * t - 0.0001536 * t2 +
t3 / 24490000.0, 360.0) * D2R;
m1 =
modulo (134.9633964 + 477198.8675055 * t + 0.0087417 * t2 + t3 / 69699.0 -
t4 / 14712000.0, 360.0) * D2R;
f =
modulo (93.2720950 + 483202.0175233 * t - 0.0036539 * t2 -
t3 / 3526000.0 + t4 / 86331000.0, 360.0) * D2R;
a1 = modulo (119.75 + 131.849 * t, 360.0) * D2R;
a2 = modulo (53.09 + 479264.290 * t, 360.0) * D2R;
a3 = modulo (313.45 + 481266.484 * t, 360.0) * D2R;
e = 1.0 - 0.002516 * t - 0.0000074 * t2;
// Compute sums
for (i = 0, suml = sumb = sumr = 0.0; i < 60; i++)
{
// Arguments
arglr = clr[i].nd * d + clr[i].nm * m + clr[i].nm1 * m1 + clr[i].nf * f;
argb = cb[i].nd * d + cb[i].nm * m + cb[i].nm1 * m1 + cb[i].nf * f;
// E multiplication factor
if (abs (clr[i].nm) == 1)
ef = e;
else if (abs (clr[i].nm) == 2)
ef = e * e;
else
ef = 1.0;
// Sums
suml += clr[i].sa * sin (arglr) * ef;
sumr += clr[i].ca * cos (arglr) * ef;
// E multiplication factor
if (abs (cb[i].nm) == 1)
ef = e;
else if (abs (cb[i].nm) == 2)
ef = e * e;
else
ef = 1.0;
// Sums
sumb += cb[i].sa * sin (argb) * ef;
}
// Additives
suml += 3958 * sin (a1) + 1962 * sin (l1 - f) + 318 * sin (a2);
sumb +=
-2235 * sin (l1) + 382 * sin (a3) + 175 * sin (a1 - f) + 175 * sin (a1 +
f) +
127 * sin (l1 - m1) - 115 * sin (l1 + m1);
// Ecliptic longitude, latitude and distance
l = modulo (l1 * R2D + suml / 1000000.0, 360.0);
b = sumb / 1000000.0;
r = 385000.56 + sumr / 1000.0;
// Equatorial
ecliptical2equatorial (l, b, ra, de);
// Position
pos->x = r * cos (*de * D2R) * cos (*ra * D2R);
pos->y = r * cos (*de * D2R) * sin (*ra * D2R);
pos->z = r * sin (*de * D2R);
return;
}
// Convert ecliptical into equatorial coordinates
void
ecliptical2equatorial (double l, double b, double *ra, double *de)
{
double eps = 23.4392911;
*ra =
modulo (atan2
(sin (l * D2R) * cos (eps * D2R) -
tan (b * D2R) * sin (eps * D2R), cos (l * D2R)) * R2D, 360.0);
*de =
asin (sin (b * D2R) * cos (eps * D2R) +
cos (b * D2R) * sin (eps * D2R) * sin (l * D2R)) * R2D;
return;
}