Added propagation models and knife edge diffraction :)
This commit is contained in:
Cloud-RF
2013-12-30 21:41:03 +00:00
parent bf6a259c83
commit cdabfd517a
6 changed files with 367 additions and 125 deletions

View File

@@ -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 v1.3.6 - 12 Aug 2013
Added LOS model for up to 100GHz Added LOS model for up to 100GHz

View File

@@ -1,16 +1,14 @@
Signal-Server Signal-Server RF coverage calculator
============= ====================================
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 * * 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 * * This program is free software; you can redistribute it and/or modify it *
@@ -24,7 +22,7 @@ RF coverage calculator
* for more details. * * 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) Usage: Signalserver (options)
@@ -51,4 +49,7 @@ RF coverage calculator
-R Radius (miles/kilometers) -R Radius (miles/kilometers)
-res Pixels per degree. 300/600/1200(default)/3600 (optional) -res Pixels per degree. 300/600/1200(default)/3600 (optional)
-t Terrain background -t Terrain background
-dbg Debug -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

41
cost.cpp Normal file
View File

@@ -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 <stdlib.h>
#include <math.h>
#include <iostream>
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;
}

109
hata.cpp Normal file
View File

@@ -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 <stdlib.h>
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <string>
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;
}

View File

@@ -1215,9 +1215,9 @@ void point_to_point(double elev[], double tht_m, double rht_m, double eps_dielec
prop.mdp=-1; prop.mdp=-1;
zc=qerfi(conf); zc=qerfi(conf);
zr=qerfi(rel); zr=qerfi(rel);
np=(long)elev[0]; np=(long)elev[0]; //number of points
dkm=(elev[1]*elev[0])/1000.0; dkm=(elev[1]*elev[0])/1000.0; // total distance in km. elev[1]=90(m) (default)
xkm=elev[1]/1000.0; xkm=elev[1]/1000.0; // distance between points in km
eno=eno_ns_surfref; eno=eno_ns_surfref;
enso=0.0; enso=0.0;
q=enso; q=enso;

296
main.cpp
View File

@@ -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 * * 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 * * This program is free software; you can redistribute it and/or modify it *
@@ -19,7 +19,7 @@
* for more details. * * 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 <stdio.h> #include <stdio.h>
@@ -30,9 +30,9 @@
#include <unistd.h> #include <unistd.h>
#define GAMMA 2.5 #define GAMMA 2.5
#define MAXPAGES 9 #define MAXPAGES 64
#define ARRAYSIZE 32600 #define ARRAYSIZE 76810
#define IPPD 3600 #define IPPD 1200
#ifndef PI #ifndef PI
#define PI 3.141592653589793 #define PI 3.141592653589793
@@ -118,6 +118,12 @@ void point_to_point(double elev[], double tht_m, double rht_m,
double frq_mhz, int radio_climate, int pol, double conf, double frq_mhz, int radio_climate, int pol, double conf,
double rel, double &dbloss, char *strmode, int &errnum); 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) double arccos(double x, double y)
{ {
/* This function implements the arc cosine function, /* This function implements the arc cosine function,
@@ -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) /* This function reads uncompressed ss Data Files (.sdf)
containing digital elevation model data into memory. containing digital elevation model data into memory.
@@ -1243,8 +1249,11 @@ int LoadSDF_SDF(char *name)
sdf_file[x]=0; sdf_file[x]=0;
/* Parse filename for minimum latitude and longitude values */ /* 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); sscanf(sdf_file,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon);
}
sdf_file[x]='.'; sdf_file[x]='.';
sdf_file[x+1]='s'; sdf_file[x+1]='s';
@@ -1431,7 +1440,7 @@ int LoadSDF_SDF(char *name)
else else
return 0; return 0;
} }
char LoadSDF(char *name) char LoadSDF(char *name, int winfiles)
{ {
/* This function loads the requested SDF file from the filesystem. /* This function loads the requested SDF file from the filesystem.
It first tries to invoke the LoadSDF_SDF() function to load an 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; char found, free_page=0;
int return_value=-1; 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. */ /* 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); sscanf(name,"%d:%d:%d:%d",&minlat,&maxlat,&minlon,&maxlon);
}
/* Is it already in memory? */ /* Is it already in memory? */
for (indx=0, found=0; indx<MAXPAGES && found==0; indx++) for (indx=0, found=0; indx<MAXPAGES && found==0; indx++)
@@ -1565,7 +1575,7 @@ char LoadSDF(char *name)
return return_value; return return_value;
} }
void PlotPath(struct site source, struct site destination, char mask_value, FILE *fd) void PlotLOSPath(struct site source, struct site destination, char mask_value, FILE *fd)
{ {
/* This function analyzes the path between the source and /* This function analyzes the path between the source and
destination locations. It determines which points along destination locations. It determines which points along
@@ -1623,27 +1633,26 @@ void PlotPath(struct site source, struct site destination, char mask_value, FILE
} }
} }
void PlotLRPath(struct site source, struct site destination, unsigned char mask_value, FILE *fd) void PlotPropPath(struct site source, struct site destination, unsigned char mask_value, FILE *fd, int propmodel, int knifeedge)
{ {
/* This function plots the RF path loss between source and
destination points based on the Longley-Rice propagation
model, taking into account antenna pattern data, if available. */
int x, y, ifs, ofs, errnum; int x, y, ifs, ofs, errnum;
char block=0, strmode[100]; char block=0, strmode[100];
double loss, azimuth, pattern=0.0, double loss, azimuth, pattern=0.0,
xmtr_alt, dest_alt, xmtr_alt2, dest_alt2, xmtr_alt, dest_alt, xmtr_alt2, dest_alt2,
cos_rcvr_angle, cos_test_angle=0.0, test_alt, cos_rcvr_angle, cos_test_angle=0.0, test_alt,
elevation=0.0, distance=0.0, four_thirds_earth, elevation=0.0, distance=0.0, radius=0.0, four_thirds_earth,
field_strength=0.0, rxp, dBm; field_strength=0.0, rxp, dBm, txelev, dkm, diffloss, lastdiffloss;
struct site temp; struct site temp;
radius = Distance(source,destination);
ReadPath(source,destination); ReadPath(source,destination);
four_thirds_earth=FOUR_THIRDS*EARTHRADIUS; four_thirds_earth=FOUR_THIRDS*EARTHRADIUS;
/* Copy elevations plus clutter along path into the elev[] array. */ /* Copy elevations plus clutter along path into the elev[] array. */
lastdiffloss=1;
for (x=1; x<path.length-1; x++) for (x=1; x<path.length-1; x++)
elev[x+2]=(path.elevation[x]==0.0?path.elevation[x]*METERS_PER_FOOT:(clutter+path.elevation[x])*METERS_PER_FOOT); elev[x+2]=(path.elevation[x]==0.0?path.elevation[x]*METERS_PER_FOOT:(clutter+path.elevation[x])*METERS_PER_FOOT);
@@ -1651,6 +1660,8 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_
/* Copy ending points without clutter */ /* Copy ending points without clutter */
elev[2]=path.elevation[0]*METERS_PER_FOOT; elev[2]=path.elevation[0]*METERS_PER_FOOT;
txelev=elev[2]+(source.alt*METERS_PER_FOOT);
elev[path.length+1]=path.elevation[path.length-1]*METERS_PER_FOOT; elev[path.length+1]=path.elevation[path.length-1]*METERS_PER_FOOT;
/* Since the only energy the Longley-Rice model considers /* Since the only energy the Longley-Rice model considers
@@ -1731,8 +1742,7 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_
} }
/* Determine attenuation for each point along the /* Determine attenuation for each point along the
path using Longley-Rice's point_to_point mode path using a prop model starting at y=2 (number_of_points = 1), the
starting at y=2 (number_of_points = 1), the
shortest distance terrain can play a role in shortest distance terrain can play a role in
path loss. */ path loss. */
@@ -1742,11 +1752,65 @@ void PlotLRPath(struct site source, struct site destination, unsigned char mask_
elev[1]=METERS_PER_MILE*(path.distance[y]-path.distance[y-1]); 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, elev[2]=path.elevation[0]*METERS_PER_FOOT;
LR.sgm_conductivity, LR.eno_ns_surfref, LR.frq_mhz, elev[path.length+1]=path.elevation[path.length-1]*METERS_PER_FOOT;
LR.radio_climate, LR.pol, LR.conf, LR.rel, loss, */
strmode, errnum); if(path.elevation[y] < 1){
path.elevation[y]=1;
}
dkm=(elev[1]*elev[0])/1000; // km
switch (propmodel)
{
case 1:
// Longley Rice
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);
break;
case 3:
//HATA urban
loss=HataLinkdB(LR.frq_mhz,txelev,path.elevation[y]+(destination.alt*METERS_PER_FOOT),dkm, 1);
break;
case 4:
//HATA suburban
loss=HataLinkdB(LR.frq_mhz,txelev,path.elevation[y]+(destination.alt*METERS_PER_FOOT),dkm, 2);
break;
case 5:
//HATA open
loss=HataLinkdB(LR.frq_mhz,txelev,path.elevation[y]+(destination.alt*METERS_PER_FOOT),dkm, 3);
break;
case 6:
// COST231-HATA
loss=CostHataLinkdB(LR.frq_mhz,txelev,path.elevation[y]+(destination.alt*METERS_PER_FOOT),dkm);
break;
default:
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(knifeedge==1){
diffloss = ked(LR.frq_mhz,elev,destination.alt*METERS_PER_FOOT,dkm);
loss+=(diffloss); // ;)
}
if(debug){
fprintf(stdout,"\n%2f\t%2f\t%2f\t%2f",txelev,path.elevation[y],dkm,loss);
fflush(stdout);
}
//Key stage. Link dB for p2p is returned as 'loss'.
temp.lat=path.lat[y]; temp.lat=path.lat[y];
temp.lon=path.lon[y]; temp.lon=path.lon[y];
@@ -1877,9 +1941,9 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
of a topographic map when the WritePPM() function of a topographic map when the WritePPM() function
is later invoked. */ is later invoked. */
int y, z, count; int y, z;
struct site edge; struct site edge;
unsigned char symbol[4], x; unsigned char x;
double lat, lon, minwest, maxnorth, th; double lat, lon, minwest, maxnorth, th;
static unsigned char mask_value=1; static unsigned char mask_value=1;
FILE *fd=NULL; FILE *fd=NULL;
@@ -1909,7 +1973,7 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
edge.lon=lon; edge.lon=lon;
edge.alt=altitude; edge.alt=altitude;
PlotPath(source,edge,mask_value,fd); PlotLOSPath(source,edge,mask_value,fd);
} }
@@ -1922,7 +1986,7 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
edge.lon=min_west; edge.lon=min_west;
edge.alt=altitude; edge.alt=altitude;
PlotPath(source,edge,mask_value,fd); PlotLOSPath(source,edge,mask_value,fd);
} }
@@ -1939,7 +2003,7 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
edge.lon=lon; edge.lon=lon;
edge.alt=altitude; edge.alt=altitude;
PlotPath(source,edge,mask_value,fd); PlotLOSPath(source,edge,mask_value,fd);
} }
@@ -1952,7 +2016,7 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
edge.lon=max_west; edge.lon=max_west;
edge.alt=altitude; edge.alt=altitude;
PlotPath(source,edge,mask_value,fd); PlotLOSPath(source,edge,mask_value,fd);
} }
@@ -1973,21 +2037,12 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename)
} }
} }
void PlotLRMap(struct site source, double altitude, char *plo_filename) void PlotPropagation(struct site source, double altitude, char *plo_filename, int propmodel, int knifeedge)
{ {
/* This function performs a 360 degree sweep around the
transmitter site (source location), and plots the
Longley-Rice attenuation on the ss generated
topographic map based on a receiver located at
the specified altitude (in feet AGL). Results
are stored in memory, and written out in the form
of a topographic map when the DoPathLoss() or
DoSigStr() functions are later invoked. */
int y, z, count; int y, z, count;
struct site edge; struct site edge;
double lat, lon, minwest, maxnorth, th; double lat, lon, minwest, maxnorth, th;
unsigned char x, symbol[4]; unsigned char x;
static unsigned char mask_value=1; static unsigned char mask_value=1;
FILE *fd=NULL; FILE *fd=NULL;
@@ -1995,9 +2050,7 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
maxnorth=(double)max_north-dpp; maxnorth=(double)max_north-dpp;
count=0; count=0;
if (debug){
fprintf(stdout,"\nComputing Longley-Rice ");
}
if (LR.erp==0.0 && debug) if (LR.erp==0.0 && debug)
fprintf(stdout,"path loss"); fprintf(stdout,"path loss");
@@ -2025,14 +2078,9 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
if (fd!=NULL) if (fd!=NULL)
{ {
/* Write header information to output file */
fprintf(fd,"%d, %d\t; max_west, min_west\n%d, %d\t; max_north, min_north\n",max_west, min_west, max_north, min_north); fprintf(fd,"%d, %d\t; max_west, min_west\n%d, %d\t; max_north, min_north\n",max_west, min_west, max_north, min_north);
} }
/* th=pixels/degree divided by 64 loops per
progress indicator symbol (.oOo) printed. */
th=ppd/loops; th=ppd/loops;
z=(int)(th*ReduceAngle(max_west-min_west)); z=(int)(th*ReduceAngle(max_west-min_west));
@@ -2046,13 +2094,11 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
edge.lon=lon; edge.lon=lon;
edge.alt=altitude; edge.alt=altitude;
PlotLRPath(source,edge,mask_value,fd); PlotPropPath(source,edge,mask_value,fd,propmodel,knifeedge);
count++; count++;
if (count==z) if (count==z)
{ {
//fprintf(stdout,"%c",symbol[x]);
//fflush(stdout);
count=0; count=0;
if (x==3) if (x==3)
@@ -2075,7 +2121,7 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
edge.lon=min_west; edge.lon=min_west;
edge.alt=altitude; edge.alt=altitude;
PlotLRPath(source,edge,mask_value,fd); PlotPropPath(source,edge,mask_value,fd,propmodel,knifeedge);
count++; count++;
if (count==z) if (count==z)
@@ -2107,7 +2153,7 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
edge.lon=lon; edge.lon=lon;
edge.alt=altitude; edge.alt=altitude;
PlotLRPath(source,edge,mask_value,fd); PlotPropPath(source,edge,mask_value,fd,propmodel,knifeedge);
count++; count++;
if (count==z) if (count==z)
{ {
@@ -2136,13 +2182,12 @@ void PlotLRMap(struct site source, double altitude, char *plo_filename)
edge.lon=max_west; edge.lon=max_west;
edge.alt=altitude; edge.alt=altitude;
PlotLRPath(source,edge,mask_value,fd); PlotPropPath(source,edge,mask_value,fd,propmodel,knifeedge);
count++; count++;
if (count==z) if (count==z)
{ {
//fprintf(stdout,"%c",symbol[x]);
//fflush(stdout);
count=0; count=0;
if (x==3) if (x==3)
@@ -3273,9 +3318,9 @@ void DoLOS(char *filename, unsigned char geo, unsigned char kml, unsigned char n
points up and east points right in the image generated. */ points up and east points right in the image generated. */
char mapfile[255], geofile[255], kmlfile[255]; char mapfile[255], geofile[255], kmlfile[255];
unsigned width, height, terrain, red, green, blue; unsigned width, height, terrain;
unsigned char found, mask, cityorcounty; unsigned char found, mask;
int indx, x, y, z=1, x0, y0, dBm, match; int indx, x, y, x0, y0;
double conversion, one_over_gamma, lat, lon, minwest; double conversion, one_over_gamma, lat, lon, minwest;
FILE *fd; FILE *fd;
@@ -3488,7 +3533,7 @@ void DoLOS(char *filename, unsigned char geo, unsigned char kml, unsigned char n
} }
void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat) void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat, int winfiles)
{ {
/* This function loads the SDF files required /* This function loads the SDF files required
to cover the limits of the region specified. */ to cover the limits of the region specified. */
@@ -3518,13 +3563,20 @@ void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat)
while (ymax>=360) while (ymax>=360)
ymax-=360; ymax-=360;
if (ippd==3600) if (winfiles==1){
snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax); if (ippd==3600)
else snprintf(string,19,"%d=%d=%d=%d=hd",x, x+1, ymin, ymax);
snprintf(string,16,"%d:%d:%d:%d",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); LoadSDF(string,winfiles);
} }
} }
@@ -3549,11 +3601,20 @@ void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat)
while (ymax>=360) while (ymax>=360)
ymax-=360; ymax-=360;
if (ippd==3600) if (winfiles==1){
snprintf(string,19,"%d:%d:%d:%d-hd",x, x+1, ymin, ymax); if (ippd==3600)
else snprintf(string,19,"%d=%d=%d=%d=hd",x, x+1, ymin, ymax);
snprintf(string,16,"%d:%d:%d:%d",x, x+1, ymin, ymax); else
LoadSDF(string); 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, int x, y, z=0, min_lat, min_lon, max_lat, max_lon,
rxlat, rxlon, txlat, txlon, west_min, west_max, 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, unsigned char LRmap=0, map=0,txsites=0,
topomap=0, geo=0, kml=0, area_mode=0, max_txsites, ngs=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); strncpy(ss_name,"Signal Server\0",14);
if (argc==1) if (argc==1)
@@ -3769,7 +3830,10 @@ int main(int argc, char *argv[])
fprintf(stdout," -R Radius (miles/kilometers)\n"); fprintf(stdout," -R Radius (miles/kilometers)\n");
fprintf(stdout," -res Pixels per degree. 300/600/1200(default)/3600 (optional)\n"); fprintf(stdout," -res Pixels per degree. 300/600/1200(default)/3600 (optional)\n");
fprintf(stdout," -t Terrain background\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; ano_filename[0]=0;
ani_filename[0]=0; ani_filename[0]=0;
earthradius=EARTHRADIUS; earthradius=EARTHRADIUS;
max_range=1.0; max_range=1.0;
propmodel=1; //ITM
winfiles=0;
lat=0; lat=0;
lon=0; lon=0;
@@ -3822,8 +3887,8 @@ int main(int argc, char *argv[])
sscanf("0.1","%lf",&altitudeLR); sscanf("0.1","%lf",&altitudeLR);
// Defaults // Defaults
LR.eps_dielect=15.0; // Farmland LR.eps_dielect=15.0; // Farmland
LR.sgm_conductivity=0.005; // Farmland LR.sgm_conductivity=0.005; // Farmland
LR.eno_ns_surfref=301.0; LR.eno_ns_surfref=301.0;
LR.frq_mhz=19.0; // Deliberately too low LR.frq_mhz=19.0; // Deliberately too low
@@ -3837,10 +3902,6 @@ int main(int argc, char *argv[])
tx_site[0].lon=361.0; 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; x<MAXPAGES; x++) for (x=0; x<MAXPAGES; x++)
{ {
dem[x].min_el=32768; dem[x].min_el=32768;
@@ -3877,9 +3938,9 @@ int main(int argc, char *argv[])
jgets=1; jgets=1;
break; break;
case 3600: case 3600:
MAXRAD=100; MAXRAD=100;
ippd=3600; ippd=3600;
jgets=0; jgets=0;
break; break;
@@ -4146,9 +4207,9 @@ int main(int argc, char *argv[])
/*UDT*/ /*UDT*/
if (strcmp(argv[x],"-udt")==0) if (strcmp(argv[x],"-udt")==0)
{ {
z=x+1; z=x+1;
@@ -4158,7 +4219,31 @@ int main(int argc, char *argv[])
} }
} }
/*Prop model*/
if (strcmp(argv[x],"-pm")==0)
{
z=x+1;
if (z<=y && argv[z][0])
{
sscanf(argv[z],"%d",&propmodel);
}
}
//Knife edge diffraction
if (strcmp(argv[x],"-ked")==0)
{
z=x+1;
knifeedge=1;
}
//Windows friendly SDF filenames
if (strcmp(argv[x],"-wf")==0)
{
z=x+1;
winfiles=1;
}
} }
/* ERROR DETECTION */ /* ERROR DETECTION */
@@ -4221,7 +4306,10 @@ int main(int argc, char *argv[])
fprintf(stdout,"ERROR: Receiver threshold out of range (-200 / +200)"); fprintf(stdout,"ERROR: Receiver threshold out of range (-200 / +200)");
exit(0); exit(0);
} }
if(propmodel>2 && LR.frq_mhz < 150){
fprintf(stdout,"ERROR: Frequency too low for Propagation model");
exit(0);
}
/* ERROR DETECTION COMPLETE */ /* ERROR DETECTION COMPLETE */
@@ -4229,12 +4317,11 @@ int main(int argc, char *argv[])
if (metric) if (metric)
{ {
altitudeLR/=METERS_PER_FOOT; /* RXH meters --> feet */ altitudeLR/=METERS_PER_FOOT; /* 10ft * 0.3 = 3.3m */
max_range/=KM_PER_MILE; /* RAD kilometers --> miles */ max_range/=KM_PER_MILE; /* 10 / 1.6 = 7.5 */
altitude/=METERS_PER_FOOT; altitude/=METERS_PER_FOOT;
tx_site[0].alt/=METERS_PER_FOOT; /* TXH meters --> feet */ tx_site[0].alt/=METERS_PER_FOOT; /* Feet to metres */
clutter/=METERS_PER_FOOT; /* CLH meters --> feet */ clutter/=METERS_PER_FOOT; /* Feet to metres */
} }
/* Ensure a trailing '/' is present in sdf_path */ /* Ensure a trailing '/' is present in sdf_path */
@@ -4296,7 +4383,7 @@ int main(int argc, char *argv[])
/* Load the required SDF files */ /* 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) if (area_mode || topomap)
{ {
@@ -4381,22 +4468,19 @@ int main(int argc, char *argv[])
/* Load any additional SDF files, if required */ /* 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 // UDT clutter
LoadUDT (udt_file); LoadUDT (udt_file);
if (LR.frq_mhz > 20000){ if (LR.frq_mhz > 20000 || propmodel==2){
PlotLOSMap(tx_site[0],altitudeLR,ano_filename); PlotLOSMap(tx_site[0],altitudeLR,ano_filename);
DoLOS(mapfile,geo,kml,ngs,tx_site,txsites); DoLOS(mapfile,geo,kml,ngs,tx_site,txsites);
} }
else{ else{
PlotLRMap(tx_site[0],altitudeLR,ano_filename); PlotPropagation(tx_site[0],altitudeLR,ano_filename,propmodel,knifeedge);
if (LR.erp==0.0) if (LR.erp==0.0)
DoPathLoss(mapfile,geo,kml,ngs,tx_site,txsites); DoPathLoss(mapfile,geo,kml,ngs,tx_site,txsites);