Annotation of embedaddon/ntp/clockstuff/propdelay.c, revision 1.1
1.1 ! misho 1: /* propdelay.c,v 3.1 1993/07/06 01:05:24 jbj Exp
! 2: * propdelay - compute propagation delays
! 3: *
! 4: * cc -o propdelay propdelay.c -lm
! 5: *
! 6: * "Time and Frequency Users' Manual", NBS Technical Note 695 (1977).
! 7: */
! 8:
! 9: /*
! 10: * This can be used to get a rough idea of the HF propagation delay
! 11: * between two points (usually between you and the radio station).
! 12: * The usage is
! 13: *
! 14: * propdelay latitudeA longitudeA latitudeB longitudeB
! 15: *
! 16: * where points A and B are the locations in question. You obviously
! 17: * need to know the latitude and longitude of each of the places.
! 18: * The program expects the latitude to be preceded by an 'n' or 's'
! 19: * and the longitude to be preceded by an 'e' or 'w'. It understands
! 20: * either decimal degrees or degrees:minutes:seconds. Thus to compute
! 21: * the delay between the WWVH (21:59:26N, 159:46:00W) and WWV (40:40:49N,
! 22: * 105:02:27W) you could use:
! 23: *
! 24: * propdelay n21:59:26 w159:46 n40:40:49 w105:02:27
! 25: *
! 26: * By default it prints out a summer (F2 average virtual height 350 km) and
! 27: * winter (F2 average virtual height 250 km) number. The results will be
! 28: * quite approximate but are about as good as you can do with HF time anyway.
! 29: * You might pick a number between the values to use, or use the summer
! 30: * value in the summer and switch to the winter value when the static
! 31: * above 10 MHz starts to drop off in the fall. You can also use the
! 32: * -h switch if you want to specify your own virtual height.
! 33: *
! 34: * You can also do a
! 35: *
! 36: * propdelay -W n45:17:47 w75:45:22
! 37: *
! 38: * to find the propagation delays to WWV and WWVH (from CHU in this
! 39: * case), a
! 40: *
! 41: * propdelay -C n40:40:49 w105:02:27
! 42: *
! 43: * to find the delays to CHU, and a
! 44: *
! 45: * propdelay -G n52:03:17 w98:34:18
! 46: *
! 47: * to find delays to GOES via each of the three satellites.
! 48: */
! 49:
! 50: #include <stdio.h>
! 51: #include <string.h>
! 52:
! 53: #include "ntp_stdlib.h"
! 54:
! 55: extern double sin (double);
! 56: extern double cos (double);
! 57: extern double acos (double);
! 58: extern double tan (double);
! 59: extern double atan (double);
! 60: extern double sqrt (double);
! 61:
! 62: #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
! 63:
! 64: /*
! 65: * Program constants
! 66: */
! 67: #define EARTHRADIUS (6370.0) /* raduis of earth (km) */
! 68: #define LIGHTSPEED (299800.0) /* speed of light, km/s */
! 69: #define PI (3.1415926536)
! 70: #define RADPERDEG (PI/180.0) /* radians per degree */
! 71: #define MILE (1.609344) /* km in a mile */
! 72:
! 73: #define SUMMERHEIGHT (350.0) /* summer height in km */
! 74: #define WINTERHEIGHT (250.0) /* winter height in km */
! 75:
! 76: #define SATHEIGHT (6.6110 * 6378.0) /* geosync satellite height in km
! 77: from centre of earth */
! 78:
! 79: #define WWVLAT "n40:40:49"
! 80: #define WWVLONG "w105:02:27"
! 81:
! 82: #define WWVHLAT "n21:59:26"
! 83: #define WWVHLONG "w159:46:00"
! 84:
! 85: #define CHULAT "n45:17:47"
! 86: #define CHULONG "w75:45:22"
! 87:
! 88: #define GOES_UP_LAT "n37:52:00"
! 89: #define GOES_UP_LONG "w75:27:00"
! 90: #define GOES_EAST_LONG "w75:00:00"
! 91: #define GOES_STBY_LONG "w105:00:00"
! 92: #define GOES_WEST_LONG "w135:00:00"
! 93: #define GOES_SAT_LAT "n00:00:00"
! 94:
! 95: char *wwvlat = WWVLAT;
! 96: char *wwvlong = WWVLONG;
! 97:
! 98: char *wwvhlat = WWVHLAT;
! 99: char *wwvhlong = WWVHLONG;
! 100:
! 101: char *chulat = CHULAT;
! 102: char *chulong = CHULONG;
! 103:
! 104: char *goes_up_lat = GOES_UP_LAT;
! 105: char *goes_up_long = GOES_UP_LONG;
! 106: char *goes_east_long = GOES_EAST_LONG;
! 107: char *goes_stby_long = GOES_STBY_LONG;
! 108: char *goes_west_long = GOES_WEST_LONG;
! 109: char *goes_sat_lat = GOES_SAT_LAT;
! 110:
! 111: int hflag = 0;
! 112: int Wflag = 0;
! 113: int Cflag = 0;
! 114: int Gflag = 0;
! 115: int height;
! 116:
! 117: char *progname;
! 118: volatile int debug;
! 119:
! 120: static void doit (double, double, double, double, double, char *);
! 121: static double latlong (char *, int);
! 122: static double greatcircle (double, double, double, double);
! 123: static double waveangle (double, double, int);
! 124: static double propdelay (double, double, int);
! 125: static int finddelay (double, double, double, double, double, double *);
! 126: static void satdoit (double, double, double, double, double, double, char *);
! 127: static void satfinddelay (double, double, double, double, double *);
! 128: static double satpropdelay (double);
! 129:
! 130: /*
! 131: * main - parse arguments and handle options
! 132: */
! 133: int
! 134: main(
! 135: int argc,
! 136: char *argv[]
! 137: )
! 138: {
! 139: int c;
! 140: int errflg = 0;
! 141: double lat1, long1;
! 142: double lat2, long2;
! 143: double lat3, long3;
! 144:
! 145: progname = argv[0];
! 146: while ((c = ntp_getopt(argc, argv, "dh:CWG")) != EOF)
! 147: switch (c) {
! 148: case 'd':
! 149: ++debug;
! 150: break;
! 151: case 'h':
! 152: hflag++;
! 153: height = atof(ntp_optarg);
! 154: if (height <= 0.0) {
! 155: (void) fprintf(stderr, "height %s unlikely\n",
! 156: ntp_optarg);
! 157: errflg++;
! 158: }
! 159: break;
! 160: case 'C':
! 161: Cflag++;
! 162: break;
! 163: case 'W':
! 164: Wflag++;
! 165: break;
! 166: case 'G':
! 167: Gflag++;
! 168: break;
! 169: default:
! 170: errflg++;
! 171: break;
! 172: }
! 173: if (errflg || (!(Cflag || Wflag || Gflag) && ntp_optind+4 != argc) ||
! 174: ((Cflag || Wflag || Gflag) && ntp_optind+2 != argc)) {
! 175: (void) fprintf(stderr,
! 176: "usage: %s [-d] [-h height] lat1 long1 lat2 long2\n",
! 177: progname);
! 178: (void) fprintf(stderr," - or -\n");
! 179: (void) fprintf(stderr,
! 180: "usage: %s -CWG [-d] lat long\n",
! 181: progname);
! 182: exit(2);
! 183: }
! 184:
! 185:
! 186: if (!(Cflag || Wflag || Gflag)) {
! 187: lat1 = latlong(argv[ntp_optind], 1);
! 188: long1 = latlong(argv[ntp_optind + 1], 0);
! 189: lat2 = latlong(argv[ntp_optind + 2], 1);
! 190: long2 = latlong(argv[ntp_optind + 3], 0);
! 191: if (hflag) {
! 192: doit(lat1, long1, lat2, long2, height, "");
! 193: } else {
! 194: doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT,
! 195: "summer propagation, ");
! 196: doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT,
! 197: "winter propagation, ");
! 198: }
! 199: } else if (Wflag) {
! 200: /*
! 201: * Compute delay from WWV
! 202: */
! 203: lat1 = latlong(argv[ntp_optind], 1);
! 204: long1 = latlong(argv[ntp_optind + 1], 0);
! 205: lat2 = latlong(wwvlat, 1);
! 206: long2 = latlong(wwvlong, 0);
! 207: if (hflag) {
! 208: doit(lat1, long1, lat2, long2, height, "WWV ");
! 209: } else {
! 210: doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT,
! 211: "WWV summer propagation, ");
! 212: doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT,
! 213: "WWV winter propagation, ");
! 214: }
! 215:
! 216: /*
! 217: * Compute delay from WWVH
! 218: */
! 219: lat2 = latlong(wwvhlat, 1);
! 220: long2 = latlong(wwvhlong, 0);
! 221: if (hflag) {
! 222: doit(lat1, long1, lat2, long2, height, "WWVH ");
! 223: } else {
! 224: doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT,
! 225: "WWVH summer propagation, ");
! 226: doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT,
! 227: "WWVH winter propagation, ");
! 228: }
! 229: } else if (Cflag) {
! 230: lat1 = latlong(argv[ntp_optind], 1);
! 231: long1 = latlong(argv[ntp_optind + 1], 0);
! 232: lat2 = latlong(chulat, 1);
! 233: long2 = latlong(chulong, 0);
! 234: if (hflag) {
! 235: doit(lat1, long1, lat2, long2, height, "CHU ");
! 236: } else {
! 237: doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT,
! 238: "CHU summer propagation, ");
! 239: doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT,
! 240: "CHU winter propagation, ");
! 241: }
! 242: } else if (Gflag) {
! 243: lat1 = latlong(goes_up_lat, 1);
! 244: long1 = latlong(goes_up_long, 0);
! 245: lat3 = latlong(argv[ntp_optind], 1);
! 246: long3 = latlong(argv[ntp_optind + 1], 0);
! 247:
! 248: lat2 = latlong(goes_sat_lat, 1);
! 249:
! 250: long2 = latlong(goes_west_long, 0);
! 251: satdoit(lat1, long1, lat2, long2, lat3, long3,
! 252: "GOES Delay via WEST");
! 253:
! 254: long2 = latlong(goes_stby_long, 0);
! 255: satdoit(lat1, long1, lat2, long2, lat3, long3,
! 256: "GOES Delay via STBY");
! 257:
! 258: long2 = latlong(goes_east_long, 0);
! 259: satdoit(lat1, long1, lat2, long2, lat3, long3,
! 260: "GOES Delay via EAST");
! 261:
! 262: }
! 263: exit(0);
! 264: }
! 265:
! 266:
! 267: /*
! 268: * doit - compute a delay and print it
! 269: */
! 270: static void
! 271: doit(
! 272: double lat1,
! 273: double long1,
! 274: double lat2,
! 275: double long2,
! 276: double h,
! 277: char *str
! 278: )
! 279: {
! 280: int hops;
! 281: double delay;
! 282:
! 283: hops = finddelay(lat1, long1, lat2, long2, h, &delay);
! 284: printf("%sheight %g km, hops %d, delay %g seconds\n",
! 285: str, h, hops, delay);
! 286: }
! 287:
! 288:
! 289: /*
! 290: * latlong - decode a latitude/longitude value
! 291: */
! 292: static double
! 293: latlong(
! 294: char *str,
! 295: int islat
! 296: )
! 297: {
! 298: register char *cp;
! 299: register char *bp;
! 300: double arg;
! 301: double divby;
! 302: int isneg;
! 303: char buf[32];
! 304: char *colon;
! 305:
! 306: if (islat) {
! 307: /*
! 308: * Must be north or south
! 309: */
! 310: if (*str == 'N' || *str == 'n')
! 311: isneg = 0;
! 312: else if (*str == 'S' || *str == 's')
! 313: isneg = 1;
! 314: else
! 315: isneg = -1;
! 316: } else {
! 317: /*
! 318: * East is positive, west is negative
! 319: */
! 320: if (*str == 'E' || *str == 'e')
! 321: isneg = 0;
! 322: else if (*str == 'W' || *str == 'w')
! 323: isneg = 1;
! 324: else
! 325: isneg = -1;
! 326: }
! 327:
! 328: if (isneg >= 0)
! 329: str++;
! 330:
! 331: colon = strchr(str, ':');
! 332: if (colon != NULL) {
! 333: /*
! 334: * in hhh:mm:ss form
! 335: */
! 336: cp = str;
! 337: bp = buf;
! 338: while (cp < colon)
! 339: *bp++ = *cp++;
! 340: *bp = '\0';
! 341: cp++;
! 342: arg = atof(buf);
! 343: divby = 60.0;
! 344: colon = strchr(cp, ':');
! 345: if (colon != NULL) {
! 346: bp = buf;
! 347: while (cp < colon)
! 348: *bp++ = *cp++;
! 349: *bp = '\0';
! 350: cp++;
! 351: arg += atof(buf) / divby;
! 352: divby = 3600.0;
! 353: }
! 354: if (*cp != '\0')
! 355: arg += atof(cp) / divby;
! 356: } else {
! 357: arg = atof(str);
! 358: }
! 359:
! 360: if (isneg == 1)
! 361: arg = -arg;
! 362:
! 363: if (debug > 2)
! 364: (void) printf("latitude/longitude %s = %g\n", str, arg);
! 365:
! 366: return arg;
! 367: }
! 368:
! 369:
! 370: /*
! 371: * greatcircle - compute the great circle distance in kilometers
! 372: */
! 373: static double
! 374: greatcircle(
! 375: double lat1,
! 376: double long1,
! 377: double lat2,
! 378: double long2
! 379: )
! 380: {
! 381: double dg;
! 382: double l1r, l2r;
! 383:
! 384: l1r = lat1 * RADPERDEG;
! 385: l2r = lat2 * RADPERDEG;
! 386: dg = EARTHRADIUS * acos(
! 387: (cos(l1r) * cos(l2r) * cos((long2-long1)*RADPERDEG))
! 388: + (sin(l1r) * sin(l2r)));
! 389: if (debug >= 2)
! 390: printf(
! 391: "greatcircle lat1 %g long1 %g lat2 %g long2 %g dist %g\n",
! 392: lat1, long1, lat2, long2, dg);
! 393: return dg;
! 394: }
! 395:
! 396:
! 397: /*
! 398: * waveangle - compute the wave angle for the given distance, virtual
! 399: * height and number of hops.
! 400: */
! 401: static double
! 402: waveangle(
! 403: double dg,
! 404: double h,
! 405: int n
! 406: )
! 407: {
! 408: double theta;
! 409: double delta;
! 410:
! 411: theta = dg / (EARTHRADIUS * (double)(2 * n));
! 412: delta = atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2)) - theta;
! 413: if (debug >= 2)
! 414: printf("waveangle dist %g height %g hops %d angle %g\n",
! 415: dg, h, n, delta / RADPERDEG);
! 416: return delta;
! 417: }
! 418:
! 419:
! 420: /*
! 421: * propdelay - compute the propagation delay
! 422: */
! 423: static double
! 424: propdelay(
! 425: double dg,
! 426: double h,
! 427: int n
! 428: )
! 429: {
! 430: double phi;
! 431: double theta;
! 432: double td;
! 433:
! 434: theta = dg / (EARTHRADIUS * (double)(2 * n));
! 435: phi = (PI/2.0) - atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2));
! 436: td = dg / (LIGHTSPEED * sin(phi));
! 437: if (debug >= 2)
! 438: printf("propdelay dist %g height %g hops %d time %g\n",
! 439: dg, h, n, td);
! 440: return td;
! 441: }
! 442:
! 443:
! 444: /*
! 445: * finddelay - find the propagation delay
! 446: */
! 447: static int
! 448: finddelay(
! 449: double lat1,
! 450: double long1,
! 451: double lat2,
! 452: double long2,
! 453: double h,
! 454: double *delay
! 455: )
! 456: {
! 457: double dg; /* great circle distance */
! 458: double delta; /* wave angle */
! 459: int n; /* number of hops */
! 460:
! 461: dg = greatcircle(lat1, long1, lat2, long2);
! 462: if (debug)
! 463: printf("great circle distance %g km %g miles\n", dg, dg/MILE);
! 464:
! 465: n = 1;
! 466: while ((delta = waveangle(dg, h, n)) < 0.0) {
! 467: if (debug)
! 468: printf("tried %d hop%s, no good\n", n, n>1?"s":"");
! 469: n++;
! 470: }
! 471: if (debug)
! 472: printf("%d hop%s okay, wave angle is %g\n", n, n>1?"s":"",
! 473: delta / RADPERDEG);
! 474:
! 475: *delay = propdelay(dg, h, n);
! 476: return n;
! 477: }
! 478:
! 479: /*
! 480: * satdoit - compute a delay and print it
! 481: */
! 482: static void
! 483: satdoit(
! 484: double lat1,
! 485: double long1,
! 486: double lat2,
! 487: double long2,
! 488: double lat3,
! 489: double long3,
! 490: char *str
! 491: )
! 492: {
! 493: double up_delay,down_delay;
! 494:
! 495: satfinddelay(lat1, long1, lat2, long2, &up_delay);
! 496: satfinddelay(lat3, long3, lat2, long2, &down_delay);
! 497:
! 498: printf("%s, delay %g seconds\n", str, up_delay + down_delay);
! 499: }
! 500:
! 501: /*
! 502: * satfinddelay - calculate the one-way delay time between a ground station
! 503: * and a satellite
! 504: */
! 505: static void
! 506: satfinddelay(
! 507: double lat1,
! 508: double long1,
! 509: double lat2,
! 510: double long2,
! 511: double *delay
! 512: )
! 513: {
! 514: double dg; /* great circle distance */
! 515:
! 516: dg = greatcircle(lat1, long1, lat2, long2);
! 517:
! 518: *delay = satpropdelay(dg);
! 519: }
! 520:
! 521: /*
! 522: * satpropdelay - calculate the one-way delay time between a ground station
! 523: * and a satellite
! 524: */
! 525: static double
! 526: satpropdelay(
! 527: double dg
! 528: )
! 529: {
! 530: double k1, k2, dist;
! 531: double theta;
! 532: double td;
! 533:
! 534: theta = dg / (EARTHRADIUS);
! 535: k1 = EARTHRADIUS * sin(theta);
! 536: k2 = SATHEIGHT - (EARTHRADIUS * cos(theta));
! 537: if (debug >= 2)
! 538: printf("Theta %g k1 %g k2 %g\n", theta, k1, k2);
! 539: dist = sqrt(k1*k1 + k2*k2);
! 540: td = dist / LIGHTSPEED;
! 541: if (debug >= 2)
! 542: printf("propdelay dist %g height %g time %g\n", dg, dist, td);
! 543: return td;
! 544: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>