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>