diff --git a/CHANGELOG b/CHANGELOG index 622746a..3146458 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,11 @@ -Signal Server 1.3.6 changelog +Signal Server 1.3.7 changelog + +v1.3.7 - 30 Dec 2013 +Added propagation model option (-pm) +Added HATA urban/suburban/open models (150-1500MHz) +Added COST231-Hata (urban) model (1500-2000MHz) +Added custom Knife Edge Diffraction option (-ked) to enhance new models +Removed unused variables v1.3.6 - 12 Aug 2013 Added LOS model for up to 100GHz diff --git a/README.md b/README.md index 5d2c6dc..406ef2e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ -Signal-Server -============= - -RF coverage calculator +Signal-Server RF coverage calculator +==================================== /****************************************************************************\ -* Signal Server 1.3.6: Server optimised SPLAT! by Alex Farrant * +* Signal Server 1.3.7: Server optimised SPLAT! by Alex Farrant * ****************************************************************************** -* SPLAT! Project started in 1997 by John A. Magliacane, KD2BD * -* * +* SPLAT! Project started in 1997 by John A. Magliacane, KD2BD * +* * ****************************************************************************** * Please consult the SPLAT! documentation for a complete list of * -* individuals who have contributed to this project. * +* individuals who have contributed to this project. * ****************************************************************************** * * * This program is free software; you can redistribute it and/or modify it * @@ -24,7 +22,7 @@ RF coverage calculator * for more details. * * * ****************************************************************************** -* g++ -Wall -O3 -s -lm -fomit-frame-pointer itm.cpp main.cpp -o ss * +* g++ -Wall -O3 -s -lm -fomit-frame-pointer itm.cpp cost.cpp hata.cpp main.cpp -o ss * \****************************************************************************/ Usage: Signalserver (options) @@ -51,4 +49,7 @@ RF coverage calculator -R Radius (miles/kilometers) -res Pixels per degree. 300/600/1200(default)/3600 (optional) -t Terrain background - -dbg Debug \ No newline at end of file + -pm Propagation model. 1: ITM (Default), 2: LOS, 3-5: Hata + -ked Knife edge diffraction (Default for ITM) + -wf Win32 SDF tile names ('=' not ':') + -dbg Debug mode \ No newline at end of file diff --git a/cost.cpp b/cost.cpp new file mode 100644 index 0000000..2ac3e51 --- /dev/null +++ b/cost.cpp @@ -0,0 +1,41 @@ +/***************************************************************************** +* COST231-HATA MODEL for Signal Server by Alex Farrant * +* 30 December 2013 * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the * +* Free Software Foundation; either version 2 of the License or any later * +* version. * +* * +* 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. * +* */ + +#include +#include +#include + +using namespace std; + +double CostHataLinkdB(float f,float h_B, float h_M, float d){ +/* +COST HATA URBAN model +Frequency 1500 to 2000MHz +h_B = Base station height 30 to 200m +h_M = Mobile station height 1 to 10m +Distance 1-20km +*/ + + int C = 0; // 0dB for suburban + + float lh_M = log10(11.75*h_M); + float C_H = 3.2*lh_M*lh_M-4.97; + + float logf = log10(f); + + double dbloss = 46.3 + (33.9 * logf) - (13.82 * log10(h_B)) - C_H + (44.9 - 6.55 * log10(h_B)) * log10(d) + C; + + + return dbloss; +} diff --git a/hata.cpp b/hata.cpp new file mode 100644 index 0000000..7f1685d --- /dev/null +++ b/hata.cpp @@ -0,0 +1,109 @@ +/***************************************************************************** +* HATA MODEL for Signal Server by Alex Farrant * +* 30 December 2013 * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the * +* Free Software Foundation; either version 2 of the License or any later * +* version. * +* * +* 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. * +* */ + +#include +#include +#include +#include +#include + +using namespace std; + +#define PI 3.14159265 + +/* Acute Angle from Rx point to an obstacle of height (opp) and distance (adj) */ +double incidenceAngle(double opp, double adj){ +return atan2(opp,adj) * 180 / PI; +} + +/* +Knife edge diffraction: +This custom function adds to the overall path loss based upon the obstacle +angle (from receive point) and the frequency. Loss increases with angle and frequency. +This is not a recognised formula like Huygens, rather it is a +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; + +dkm=dkm*1000; // KM to metres + + 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)){ + + // Angle from Rx point to obstacle + rxobaoi = incidenceAngle((obh-(elev[n]+rxh)),d-obd); + } else{ + // Line of sight or higher + rxobaoi=0; + } + + //note the highest point + if(elev[n]>obh){ + obh=elev[n]; + obd=d; + } + + } + +if(rxobaoi >= 0){ +return (rxobaoi * 3) / (300/freq); // Exaggerate diffraction angle and divide by wavelength (m) +}else{ +return 0; +} + +} + +double HataLinkdB(float f,float h_B, float h_M, float d, int mode){ +/* +HATA URBAN model for cellular planning +Frequency (MHz) 150 to 1500MHz +Base station height 30-200m +Mobile station height 1-10m +Distance 1-20km + +mode 1 = URBAN +mode 2 = SUBURBAN +mode 3 = OPEN +*/ + + float lh_M = log10(11.75*h_M); + float C_H = 3.2*lh_M*lh_M-4.97; + + float logf = log10(f); + + float L_u = 69.55 + 26.16*logf - 13.82*log10(h_B) - C_H + (44.9 - 6.55*log10(h_B))*log10(d); + + if(!mode || mode==1){ + return L_u; //URBAN + } + + if(mode==2){ //SUBURBAN + float logf_28 = log10(f/28); + return L_u - 2*logf_28*logf_28 - 5.4; + } + + if(mode==3){ //OPEN + return L_u - 4.78*logf*logf + 18.33*logf - 40.94; + } + + return 0; +} \ No newline at end of file diff --git a/itm.cpp b/itm.cpp index 486dcb0..a9ff3aa 100644 --- a/itm.cpp +++ b/itm.cpp @@ -1215,9 +1215,9 @@ void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielec prop.mdp=-1; zc=qerfi(conf); zr=qerfi(rel); - np=(long)elev[0]; - dkm=(elev[1]*elev[0])/1000.0; - xkm=elev[1]/1000.0; + 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 eno=eno_ns_surfref; enso=0.0; q=enso; diff --git a/main.cpp b/main.cpp index 9af0b7d..6c65f4f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,11 +1,11 @@ /****************************************************************************\ -* Signal Server 1.3.6: Server optimised SPLAT! by Alex Farrant * +* Signal Server 1.3.7: Server optimised SPLAT! by Alex Farrant * ****************************************************************************** -* SPLAT! Project started in 1997 by John A. Magliacane, KD2BD * -* * +* SPLAT! Project started in 1997 by John A. Magliacane, KD2BD * +* * ****************************************************************************** * Please consult the SPLAT! documentation for a complete list of * -* individuals who have contributed to this project. * +* individuals who have contributed to this project. * ****************************************************************************** * * * This program is free software; you can redistribute it and/or modify it * @@ -19,7 +19,7 @@ * for more details. * * * ****************************************************************************** -* g++ -Wall -O3 -s -lm -fomit-frame-pointer itm.cpp main.cpp -o ss * +* g++ -Wall -O3 -s -lm -fomit-frame-pointer itm.cpp cost.cpp hata.cpp main.cpp -o ss * \****************************************************************************/ #include @@ -30,9 +30,9 @@ #include #define GAMMA 2.5 -#define MAXPAGES 9 -#define ARRAYSIZE 32600 -#define IPPD 3600 +#define MAXPAGES 64 +#define ARRAYSIZE 76810 +#define IPPD 1200 #ifndef PI #define PI 3.141592653589793 @@ -117,6 +117,12 @@ void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielect, double sgm_conductivity, double eno_ns_surfref, double frq_mhz, int radio_climate, int pol, double conf, double rel, double &dbloss, char *strmode, int &errnum); + +double HataLinkdB(float f,float h_B, float h_M, float d, int mode); + +double CostHataLinkdB(float f,float h_B, float h_M, float d); + +double ked(double freq, double elev[], double rxh, double dkm); double arccos(double x, double y) { @@ -1222,7 +1228,7 @@ void LoadPAT(char *filename) } } -int LoadSDF_SDF(char *name) +int LoadSDF_SDF(char *name, int winfiles) { /* This function reads uncompressed ss Data Files (.sdf) containing digital elevation model data into memory. @@ -1243,9 +1249,12 @@ int LoadSDF_SDF(char *name) sdf_file[x]=0; /* Parse filename for minimum latitude and longitude values */ - + if(winfiles==1){ + sscanf(sdf_file,"%d=%d=%d=%d",&minlat,&maxlat,&minlon,&maxlon); + }else{ sscanf(sdf_file,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon); - + } + sdf_file[x]='.'; sdf_file[x+1]='s'; sdf_file[x+2]='d'; @@ -1431,7 +1440,7 @@ int LoadSDF_SDF(char *name) else return 0; } -char LoadSDF(char *name) +char LoadSDF(char *name, int winfiles) { /* This function loads the requested SDF file from the filesystem. It first tries to invoke the LoadSDF_SDF() function to load an @@ -1446,7 +1455,7 @@ char LoadSDF(char *name) char found, free_page=0; int return_value=-1; - return_value=LoadSDF_SDF(name); + return_value=LoadSDF_SDF(name, winfiles); /* If neither format can be found, then assume the area is water. */ @@ -1456,10 +1465,11 @@ char LoadSDF(char *name) - /* Parse SDF name for minimum latitude and longitude values */ - + if(winfiles==1){ + sscanf(name,"%d=%d=%d=%d",&minlat,&maxlat,&minlon,&maxlon); + }else{ sscanf(name,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon); - + } /* Is it already in memory? */ for (indx=0, found=0; indx=360) ymax-=360; - if (ippd==3600) - snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax); - else - snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax); - + if (winfiles==1){ + if (ippd==3600) + snprintf(string,19,"%d=%d=%d=%d=hd",x, x+1, ymin, ymax); + else + snprintf(string,16,"%d=%d=%d=%d",x, x+1, ymin, ymax); - LoadSDF(string); + }else{ + if (ippd==3600) + snprintf(string,19,"%d:%d:%d:%d=hd",x, x+1, ymin, ymax); + else + snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax); + } + + LoadSDF(string,winfiles); } } @@ -3549,11 +3601,20 @@ void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat) while (ymax>=360) ymax-=360; - if (ippd==3600) - snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax); - else - snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax); - LoadSDF(string); + if (winfiles==1){ + if (ippd==3600) + snprintf(string,19,"%d=%d=%d=%d=hd",x, x+1, ymin, ymax); + else + snprintf(string,16,"%d=%d=%d=%d",x, x+1, ymin, ymax); + + }else{ + if (ippd==3600) + snprintf(string,19,"%d:%d:%d:%d=hd",x, x+1, ymin, ymax); + else + snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax); + } + + LoadSDF(string,winfiles); } } } @@ -3725,7 +3786,7 @@ 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; + north_min, north_max, propmodel, winfiles,knifeedge=0; unsigned char LRmap=0, map=0,txsites=0, topomap=0, geo=0, kml=0, area_mode=0, max_txsites, ngs=0; @@ -3742,7 +3803,7 @@ int main(int argc, char *argv[]) - strncpy(ss_version,"1.3.6\0",6); + strncpy(ss_version,"1.3.7\0",6); strncpy(ss_name,"Signal Server\0",14); if (argc==1) @@ -3769,7 +3830,10 @@ int main(int argc, char *argv[]) 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," -dbg Debug\n\n"); + fprintf(stdout," -pm Propagation model. 1: ITM (Default), 2: LOS, 3-5: Hata\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"); @@ -3806,8 +3870,9 @@ int main(int argc, char *argv[]) ano_filename[0]=0; ani_filename[0]=0; earthradius=EARTHRADIUS; - max_range=1.0; - + max_range=1.0; + propmodel=1; //ITM + winfiles=0; lat=0; lon=0; @@ -3822,8 +3887,8 @@ int main(int argc, char *argv[]) sscanf("0.1","%lf",&altitudeLR); - // Defaults - LR.eps_dielect=15.0; // Farmland + // Defaults + LR.eps_dielect=15.0; // Farmland LR.sgm_conductivity=0.005; // Farmland LR.eno_ns_surfref=301.0; LR.frq_mhz=19.0; // Deliberately too low @@ -3837,10 +3902,6 @@ int main(int argc, char *argv[]) tx_site[0].lon=361.0; - //flush dem - //memset(dem, 0, ARRAYSIZE * sizeof(struct dem)); - memset(dem, 0, (size_t)MAXPAGES * sizeof(struct dem)); - for (x=0; x2 && LR.frq_mhz < 150){ + fprintf(stdout,"ERROR: Frequency too low for Propagation model"); + exit(0); + } /* ERROR DETECTION COMPLETE */ @@ -4229,12 +4317,11 @@ int main(int argc, char *argv[]) if (metric) { - altitudeLR/=METERS_PER_FOOT; /* RXH meters --> feet */ - max_range/=KM_PER_MILE; /* RAD kilometers --> miles */ + altitudeLR/=METERS_PER_FOOT; /* 10ft * 0.3 = 3.3m */ + max_range/=KM_PER_MILE; /* 10 / 1.6 = 7.5 */ altitude/=METERS_PER_FOOT; - tx_site[0].alt/=METERS_PER_FOOT; /* TXH meters --> feet */ - clutter/=METERS_PER_FOOT; /* CLH meters --> feet */ - + tx_site[0].alt/=METERS_PER_FOOT; /* Feet to metres */ + clutter/=METERS_PER_FOOT; /* Feet to metres */ } /* Ensure a trailing '/' is present in sdf_path */ @@ -4296,7 +4383,7 @@ int main(int argc, char *argv[]) /* Load the required SDF files */ - LoadTopoData(max_lon, min_lon, max_lat, min_lat); + LoadTopoData(max_lon, min_lon, max_lat, min_lat, winfiles); if (area_mode || topomap) { @@ -4381,22 +4468,19 @@ int main(int argc, char *argv[]) /* Load any additional SDF files, if required */ - LoadTopoData(max_lon, min_lon, max_lat, min_lat); + LoadTopoData(max_lon, min_lon, max_lat, min_lat, winfiles); } - // UDT clutter - LoadUDT (udt_file); + // UDT clutter + LoadUDT (udt_file); - if (LR.frq_mhz > 20000){ - + if (LR.frq_mhz > 20000 || propmodel==2){ PlotLOSMap(tx_site[0],altitudeLR,ano_filename); DoLOS(mapfile,geo,kml,ngs,tx_site,txsites); - } else{ - PlotLRMap(tx_site[0],altitudeLR,ano_filename); - + PlotPropagation(tx_site[0],altitudeLR,ano_filename,propmodel,knifeedge); if (LR.erp==0.0) DoPathLoss(mapfile,geo,kml,ngs,tx_site,txsites);