Annotation of embedaddon/ntp/clockstuff/propdelay.c, revision 1.1.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>