diff --git a/CHANGELOG b/CHANGELOG index c690ceb..3a93caf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,19 @@ -Signal Server 1.3.8 changelog +Signal Server changelog + +v2.23 - 14 August 2014 +Improved diffraction model to work only for dips deeper than 20m and not to exaggerate result by an arbitrary figure (3) +Fixed false 'frequency too low' error message for FSPL model which was intended for Hata models only. + +v2.22 - +Fixed LOS not outputting bounds + +v2.2 - +Made .dot output opt in to save some disk space +Changed version number to line 1 of main.cpp instead of buried in code in two places. + +v2.1 - +Added experimental dual core support with -haf +Requires double the RAM v1.3.8 - 16 Jan 2014 Added Free Space Path Loss model (with optional diffraction) diff --git a/hata.cpp b/hata.cpp index 7f1685d..43ff972 100644 --- a/hata.cpp +++ b/hata.cpp @@ -37,17 +37,18 @@ compromise for increased speed which adds a realistic diffraction effect. double ked(double freq, double elev[], double rxh, double dkm){ double obh,obd,rxobaoi=0,d; -obh=0; -obd=0; +obh=0; // Obstacle height +obd=0; // Obstacle distance dkm=dkm*1000; // KM to metres + // walk along path for(int n=2;n<(dkm/elev[1]);n++){ d = (n-2)*elev[1]; // no of points * delta = km //Find dip(s) - if(elev[n] > 0 && elev[n]<(obh+10)){ + if(elev[n]<(obh+20)){ // Angle from Rx point to obstacle rxobaoi = incidenceAngle((obh-(elev[n]+rxh)),d-obd); @@ -65,7 +66,7 @@ dkm=dkm*1000; // KM to metres } if(rxobaoi >= 0){ -return (rxobaoi * 3) / (300/freq); // Exaggerate diffraction angle and divide by wavelength (m) +return rxobaoi / (300/freq); // Diffraction angle divided by wavelength (m) }else{ return 0; } diff --git a/itm.cpp b/itm.cpp index a9ff3aa..55ec53e 100644 --- a/itm.cpp +++ b/itm.cpp @@ -1204,7 +1204,7 @@ void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielec double zc, zr; double eno, enso, q; long ja, jb, i, np; - double dkm, xkm; + //double dkm, xkm; double fs; prop.hg[0]=tht_m; @@ -1216,8 +1216,8 @@ void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielec zc=qerfi(conf); zr=qerfi(rel); np=(long)elev[0]; //number of points - dkm=(elev[1]*elev[0])/1000.0; // total distance in km. elev[1]=90(m) (default) - xkm=elev[1]/1000.0; // distance between points in km + //dkm=(elev[1]*elev[0])/1000.0; // total distance in km. elev[1]=90(m) (default) + //xkm=elev[1]/1000.0; // distance between points in km eno=eno_ns_surfref; enso=0.0; q=enso; @@ -1295,7 +1295,7 @@ void point_to_pointMDH (double elev[], double tht_m, double rht_m, double eps_di double ztime, zloc, zconf; double eno, enso, q; long ja, jb, i, np; - double dkm, xkm; + //double dkm, xkm; double fs; propmode=-1; // mode is undefined @@ -1310,8 +1310,8 @@ void point_to_pointMDH (double elev[], double tht_m, double rht_m, double eps_di zconf=qerfi(confpct); np=(long)elev[0]; - dkm=(elev[1]*elev[0])/1000.0; - xkm=elev[1]/1000.0; + //dkm=(elev[1]*elev[0])/1000.0; + //xkm=elev[1]/1000.0; eno=eno_ns_surfref; enso=0.0; q=enso; @@ -1382,7 +1382,7 @@ void point_to_pointDH (double elev[], double tht_m, double rht_m, double eps_die double zc, zr; double eno, enso, q; long ja, jb, i, np; - double dkm, xkm; + //double dkm, xkm; double fs; prop.hg[0]=tht_m; @@ -1394,8 +1394,8 @@ void point_to_pointDH (double elev[], double tht_m, double rht_m, double eps_die zc=qerfi(conf); zr=qerfi(rel); np=(long)elev[0]; - dkm=(elev[1]*elev[0])/1000.0; - xkm=elev[1]/1000.0; + //dkm=(elev[1]*elev[0])/1000.0; + //xkm=elev[1]/1000.0; eno=eno_ns_surfref; enso=0.0; q=enso; diff --git a/main.cpp b/main.cpp index d70f6e2..19a3cbc 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,6 @@ +double version=2.23; /****************************************************************************\ -* Signal Server 1.3.8: Server optimised SPLAT! by Alex Farrant * +* Signal Server: Server optimised SPLAT! by Alex Farrant * ****************************************************************************** * SPLAT! Project started in 1997 by John A. Magliacane, KD2BD * * * @@ -16,8 +17,8 @@ * This program is distributed in the hope that it will useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * -* for more details. * -* * +* for more details. * +* * ****************************************************************************** * g++ -Wall -O3 -s -lm -fomit-frame-pointer itm.cpp hata.cpp cost.cpp fspl.cpp main.cpp -o ss * \****************************************************************************/ @@ -29,10 +30,10 @@ #include #include -#define GAMMA 2.5 #define MAXPAGES 64 #define ARRAYSIZE 76810 #define IPPD 1200 +#define GAMMA 2.5 #ifndef PI #define PI 3.141592653589793 @@ -53,16 +54,15 @@ #define KM_PER_MILE 1.609344 #define FOUR_THIRDS 1.3333333333333 -char string[255], sdf_path[255], udt_file[255], opened=0, gpsav=0, ss_name[16], - ss_version[6], dashes[80]; +char string[255], sdf_path[255], udt_file[255], opened=0, gpsav=0, ss_name[16], dashes[80]; double earthradius, max_range=0.0, forced_erp, dpp, ppd, fzone_clearance=0.6, forced_freq, clutter, lat,lon,txh,tercon,terdic, - north,east,south,west; + north,east,south,west,dBm,loss,field_strength; int min_north=90, max_north=-90, min_west=360, max_west=-1, ippd, mpi, max_elevation=-32768, min_elevation=32768, bzerror, contour_threshold, - pred,pblue,pgreen,ter,multiplier=256,debug=0,loops=64,jgets=0, MAXRAD; + pred,pblue,pgreen,ter,multiplier=256,debug=0,loops=64,jgets=0, MAXRAD, hottest=10,csv=0; unsigned char got_elevation_pattern, got_azimuth_pattern, metric=0, dbm=0; @@ -112,6 +112,7 @@ struct region { unsigned char color[128][3]; double elev[ARRAYSIZE+10]; +struct site tx_site[2]; void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielect, double sgm_conductivity, double eno_ns_surfref, @@ -290,10 +291,20 @@ int PutSignal(double lat, double lon, unsigned char signal) { /* This function writes a signal level (0-255) at the specified location for later recall. */ + char dotfile[255]; + FILE *fd=NULL; + snprintf(dotfile,80,"%s.dot%c",tx_site[0].filename,0); + if(csv) + fd=fopen(dotfile,"a"); + int x, y, indx; char found; - + + if(signal > hottest) + hottest=signal; + + //lookup x/y for this co-ord for (indx=0, found=0; indx0 && csv){ + fprintf(fd,"%.6f,%.6f,%d\n",lat,lon,signal); + } + if(csv) + fclose(fd); return (dem[indx].signal[x][y]); } else + if(csv) + fclose(fd); return 0; } @@ -1644,7 +1665,7 @@ void PlotPropPath(struct site source, struct site destination, unsigned char mas xmtr_alt, dest_alt, xmtr_alt2, dest_alt2, cos_rcvr_angle, cos_test_angle=0.0, test_alt, elevation=0.0, distance=0.0, radius=0.0, four_thirds_earth, - field_strength=0.0, rxp, dBm, txelev, dkm, diffloss, lastdiffloss; + field_strength=0.0, rxp, dBm, txelev, dkm, diffloss; struct site temp; radius = Distance(source,destination); @@ -1653,9 +1674,7 @@ void PlotPropPath(struct site source, struct site destination, unsigned char mas four_thirds_earth=FOUR_THIRDS*EARTHRADIUS; - /* Copy elevations plus clutter along path into the elev[] array. */ - lastdiffloss=1; - + for (x=1; xifs) ifs=ofs; + PutSignal(path.lat[y],path.lon[y],(unsigned char)ifs); + } else @@ -1918,8 +1936,8 @@ void PlotPropPath(struct site source, struct site destination, unsigned char mas if (ofs0.0 && debug) fprintf(stdout,"\nand %.2f %s of ground clutter",metric?clutter*METERS_PER_FOOT:clutter,metric?"meters":"feet"); - if(debug){ - fprintf(stdout,"...\n\n 0%c to 25%c ",37,37); - fflush(stdout); - } + + if(debug){ + fprintf(stdout,"...\n\n 0%c to 25%c ",37,37); + fflush(stdout); + } + if (plo_filename[0]!=0) fd=fopen(plo_filename,"wb"); @@ -2090,6 +2112,10 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, in th=ppd/loops; + // Four sections start here + + //S1 + if(haf==0 || haf==1){ z=(int)(th*ReduceAngle(max_west-min_west)); for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y)) @@ -2115,11 +2141,16 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, in } } + } + + //S2 + if(haf==0 || haf==1){ count=0; - if(debug){ - fprintf(stdout,"\n25%c to 50%c ",37,37); - fflush(stdout); - } + if(debug){ + fprintf(stdout,"\n25%c to 50%c ",37,37); + fflush(stdout); + } + z=(int)(th*(double)(max_north-min_north)); for (lat=maxnorth, x=0, y=0; lat>=(double)min_north; y++, lat=maxnorth-(dpp*(double)y)) @@ -2144,11 +2175,15 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, in } } + } + //S3 + if(haf==0 || haf==2){ count=0; - if(debug){ - fprintf(stdout,"\n50%c to 75%c ",37,37); - fflush(stdout); - } + if(debug){ + fprintf(stdout,"\n50%c to 75%c ",37,37); + fflush(stdout); + } + z=(int)(th*ReduceAngle(max_west-min_west)); for (lon=minwest, x=0, y=0; (LonDiff(lon,(double)max_west)<=0.0); y++, lon=minwest+(dpp*(double)y)) @@ -2176,11 +2211,14 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, in } + } + //S4 + if(haf==0 || haf==2){ count=0; - if(debug){ - fprintf(stdout,"\n75%c to 100%c ",37,37); - fflush(stdout); - } + if(debug){ + fprintf(stdout,"\n75%c to 100%c ",37,37); + fflush(stdout); + } z=(int)(th*(double)(max_north-min_north)); for (lat=(double)min_north, x=0, y=0; lat<(double)max_north; y++, lat=(double)min_north+(dpp*(double)y)) @@ -2204,10 +2242,11 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, in } } + } //S4 + if (fd!=NULL) fclose(fd); - if (mask_value<30) mask_value++; } @@ -2679,10 +2718,10 @@ void DoPathLoss(char *filename, unsigned char geo, unsigned char kml, unsigned c 90 degrees from its representation in dem[][] so that north points up and east points right in the image generated. */ - char mapfile[255], geofile[255], kmlfile[255]; + char mapfile[255]; unsigned width, height, red, green, blue, terrain=0; unsigned char found, mask, cityorcounty; - int indx, x, y, z, x0, y0, loss, match; + int indx, x, y, z, x0, y0, loss,match; double lat, lon, conversion, one_over_gamma,minwest; FILE *fd; @@ -2711,25 +2750,25 @@ void DoPathLoss(char *filename, unsigned char geo, unsigned char kml, unsigned c for (x=0; x 60){ + loss=(prevloss-5); + }else{ + prevloss=loss; + } + */ + if(debug){ + fprintf(stdout,"\n%d\t%d\t%d\t%d",loss,indx,x0,y0); + fflush(stdout); + } match=255; red=0; @@ -2894,7 +2945,7 @@ void DoSigStr(char *filename, unsigned char geo, unsigned char kml, unsigned cha 90 degrees from its representation in dem[][] so that north points up and east points right in the image generated. */ - char mapfile[255], geofile[255], kmlfile[255]; + char mapfile[255]; unsigned width, height, terrain, red, green, blue; unsigned char found, mask, cityorcounty; int indx, x, y, z=1, x0, y0, signal,match; @@ -2926,25 +2977,25 @@ void DoSigStr(char *filename, unsigned char geo, unsigned char kml, unsigned cha for (x=0; x -40){ + signal=(prevsignal+5); + }else{ + prevsignal=signal; + }*/ + + if(debug){ + fprintf(stdout,"\n%d\t%d\t%d\t%d",signal,indx,x0,y0); + fflush(stdout); + } + match=255; red=0; @@ -3108,7 +3172,7 @@ void DoRxdPwr(char *filename, unsigned char geo, unsigned char kml, unsigned cha 90 degrees from its representation in dem[][] so that north points up and east points right in the image generated. */ - char mapfile[255], geofile[255], kmlfile[255]; + char mapfile[255]; unsigned width, height, terrain, red, green, blue; unsigned char found, mask, cityorcounty; int indx, x, y, z=1, x0, y0, dBm, match; @@ -3140,25 +3204,25 @@ void DoRxdPwr(char *filename, unsigned char geo, unsigned char kml, unsigned cha for (x=0; x=0 && block==0; x--) + { + distance=5280.0*(path.distance[y]-path.distance[x]); + test_alt=earthradius+(path.elevation[x]==0.0?path.elevation[x]:path.elevation[x]+clutter); + + cos_test_angle=((rx_alt*rx_alt)+(distance*distance)-(test_alt*test_alt))/(2.0*rx_alt*distance); + + /* Compare these two angles to determine if + an obstruction exists. Since we're comparing + the cosines of these angles rather than + the angles themselves, the following "if" + statement is reversed from what it would + be if the actual angles were compared. */ + + if (cos_xmtr_angle>=cos_test_angle) + block=1; + } + + if (block==0) + OrMask(path.lat[y],path.lon[y],mask_value); + } + } +} + +void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *outfile) +{ + /* Perform an obstruction analysis along the + path between receiver and transmitter. */ + + int x; + struct site site_x; + double h_r, h_t, h_x, h_r_orig, cos_tx_angle, cos_test_angle, + cos_tx_angle_f1, cos_tx_angle_fpt6, d_tx, d_x, + h_r_f1, h_r_fpt6, h_f, h_los, lambda=0.0; + char string[255], string_fpt6[255], string_f1[255]; + + ReadPath(xmtr,rcvr); + h_r=GetElevation(rcvr)+rcvr.alt+earthradius; + h_r_f1=h_r; + h_r_fpt6=h_r; + h_r_orig=h_r; + h_t=GetElevation(xmtr)+xmtr.alt+earthradius; + d_tx=5280.0*Distance(rcvr,xmtr); + cos_tx_angle=((h_r*h_r)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r*d_tx); + cos_tx_angle_f1=cos_tx_angle; + cos_tx_angle_fpt6=cos_tx_angle; + + if (f) + lambda=9.8425e8/(f*1e6); + + if (clutter>0.0) + { + fprintf(outfile,"Terrain has been raised by"); + + if (metric) + fprintf(outfile," %.2f meters",METERS_PER_FOOT*clutter); + else + fprintf(outfile," %.2f feet",clutter); + + fprintf(outfile," to account for ground clutter.\n\n"); + } + + /* At each point along the path calculate the cosine + of a sort of "inverse elevation angle" at the receiver. + From the antenna, 0 deg. looks at the ground, and 90 deg. + is parallel to the ground. + + Start at the receiver. If this is the lowest antenna, + then terrain obstructions will be nearest to it. (Plus, + that's the way ppa!'s original los() did it.) + + Calculate cosines only. That's sufficient to compare + angles and it saves the extra computational burden of + acos(). However, note the inverted comparison: if + acos(A) > acos(B), then B > A. */ + + for (x=path.length-1; x>0; x--) + { + site_x.lat=path.lat[x]; + site_x.lon=path.lon[x]; + site_x.alt=0.0; + + h_x=GetElevation(site_x)+earthradius+clutter; + d_x=5280.0*Distance(rcvr,site_x); + + /* Deal with the LOS path first. */ + + cos_test_angle=((h_r*h_r)+(d_x*d_x)-(h_x*h_x))/(2.0*h_r*d_x); + + if (cos_tx_angle>cos_test_angle) + { + if (h_r==h_r_orig) + fprintf(outfile,"Between %s and %s, obstructions were detected at:\n\n",rcvr.name,xmtr.name); + + if (site_x.lat>=0.0) + { + if (metric) + fprintf(outfile," %8.4f N,%9.4f W, %5.2f kilometers, %6.2f meters AMSL\n",site_x.lat, site_x.lon, KM_PER_MILE*(d_x/5280.0), METERS_PER_FOOT*(h_x-earthradius)); + else + fprintf(outfile," %8.4f N,%9.4f W, %5.2f miles, %6.2f feet AMSL\n",site_x.lat, site_x.lon, d_x/5280.0, h_x-earthradius); + } + + else + { + if (metric) + fprintf(outfile," %8.4f S,%9.4f W, %5.2f kilometers, %6.2f meters AMSL\n",-site_x.lat, site_x.lon, KM_PER_MILE*(d_x/5280.0), METERS_PER_FOOT*(h_x-earthradius)); + else + + fprintf(outfile," %8.4f S,%9.4f W, %5.2f miles, %6.2f feet AMSL\n",-site_x.lat, site_x.lon, d_x/5280.0, h_x-earthradius); + } + } + + while (cos_tx_angle>cos_test_angle) + { + h_r+=1; + cos_test_angle=((h_r*h_r)+(d_x*d_x)-(h_x*h_x))/(2.0*h_r*d_x); + cos_tx_angle=((h_r*h_r)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r*d_tx); + } + + if (f) + { + /* Now clear the first Fresnel zone... */ + + cos_tx_angle_f1=((h_r_f1*h_r_f1)+(d_tx*d_tx)-(h_t*h_t))/(2.0*h_r_f1*d_tx); + h_los=sqrt(h_r_f1*h_r_f1+d_x*d_x-2*h_r_f1*d_x*cos_tx_angle_f1); + h_f=h_los-sqrt(lambda*d_x*(d_tx-d_x)/d_tx); + + while (h_fh_r_orig) + { + if (metric) + snprintf(string,150,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear all obstructions detected.\n",rcvr.name, METERS_PER_FOOT*(h_r-GetElevation(rcvr)-earthradius)); + else + snprintf(string,150,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear all obstructions detected.\n",rcvr.name, h_r-GetElevation(rcvr)-earthradius); + } + + else + snprintf(string,150,"\nNo obstructions to LOS path due to terrain were detected\n"); + + if (f) + { + if (h_r_fpt6>h_r_orig) + { + if (metric) + snprintf(string_fpt6,150,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear %.0f%c of the first Fresnel zone.\n",rcvr.name, METERS_PER_FOOT*(h_r_fpt6-GetElevation(rcvr)-earthradius),fzone_clearance*100.0,37); + + else + snprintf(string_fpt6,150,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear %.0f%c of the first Fresnel zone.\n",rcvr.name, h_r_fpt6-GetElevation(rcvr)-earthradius,fzone_clearance*100.0,37); + } + + else + snprintf(string_fpt6,150,"\n%.0f%c of the first Fresnel zone is clear.\n",fzone_clearance*100.0,37); + + if (h_r_f1>h_r_orig) + { + if (metric) + snprintf(string_f1,150,"\nAntenna at %s must be raised to at least %.2f meters AGL\nto clear the first Fresnel zone.\n",rcvr.name, METERS_PER_FOOT*(h_r_f1-GetElevation(rcvr)-earthradius)); + + else + snprintf(string_f1,150,"\nAntenna at %s must be raised to at least %.2f feet AGL\nto clear the first Fresnel zone.\n",rcvr.name, h_r_f1-GetElevation(rcvr)-earthradius); + + } + + else + snprintf(string_f1,150,"\nThe first Fresnel zone is clear.\n"); + } + + fprintf(outfile,"%s",string); + + if (f) + { + fprintf(outfile,"%s",string_f1); + fprintf(outfile,"%s",string_fpt6); + } + + +} + + +void PathReport(struct site source, struct site destination, char *name, char graph_it) +{ + /* This function writes a PPA Path Report (name.txt) to + the filesystem. If (graph_it == 1), then gnuplot is invoked + to generate an appropriate output file indicating the Longley-Rice + model loss between the source and destination locations. + "filename" is the name assigned to the output file generated + by gnuplot. The filename extension is used to set gnuplot's + terminal setting and output file type. If no extension is + found, .png is assumed. */ + + int x, y, z, errnum; + char basename[255], term[30], ext[15], strmode[100], + report_name[80], block=0; + double maxloss=-100000.0, minloss=100000.0, angle1, angle2, + azimuth, pattern=1.0, patterndB=0.0, + total_loss=0.0, cos_xmtr_angle, cos_test_angle=0.0, + source_alt, test_alt, dest_alt, source_alt2, dest_alt2, + distance, elevation, four_thirds_earth, + free_space_loss=0.0, eirp=0.0, voltage, rxp, power_density; + FILE *fd=NULL, *fd2=NULL; + + //sprintf(report_name,"%s.txt",*name); + snprintf(report_name,80,"%s.txt%c",name,0); + + + + four_thirds_earth=FOUR_THIRDS*EARTHRADIUS; + + /*for (x=0; report_name[x]!=0; x++) + if (report_name[x]==32 || report_name[x]==17 || report_name[x]==92 || report_name[x]==42 || report_name[x]==47) + report_name[x]='_'; */ + + fd2=fopen(report_name,"w"); + + fprintf(fd2,"\n\t\t--==[ Path Profile Analysis ]==--\n\n"); + //fprintf(fd2,"%s\n\n",dashes); + fprintf(fd2,"Transmitter site: %s\n",source.name); + + if (source.lat>=0.0) + { + fprintf(fd2,"Site location: %.4f North / %.4f West\n",source.lat, source.lon); + //fprintf(fd2, " (%s N / ", source.lat); + } + + else + { + + fprintf(fd2,"Site location: %.4f South / %.4f West\n",-source.lat, source.lon); + //fprintf(fd2, " (%s S / ", source.lat); + } + + + if (metric) + { + fprintf(fd2,"Ground elevation: %.2f meters AMSL\n",METERS_PER_FOOT*GetElevation(source)); + fprintf(fd2,"Antenna height: %.2f meters AGL / %.2f meters AMSL\n",METERS_PER_FOOT*source.alt,METERS_PER_FOOT*(source.alt+GetElevation(source))); + } + + else + { + fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(source)); + fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",source.alt, source.alt+GetElevation(source)); + } + +/* + haavt=haat(source); + + if (haavt>-4999.0) + { + if (metric) + fprintf(fd2,"Antenna height above average terrain: %.2f meters\n",METERS_PER_FOOT*haavt); + else + fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt); + } +*/ + azimuth=Azimuth(source,destination); + angle1=ElevationAngle(source,destination); + angle2=ElevationAngle2(source,destination,earthradius); + + if (got_azimuth_pattern || got_elevation_pattern) + { + x=(int)rint(10.0*(10.0-angle2)); + + if (x>=0 && x<=1000) + pattern=(double)LR.antenna_pattern[(int)rint(azimuth)][x]; + + patterndB=20.0*log10(pattern); + } + + if (metric) + fprintf(fd2,"Distance to %s: %.2f kilometers\n",destination.name,KM_PER_MILE*Distance(source,destination)); + + else + fprintf(fd2,"Distance to %s: %.2f miles\n",destination.name,Distance(source,destination)); + + fprintf(fd2,"Azimuth to %s: %.2f degrees\n",destination.name,azimuth); + + if (angle1>=0.0) + fprintf(fd2,"Elevation angle to %s: %+.4f degrees\n",destination.name,angle1); + + else + fprintf(fd2,"Depression angle to %s: %+.4f degrees\n",destination.name,angle1); + + if ((angle2-angle1)>0.0001) + { + if (angle2<0.0) + fprintf(fd2,"Depression\n"); + else + fprintf(fd2,"Elevation\n"); + + //fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2); + } + + //fprintf(fd2,"\n%s\n\n",dashes); + + /* Receiver */ + + fprintf(fd2,"Receiver site: %s\n",destination.name); + + if (destination.lat>=0.0) + { + fprintf(fd2,"Site location: %.4f North / %.4f West\n",destination.lat, destination.lon); + //fprintf(fd2, " (%s N / ", destination.lat); + } + + else + { + fprintf(fd2,"Site location: %.4f South / %.4f West\n",-destination.lat, destination.lon); + //fprintf(fd2, " (%s S / ", destination.lat); + } + + if (metric) + { + fprintf(fd2,"Ground elevation: %.2f meters AMSL\n",METERS_PER_FOOT*GetElevation(destination)); + fprintf(fd2,"Antenna height: %.2f meters AGL / %.2f meters AMSL\n",METERS_PER_FOOT*destination.alt, METERS_PER_FOOT*(destination.alt+GetElevation(destination))); + } + + else + { + fprintf(fd2,"Ground elevation: %.2f feet AMSL\n",GetElevation(destination)); + fprintf(fd2,"Antenna height: %.2f feet AGL / %.2f feet AMSL\n",destination.alt, destination.alt+GetElevation(destination)); + } + + /*haavt=haat(destination); + + if (haavt>-4999.0) + { + if (metric) + fprintf(fd2,"Antenna height above average terrain: %.2f meters\n",METERS_PER_FOOT*haavt); + else + fprintf(fd2,"Antenna height above average terrain: %.2f feet\n",haavt); + }*/ + + if (metric) + fprintf(fd2,"Distance to %s: %.2f kilometers\n",source.name,KM_PER_MILE*Distance(source,destination)); + + else + fprintf(fd2,"Distance to %s: %.2f miles\n",source.name,Distance(source,destination)); + + azimuth=Azimuth(destination,source); + + angle1=ElevationAngle(destination,source); + angle2=ElevationAngle2(destination,source,earthradius); + + fprintf(fd2,"Azimuth to %s: %.2f degrees\n",source.name,azimuth); + + if (angle1>=0.0) + fprintf(fd2,"Elevation angle to %s: %+.4f degrees\n",source.name,angle1); + + else + fprintf(fd2,"Depression angle to %s: %+.4f degrees\n",source.name,angle1); + + if ((angle2-angle1)>0.0001) + { + if (angle2<0.0) + fprintf(fd2,"Depression"); + else + fprintf(fd2,"Elevation"); + + //fprintf(fd2," angle to the first obstruction: %+.4f degrees\n",angle2); + } + + //fprintf(fd2,"\n%s\n\n",dashes); + + if (LR.frq_mhz>0.0) + { + fprintf(fd2,"Longley-Rice path calculation parameters used in this analysis:\n\n"); + fprintf(fd2,"Earth's Dielectric Constant: %.3lf\n",LR.eps_dielect); + fprintf(fd2,"Earth's Conductivity: %.3lf Siemens/meter\n",LR.sgm_conductivity); + fprintf(fd2,"Atmospheric Bending Constant (N-units): %.3lf ppm\n",LR.eno_ns_surfref); + fprintf(fd2,"Frequency: %.3lf MHz\n",LR.frq_mhz); + fprintf(fd2,"Radio Climate: %d (",LR.radio_climate); + + switch (LR.radio_climate) + { + case 1: + fprintf(fd2,"Equatorial"); + break; + + case 2: + fprintf(fd2,"Continental Subtropical"); + break; + + case 3: + fprintf(fd2,"Maritime Subtropical"); + break; + + case 4: + fprintf(fd2,"Desert"); + break; + + case 5: + fprintf(fd2,"Continental Temperate"); + break; + + case 6: + fprintf(fd2,"Martitime Temperate, Over Land"); + break; + + case 7: + fprintf(fd2,"Maritime Temperate, Over Sea"); + break; + + default: + fprintf(fd2,"Unknown"); + } + + fprintf(fd2,")\nPolarisation: %d (",LR.pol); + + if (LR.pol==0) + fprintf(fd2,"Horizontal"); + + if (LR.pol==1) + fprintf(fd2,"Vertical"); + + fprintf(fd2,")\nFraction of Situations: %.1lf%c\n",LR.conf*100.0,37); + fprintf(fd2,"Fraction of Time: %.1lf%c\n",LR.rel*100.0,37); + + if (LR.erp!=0.0) + { + fprintf(fd2,"Transmitter ERP: "); + + if (LR.erp<1.0) + fprintf(fd2,"%.1lf milliwatts",1000.0*LR.erp); + + if (LR.erp>=1.0 && LR.erp<10.0) + fprintf(fd2,"%.1lf Watts",LR.erp); + + if (LR.erp>=10.0 && LR.erp<10.0e3) + fprintf(fd2,"%.0lf Watts",LR.erp); + + if (LR.erp>=10.0e3) + fprintf(fd2,"%.3lf kilowatts",LR.erp/1.0e3); + + dBm=10.0*(log10(LR.erp*1000.0)); + fprintf(fd2," (%+.2f dBm)\n",dBm); + + /* EIRP = ERP + 2.14 dB */ + + fprintf(fd2,"Transmitter EIRP: "); + + eirp=LR.erp*1.636816521; + + if (eirp<1.0) + fprintf(fd2,"%.1lf milliwatts",1000.0*eirp); + + if (eirp>=1.0 && eirp<10.0) + fprintf(fd2,"%.1lf Watts",eirp); + + if (eirp>=10.0 && eirp<10.0e3) + fprintf(fd2,"%.0lf Watts",eirp); + + if (eirp>=10.0e3) + fprintf(fd2,"%.3lf kilowatts",eirp/1.0e3); + + dBm=10.0*(log10(eirp*1000.0)); + fprintf(fd2," (%+.2f dBm)\n",dBm); + } + + fprintf(fd2,"\n%s\n\n",dashes); + + fprintf(fd2,"Summary for the link between %s and %s:\n\n",source.name, destination.name); + + if (patterndB!=0.0) + fprintf(fd2,"%s antenna pattern towards %s: %.3f (%.2f dB)\n", source.name, destination.name, pattern, patterndB); + + ReadPath(source, destination); /* source=TX, destination=RX */ + + /* Copy elevations plus clutter along + path into the elev[] array. */ + + for (x=1; x=cos_test_angle) + block=1; + } + + /* At this point, we have the elevation angle + to the first obstruction (if it exists). */ + } + + /* Determine path loss for each point along the + path using Longley-Rice's point_to_point mode + starting at x=2 (number_of_points = 1), the + shortest distance terrain can play a role in + path loss. */ + + elev[0]=y-1; /* (number of points - 1) */ + + /* Distance between elevation samples */ + + elev[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]); + + point_to_point(elev, source.alt*METERS_PER_FOOT, + destination.alt*METERS_PER_FOOT, LR.eps_dielect, + LR.sgm_conductivity, LR.eno_ns_surfref, LR.frq_mhz, + LR.radio_climate, LR.pol, LR.conf, LR.rel, loss, + strmode, errnum); + + if (block) + elevation=((acos(cos_test_angle))/DEG2RAD)-90.0; + else + elevation=((acos(cos_xmtr_angle))/DEG2RAD)-90.0; + + /* Integrate the antenna's radiation + pattern into the overall path loss. */ + + x=(int)rint(10.0*(10.0-elevation)); + + if (x>=0 && x<=1000) + { + pattern=(double)LR.antenna_pattern[(int)azimuth][x]; + + if (pattern!=0.0) + patterndB=20.0*log10(pattern); + } + + else + patterndB=0.0; + + total_loss=loss-patterndB; + + /* if (metric) + fprintf(fd,"%.3f %.3f\n",KM_PER_MILE*(path.distance[path.length-1]-path.distance[y]),total_loss); + + else + fprintf(fd,"%.3f %.3f\n",path.distance[path.length-1]-path.distance[y],total_loss); + */ + + if (total_loss>maxloss) + maxloss=total_loss; + + if (total_loss0 && name[x]!='.'; x--); + + if (x>0) /* Extension found */ + { + for (z=x+1; z<=y && (z-(x+1))<10; z++) + { + ext[z-(x+1)]=tolower(name[z]); + term[z-(x+1)]=name[z]; + } + + ext[z-(x+1)]=0; /* Ensure an ending 0 */ + term[z-(x+1)]=0; + basename[x]=0; + } + } + + if (ext[0]==0) /* No extension -- Default is png */ + { + strncpy(term,"png\0",4); + strncpy(ext,"png\0",4); + } + + /* Either .ps or .postscript may be used + as an extension for postscript output. */ + + if (strncmp(term,"postscript",10)==0) + strncpy(ext,"ps\0",3); + + else if (strncmp(ext,"ps",2)==0) + strncpy(term,"postscript enhanced color\0",26); + + fd=fopen("ppa.gp","w"); + + fprintf(fd,"set grid\n"); + fprintf(fd,"set yrange [%2.3f to %2.3f]\n", minloss, maxloss); + fprintf(fd,"set encoding iso_8859_1\n"); + fprintf(fd,"set term %s\n",term); + fprintf(fd,"set title \"Path Loss Profile Along Path Between %s and %s (%.2f%c azimuth)\"\n",destination.name, source.name, Azimuth(destination,source),176); + + if (metric) + fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f kilometers)\"\n",destination.name,source.name,KM_PER_MILE*Distance(destination,source)); + else + fprintf(fd,"set xlabel \"Distance Between %s and %s (%.2f miles)\"\n",destination.name,source.name,Distance(destination,source)); + + if (got_azimuth_pattern || got_elevation_pattern) + fprintf(fd,"set ylabel \"Total Path Loss (including TX antenna pattern) (dB)"); + else + fprintf(fd,"set ylabel \"Longley-Rice Path Loss (dB)"); + + fprintf(fd,"\"\nset output \"%s.%s\"\n",basename,ext); + fprintf(fd,"plot \"profile.gp\" title \"Path Loss\" with lines\n"); + + fclose(fd); + + x=system("gnuplot ppa.gp"); + + if (x!=-1) + { + if (gpsav==0) + { + //unlink("ppa.gp"); + //unlink("profile.gp"); + //unlink("reference.gp"); + } + + + } + + else + fprintf(stderr,"\n*** ERROR: Error occurred invoking gnuplot!\n"); + } + +} + +void SeriesData(struct site source, struct site destination, char *name, unsigned char fresnel_plot, unsigned char normalised) +{ + + int x, y, z; + char basename[255], term[30], ext[15], profilename[255], referencename[255],cluttername[255],curvaturename[255],fresnelname[255],fresnel60name[255]; + double a, b, c, height=0.0, refangle, cangle, maxheight=-100000.0, + minheight=100000.0, lambda=0.0, f_zone=0.0, fpt6_zone=0.0, + nm=0.0, nb=0.0, ed=0.0, es=0.0, r=0.0, d=0.0, d1=0.0, + terrain, azimuth, distance, minterrain=100000.0, + minearth=100000.0; + struct site remote; + FILE *fd=NULL, *fd1=NULL, *fd2=NULL, *fd3=NULL, *fd4=NULL, *fd5=NULL; + + ReadPath(destination,source); + azimuth=Azimuth(destination,source); + distance=Distance(destination,source); + refangle=ElevationAngle(destination,source); + b=GetElevation(destination)+destination.alt+earthradius; + + if (fresnel_plot) + { + lambda=9.8425e8/(LR.frq_mhz*1e6); + d=5280.0*path.distance[path.length-1]; + } + + if (normalised) + { + ed=GetElevation(destination); + es=GetElevation(source); + nb=-destination.alt-ed; + nm=(-source.alt-es-nb)/(path.distance[path.length-1]); + } + + strcpy(profilename,name); + strcat(profilename,"_profile\0"); + strcpy(referencename,name); + strcat(referencename,"_reference\0"); + strcpy(cluttername,name); + strcat(cluttername,"_clutter\0"); + strcpy(curvaturename,name); + strcat(curvaturename,"_curvature\0"); + strcpy(fresnelname,name); + strcat(fresnelname,"_fresnel\0"); + strcpy(fresnel60name,name); + strcat(fresnel60name,"_fresnel60\0"); + + fd=fopen(profilename,"wb"); + if (clutter>0.0) + fd1=fopen(cluttername,"wb"); + fd2=fopen(referencename,"wb"); + fd5=fopen(curvaturename, "wb"); + + if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + fd3=fopen(fresnelname, "wb"); + fd4=fopen(fresnel60name, "wb"); + } + + for (x=0; x=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + d1=5280.0*path.distance[x]; + f_zone=-1.0*sqrt(lambda*d1*(d-d1)/d); + fpt6_zone=f_zone*fzone_clearance; + } + + if (normalised) + { + r=-(nm*path.distance[x])-nb; + height+=r; + + if ((LR.frq_mhz>=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + f_zone+=r; + fpt6_zone+=r; + } + } + + else + r=0.0; + + if (metric) + { + if (METERS_PER_FOOT*height > 0){ + fprintf(fd,"%.3f %.3f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*height); + } + + if (fd1!=NULL && x>0 && x0 && x=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + if (metric) + { + fprintf(fd3,"%.3f %.3f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*f_zone); + fprintf(fd4,"%.3f %.3f\n",KM_PER_MILE*path.distance[x],METERS_PER_FOOT*fpt6_zone); + } + + else + { + fprintf(fd3,"%.3f %.3f\n",path.distance[x],f_zone); + fprintf(fd4,"%.3f %.3f\n",path.distance[x],fpt6_zone); + } + + if (f_zonemaxheight) + maxheight=height+clutter; + + if (heightmaxheight) + maxheight=r; + + if (terrain=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + if (metric) + { + fprintf(fd3,"%.3f %.3f",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r); + fprintf(fd4,"%.3f %.3f",KM_PER_MILE*path.distance[path.length-1],METERS_PER_FOOT*r); + } + + else + { + fprintf(fd3,"%.3f %.3f",path.distance[path.length-1],r); + fprintf(fd4,"%.3f %.3f",path.distance[path.length-1],r); + } + } + + if (r>maxheight) + maxheight=r; + + if (r=20.0) && (LR.frq_mhz<=100000.0) && fresnel_plot) + { + fclose(fd3); + fclose(fd4); + } + + if (name[0]=='.') + { + strncpy(basename,"profile\0",8); + strncpy(term,"png\0",4); + strncpy(ext,"png\0",4); + } + + else + { + + ext[0]=0; + y=strlen(name); + strncpy(basename,name,254); + + for (x=y-1; x>0 && name[x]!='.'; x--); + + if (x>0) + { + for (z=x+1; z<=y && (z-(x+1))<10; z++) + { + ext[z-(x+1)]=tolower(name[z]); + term[z-(x+1)]=name[z]; + } + + ext[z-(x+1)]=0; + term[z-(x+1)]=0; + basename[x]=0; + } + + if (ext[0]==0) + { + strncpy(term,"png\0",4); + strncpy(ext,"png\0",4); + } + } + + fprintf(stdout,"\n"); + fflush(stdout); + +} int main(int argc, char *argv[]) { int x, y, z=0, min_lat, min_lon, max_lat, max_lon, rxlat, rxlon, txlat, txlon, west_min, west_max, - north_min, north_max, propmodel, winfiles,knifeedge=0; + north_min, north_max, propmodel, winfiles,knifeedge=0,ppa=0,normalise=0, haf=0; - unsigned char LRmap=0, map=0,txsites=0, - topomap=0, geo=0, kml=0, area_mode=0, max_txsites, ngs=0; + unsigned char LRmap=0, txsites=0,topomap=0, geo=0, kml=0, area_mode=0, max_txsites,ngs=0; - char mapfile[255], elevation_file[255], longley_file[255], terrain_file[255], - string[255], rxfile[255],txfile[255], udt_file[255], rxsite=0, ani_filename[255], - ano_filename[255]; + char mapfile[255], longley_file[255], udt_file[255],ano_filename[255]; - double altitude=0.0, altitudeLR=0.0, tx_range=0.0, + double altitude=0.0, altitudeLR=0.0, tx_range=0.0, rx_range=0.0, deg_range=0.0, deg_limit=0.0, deg_range_lon; - struct site tx_site[32], rx_site; - - - - strncpy(ss_version,"1.3.8\0",6); strncpy(ss_name,"Signal Server\0",14); if (argc==1) { - fprintf(stdout,"\n\t\t -- %s %s options --\n\n",ss_name, ss_version); - fprintf(stdout," -d Directory containing .sdf tiles\n"); - fprintf(stdout," -lat Tx Latitude (decimal degrees)\n"); - fprintf(stdout," -lon Tx Longitude (decimal degrees) Positive 0-360 \n"); + fprintf(stdout,"\n\t\t -- %s %.2f options --\n\n",ss_name, version); + fprintf(stdout," -d Directory containing .sdf tiles\n"); + fprintf(stdout," -lat Tx Latitude (decimal degrees) -70/+70\n"); + fprintf(stdout," -lon Tx Longitude (decimal degrees) -180/+180\n"); fprintf(stdout," -txh Tx Height (above ground)\n"); - fprintf(stdout," -f Tx Frequency (MHz) 20MHz to 100Ghz (LOS after 20Ghz)\n"); + fprintf(stdout," -rla (Optional) Rx Latitude for PPA (decimal degrees) -70/+70\n"); + fprintf(stdout," -rlo (Optional) Rx Longitude for PPA (decimal degrees) -180/+180\n"); + fprintf(stdout," -f Tx Frequency (MHz) 20MHz to 100GHz (LOS after 20GHz)\n"); fprintf(stdout," -erp Tx Effective Radiated Power (Watts)\n"); fprintf(stdout," -rxh Rx Height(s) (optional. Default=0.1)\n"); - fprintf(stdout," -rt Rx Threshold (dB / dBm / dBuV/m)\n"); - fprintf(stdout," -hp Horizontal Polarisation (default=vertical)\n"); - fprintf(stdout," -gc Ground clutter (feet/meters)\n"); - fprintf(stdout," -udt User defined terrain filename\n"); + fprintf(stdout," -rt Rx Threshold (dB / dBm / dBuV/m)\n"); + fprintf(stdout," -hp Horizontal Polarisation (default=vertical)\n"); + fprintf(stdout," -gc Ground clutter (feet/meters)\n"); + fprintf(stdout," -udt User defined terrain filename\n"); fprintf(stdout," -dbm Plot Rxd signal power instead of field strength\n"); - fprintf(stdout," -m Metric units of measurement\n"); - fprintf(stdout," -te Terrain code 1-6 (optional)\n"); - fprintf(stdout," -terdic Terrain dielectric value 2-80 (optional)\n"); - fprintf(stdout," -tercon Terrain conductivity 0.01-0.0001 (optional)\n"); - fprintf(stdout," -cl Climate code 1-6 (optional)\n"); - fprintf(stdout," -o Filename. Required. \n"); - fprintf(stdout," -R Radius (miles/kilometers)\n"); + fprintf(stdout," -m Metric units of measurement\n"); + fprintf(stdout," -te Terrain code 1-6 (optional)\n"); + fprintf(stdout," -terdic Terrain dielectric value 2-80 (optional)\n"); + fprintf(stdout," -tercon Terrain conductivity 0.01-0.0001 (optional)\n"); + fprintf(stdout," -cl Climate code 1-6 (optional)\n"); + fprintf(stdout," -o Filename. Required. \n"); + fprintf(stdout," -R Radius (miles/kilometers)\n"); fprintf(stdout," -res Pixels per degree. 300/600/1200(default)/3600 (optional)\n"); fprintf(stdout," -t Terrain background\n"); - fprintf(stdout," -pm Propagation model. 1: ITM (Default), 2: LOS, 3-5: Hata, 6: COST231, 7: ITU525\n"); + fprintf(stdout," -pm Prop model. 1: ITM, 2: LOS, 3-5: Hata, 6: COST231, 7: ITU525\n"); fprintf(stdout," -ked Knife edge diffraction (Default for ITM)\n"); - fprintf(stdout," -wf Win32 SDF tile names ('=' not ':')\n"); - fprintf(stdout," -dbg Debug mode\n\n"); - + fprintf(stdout," -ng Normalise Path Profile graph\n"); + fprintf(stdout," -haf Halve 1 or 2 (optional)\n"); + fprintf(stdout," -csv Write CSV file with lat,lon,dbm\n"); fflush(stdout); @@ -3856,41 +5001,40 @@ int main(int argc, char *argv[]) dbm=0; gpsav=0; metric=0; - rxfile[0]=0; - txfile[0]=0; + //rxfile[0]=0; + //txfile[0]=0; string[0]=0; mapfile[0]=0; clutter=0.0; forced_erp=-1.0; forced_freq=0.0; - elevation_file[0]=0; - terrain_file[0]=0; + //elevation_file[0]=0; + //terrain_file[0]=0; sdf_path[0]=0; udt_file[0]=0; path.length=0; max_txsites=30; fzone_clearance=0.6; contour_threshold=0; - rx_site.lat=91.0; - rx_site.lon=361.0; + longley_file[0]=0; ano_filename[0]=0; - ani_filename[0]=0; + //ani_filename[0]=0; earthradius=EARTHRADIUS; max_range=1.0; propmodel=1; //ITM winfiles=0; - lat=0; - lon=0; - txh=0; - ngs=1; // no terrain background - kml=1; + lat=0; + lon=0; + txh=0; + ngs=1; // no terrain background + kml=1; - map=1; + //map=1; LRmap=1; area_mode=1; - ippd=IPPD; // default resolution + ippd=IPPD; // default resolution sscanf("0.1","%lf",&altitudeLR); @@ -3907,7 +5051,8 @@ int main(int argc, char *argv[]) tx_site[0].lat=91.0; tx_site[0].lon=361.0; - + tx_site[1].lat=91.0; + tx_site[1].lon=361.0; for (x=0; x 90 || tx_site[0].lat < -90) + if (tx_site[0].lat > 90 || tx_site[0].lat < -90) { fprintf(stdout,"ERROR: Either the lat was missing or out of range!"); exit(0); @@ -4293,7 +5478,7 @@ int main(int argc, char *argv[]) if (tx_site[0].alt < 0 || tx_site[0].alt > 60000) { - fprintf(stdout,"ERROR: Tx altitude above ground was too high!"); + fprintf(stdout,"ERROR: Tx altitude above ground was too high: %f", tx_site[0].alt); exit(0); } if (altitudeLR < 0 || altitudeLR > 60000) @@ -4313,7 +5498,7 @@ int main(int argc, char *argv[]) fprintf(stdout,"ERROR: Receiver threshold out of range (-200 / +200)"); exit(0); } - if(propmodel>2 && LR.frq_mhz < 150){ + if(propmodel>2 && propmodel<7 && LR.frq_mhz < 150){ fprintf(stdout,"ERROR: Frequency too low for Propagation model"); exit(0); } @@ -4328,6 +5513,7 @@ int main(int argc, char *argv[]) max_range/=KM_PER_MILE; /* 10 / 1.6 = 7.5 */ altitude/=METERS_PER_FOOT; tx_site[0].alt/=METERS_PER_FOOT; /* Feet to metres */ + tx_site[1].alt/=METERS_PER_FOOT; /* Feet to metres */ clutter/=METERS_PER_FOOT; /* Feet to metres */ } @@ -4370,10 +5556,10 @@ int main(int argc, char *argv[]) max_lon=txlon; - if (rxsite) + if (ppa==1) { - rxlat=(int)floor(rx_site.lat); - rxlon=(int)floor(rx_site.lon); + rxlat=(int)floor(tx_site[1].lat); + rxlon=(int)floor(tx_site[1].lon); if (rxlat