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