2.5 - Major refactor

This commit is contained in:
alex
2015-05-27 21:45:05 +01:00
parent d2233ddb43
commit 2364bbf6b9
51 changed files with 17014 additions and 19187 deletions

32
.txt
View File

@@ -1,32 +0,0 @@
--==[ Path Profile Analysis ]==--
Transmitter site: Tx
Site location: 50.0000 North / 350.0000 West
Ground elevation: 0.00 meters AMSL
Antenna height: 30.00 meters AGL / 30.00 meters AMSL
Distance to Rx: 5.00 kilometers
Azimuth to Rx: 89.97 degrees
Depression angle to Rx: -0.3433 degrees
Receiver site: Rx
Site location: 50.0000 North / 349.9300 West
Ground elevation: 0.00 meters AMSL
Antenna height: 2.00 meters AGL / 2.00 meters AMSL
Distance to Tx: 5.00 kilometers
Azimuth to Tx: 270.03 degrees
Elevation angle to Tx: +0.2984 degrees
Longley-Rice path calculation parameters used in this analysis:
Earth's Dielectric Constant: 15.000
Earth's Conductivity: 0.005 Siemens/meter
Atmospheric Bending Constant (N-units): 301.000 ppm
Frequency: 5900.000 MHz
Radio Climate: 5 (Continental Temperate)
Polarisation: 1 (Vertical)
Fraction of Situations: 50.0%
Fraction of Time: 50.0%
Summary for the link between Tx and Rx:

View File

@@ -1,5 +1,11 @@
SIGNAL SERVER CHANGELOG
2.5 - 27 May 2015
Code refactored by Andrew Clayton / ac000 with header files
New Makefile with c / c++ multi mode compilation
Single executable now with run time switch for HD mode
Models separated into directory
2.44 - 25 Mar 2015
Improved PPA text report to list other prop models
Added HD mode to build script

51
Makefile Normal file
View File

@@ -0,0 +1,51 @@
SHELL = /bin/sh
CC = gcc
CXX = g++
CFLAGS = -Wall -O3 -s -ffast-amth
CXXFLAGS = -Wall -O3 -s -ffast-math
LIBS = -lm
VPATH = models
objects = main.o cost.o ecc33.o ericsson.o fspl.o hata.o itwom3.0.o \
los.o sui.o inputs.o outputs.o
GCC_MAJOR := $(shell $(CXX) -dumpversion 2>&1 | cut -d . -f 1)
GCC_MINOR := $(shell $(CXX) -dumpversion 2>&1 | cut -d . -f 2)
GCC_VER_OK := $(shell test $(GCC_MAJOR) -ge 4 && \
test $(GCC_MINOR) -ge 7 && \
echo 1)
ifneq "$(GCC_VER_OK)" "1"
error:
@echo "Requires GCC version >= 4.7"
@exit
endif
%.o : %.cc
@echo -e " CXX\t$@"
@$ $(CXX) $(CXXFLAGS) -c $<
%.o : %.c
@echo -e " CC\t$@"
@$ $(CC) $(CFLAGS) -c $<
signalserver: $(objects)
@echo -e " LNK\t$@"
@$(CXX) $(objects) -o $@ ${LIBS}
@echo -e " SYMLNK\tsignalserverHD -> $@"
@ln -sf $@ signalserverHD
main.o: main.cc common.h inputs.hh outputs.hh itwom3.0.hh los.hh
inputs.o: inputs.cc common.h main.hh
outputs.o: outputs.cc common.h inputs.hh main.hh cost.hh ecc33.hh ericsson.hh \
fspl.hh hata.hh itwom3.0.hh sui.hh
los.o: los.cc common.h main.hh cost.hh ecc33.hh ericsson.hh fspl.hh hata.hh \
itwom3.0.hh sui.hh
.PHONY: clean
clean:
rm -f $(objects) signalserver signalserverHD

View File

@@ -20,15 +20,7 @@
* *
\****************************************************************************/
/*
REQUIRES GCC >= 4.7
90m mode
g++ -Wall -Ofast -s -lm itwom3.0.cpp models.cpp main.cpp -o signalserver
30m HD mode
g++ -Wall -Ofast -s -lm itwom3.0.cpp models.cpp main.cpp -DHD -o signalserverHD
*/
-- Signal Server 2.41 --
-- Signal Server 2.5 --
Compiled for 64 tiles at 1200 pixels/degree
-d Directory containing .sdf tiles

View File

@@ -1,18 +0,0 @@
0.000 -10.000
0.057 -11.490
0.114 -12.981
0.172 -14.473
0.229 -15.965
0.286 -17.457
0.343 -18.950
0.401 -20.444
0.458 -21.938
0.515 -23.432
0.572 -24.927
0.630 -26.423
0.687 -27.919
0.744 -29.415
0.801 -30.913
0.858 -32.410
0.916 -33.908
0.973 -35.407

View File

@@ -1,19 +0,0 @@
0.000 -0.000
0.057 -4.240
0.114 -5.811
0.172 -6.882
0.229 -7.666
0.286 -8.245
0.343 -8.660
0.401 -8.934
0.458 -9.081
0.515 -9.105
0.572 -9.008
0.630 -8.786
0.687 -8.430
0.744 -7.920
0.801 -7.226
0.858 -6.284
0.916 -4.959
0.973 -2.736
0.996 0.000

View File

@@ -1,19 +0,0 @@
0.000 -0.000
0.057 -2.544
0.114 -3.487
0.172 -4.129
0.229 -4.600
0.286 -4.947
0.343 -5.196
0.401 -5.361
0.458 -5.448
0.515 -5.463
0.572 -5.405
0.630 -5.272
0.687 -5.058
0.744 -4.752
0.801 -4.335
0.858 -3.771
0.916 -2.975
0.973 -1.642
0.996 0.000

View File

@@ -1 +0,0 @@
0.996 0.000

View File

@@ -1,19 +0,0 @@
0.000 0.000
0.057 0.000
0.114 0.000
0.172 0.000
0.229 0.000
0.286 0.000
0.343 0.000
0.401 0.000
0.458 0.000
0.515 0.000
0.572 0.000
0.630 0.000
0.687 0.000
0.744 0.000
0.801 0.000
0.858 0.000
0.916 0.000
0.973 0.000
0.996 0.000

View File

@@ -1,7 +0,0 @@
#!/bin/bash
rm -f signalserver
rm -f signalserverHD
g++ -Wall -O3 -s -lm -fomit-frame-pointer itwom3.0.cpp models.cpp main.cpp -o signalserver
g++ -Wall -O3 -s -lm -fomit-frame-pointer itwom3.0.cpp models.cpp main.cpp -DHD -o signalserverHD
./signalserver

119
common.h Normal file
View File

@@ -0,0 +1,119 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#define GAMMA 2.5
#ifndef PI
#define PI 3.141592653589793
#endif
#ifndef TWOPI
#define TWOPI 6.283185307179586
#endif
#ifndef HALFPI
#define HALFPI 1.570796326794896
#endif
#define DEG2RAD 1.74532925199e-02
#define EARTHRADIUS 20902230.97
#define METERS_PER_MILE 1609.344
#define METERS_PER_FOOT 0.3048
#define KM_PER_MILE 1.609344
#define FOUR_THIRDS 1.3333333333333
struct dem {
int min_north;
int max_north;
int min_west;
int max_west;
int max_el;
int min_el;
short **data;
unsigned char **mask;
unsigned char **signal;
};
struct site {
double lat;
double lon;
float alt;
char name[50];
char filename[255];
};
struct path {
double *lat;
double *lon;
double *elevation;
double *distance;
int length;
};
struct LR {
double eps_dielect;
double sgm_conductivity;
double eno_ns_surfref;
double frq_mhz;
double conf;
double rel;
double erp;
int radio_climate;
int pol;
float antenna_pattern[361][1001];
};
struct region {
unsigned char color[128][3];
int level[128];
int levels;
};
extern int MAXPAGES;
extern int ARRAYSIZE;
extern int IPPD;
extern int min_north;
extern int max_north;
extern int min_west;
extern int max_west;
extern int ippd;
extern int mpi;
extern int max_elevation;
extern int min_elevation;
extern int contour_threshold;
extern int loops;
extern int jgets;
extern double earthradius;
extern double north;
extern double east;
extern double south;
extern double west;
extern double max_range;
extern double dpp;
extern double ppd;
extern double fzone_clearance;
extern double clutter;
extern double dBm;
extern double loss;
extern double field_strength;
extern double *elev;
extern char string[];
extern char sdf_path[];
extern char gpsav;
extern unsigned char got_elevation_pattern;
extern unsigned char got_azimuth_pattern;
extern unsigned char metric;
extern unsigned char dbm;
extern struct dem *dem;
extern struct path path;
extern struct LR LR;
extern struct region region;
extern int debug;
#endif /* _COMMON_H_ */

View File

@@ -1,41 +0,0 @@
/*****************************************************************************
* 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;
}

110
hata.cpp
View File

@@ -1,110 +0,0 @@
/*****************************************************************************
* 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; // 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]<(obh+20)){
// 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 / (300/freq); // Diffraction angle divided 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;
}

1390
inputs.cc Normal file

File diff suppressed because it is too large Load Diff

16
inputs.hh Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _INPUTS_HH_
#define _INPUTS_HH_
#include "common.h"
int LoadSDF_SDF(char *name, int winfiles);
char LoadSDF(char *name, int winfiles);
void LoadPAT(char *filename);
void LoadSignalColors(struct site xmtr);
void LoadLossColors(struct site xmtr);
void LoadDBMColors(struct site xmtr);
void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat,
int winfiles);
void LoadUDT(char *filename);
#endif /* _INPUTS_HH_ */

1532
itm.cpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1691
main.cc Normal file

File diff suppressed because it is too large Load Diff

5553
main.cpp

File diff suppressed because it is too large Load Diff

26
main.hh Normal file
View File

@@ -0,0 +1,26 @@
#ifndef _MAIN_HH_
#define _MAIN_HH_
#include <stdio.h>
#include "common.h"
int ReduceAngle(double angle);
double LonDiff(double lon1, double lon2);
int PutMask(double lat, double lon, int value);
int OrMask(double lat, double lon, int value);
int GetMask(double lat, double lon);
int PutSignal(double lat, double lon, unsigned char signal);
unsigned char GetSignal(double lat, double lon);
double GetElevation(struct site location);
int AddElevation(double lat, double lon, double height);
double Distance(struct site site1, struct site site2);
double Azimuth(struct site source, struct site destination);
double ElevationAngle(struct site source, struct site destination);
void ReadPath(struct site source, struct site destination);
double ElevationAngle2(struct site source, struct site destination, double er);
double ReadBearing(char *input);
void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f,
FILE *outfile);
#endif /* _MAIN_HH_ */

5984
mainHD.cc Normal file

File diff suppressed because it is too large Load Diff

5720
mainHD.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -1,276 +0,0 @@
/*****************************************************************************
* RF propagation models for Signal Server by Alex Farrant, CloudRF.com *
* *
* 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>
using namespace std;
/*
Whilst every effort has been made to ensure the accuracy of the models, their accuracy is not guaranteed.
Finding a reputable paper to source these models from took a while. There was lots of bad copy-pasta out there.
A good paper: http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf
*/
#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 is based upon a recognised formula like Huygens, but trades thoroughness for increased speed
which adds a proportional diffraction effect to obstacles.
*/
double ked(double freq, double elev[], double rxh, double dkm){
double obh,obd,rxobaoi=0,d,dipheight=25;
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]<(obh+dipheight)){
// 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 / (300/freq); // Diffraction angle divided by wavelength (m)
}else{
return 0;
}
}
double HATApathLoss(float f,float TxH, float RxH, float d, int mode){
/*
HATA model for cellular planning
Frequency (MHz) 150 to 1500MHz
Base station height 30-200m
Mobile station height 1-10m
Distance 1-20km
modes 1 = URBAN, 2 = SUBURBAN, 3 = OPEN
*/
if(f<150 || f>1500){
printf("Error: Hata model frequency range 150-1500MHz\n");
exit(EXIT_FAILURE);
}
float lRxH = log10(11.75*RxH);
float C_H = 3.2*lRxH*lRxH-4.97;
float logf = log10(f);
float L_u = 69.55 + 26.16*logf - 13.82*log10(TxH) - C_H + (44.9 - 6.55*log10(TxH))*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;
}
double COST231pathLoss(float f,float TxH, float RxH, float d, int mode){
/*
COST231 extension to HATA model
Frequency 1500 to 2000MHz
TxH = Base station height 30 to 200m
RxH = Mobile station height 1 to 10m
Distance 1-20km
modes 1 = URBAN, 2 = SUBURBAN, 3 = OPEN
http://morse.colorado.edu/~tlen5510/text/classwebch3.html
*/
if(f<150 || f>2000){
printf("Error: COST231 Hata model frequency range 150-2000MHz\n");
exit(EXIT_FAILURE);
}
int C = 3; // 3dB for Urban
float lRxH = log10(11.75*RxH);
float C_H = 3.2*(lRxH*lRxH)-4.97; // Large city (conservative)
int c0 = 69.55;
int cf = 26.16;
if(f>1500){
c0=46.3;
cf=33.9;
}
if(mode==2){
C = 0; // Medium city (average)
C_H = 8.29*(lRxH*lRxH)-1.1;
}
if(mode==3){
C = -3; // Small city (Optimistic)
C_H = (1.1*log10(f) - 0.7) * RxH - (1.56 * log10(f)) + 0.8;
}
float logf = log10(f);
double dbloss = c0 + (cf * logf) - (13.82 * log10(TxH)) - C_H + (44.9 - 6.55 * log10(TxH)) * log10(d) + C;
return dbloss;
}
double SUIpathLoss(float f,float TxH, float RxH, float d, int mode){
/*
f = Frequency (MHz)
TxH = Transmitter height (m)
RxH = Receiver height (m)
d = distance (km)
mode 1 = Hilly + trees
mode 2 = Flat + trees OR hilly + light foliage
mode 3 = Flat + light foliage
http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf
*/
d=d*1000; // km to m
if(f<1900 || f>11000){
printf("Error: SUI model frequency range 1.9-11GHz\n");
exit(EXIT_FAILURE);
}
// Terrain mode A is default
double a = 4.6;
double b = 0.0075;
double c = 12.6;
double s = 10.6; // Optional fading value
int XhCF = -10.8;
if(mode==2){
a=4.0;
b=0.0065;
c=17.1;
s=6; // average
}
if(mode==3){
a=3.6;
b=0.005;
c=20;
s=3; // Optimistic
XhCF = -20;
}
double d0 = 100;
double A = 20 * log10((4*M_PI*d0)/(300/f));
double y = (a - b * TxH) + c / TxH;
double Xf = 6 * log10(f/2000);
double Xh = XhCF * log10(RxH/2);
return A + (10*y*log10(d/d0)) + Xf + Xh + s;
}
double ECC33pathLoss(float f,float TxH, float RxH, float d, int mode){
if(f<700 || f>3500){
printf("Error: ECC33 model frequency range 700-3500MHz\n");
exit(EXIT_FAILURE);
}
// MHz to GHz
f=f/1000;
double Gr = 0.759 * RxH - 1.862; // Big city with tall buildings (1)
// PL = Afs + Abm - Gb - Gr
double Afs = 92.4 + 20 * log10(d) + 20 * log10(f);
double Abm = 20.41 + 9.83 * log10(d) + 7.894 * log10(f) + 9.56 * (log10(f) * log10(f));
double Gb = log10(TxH/200) * (13.958 + 5.8 * (log10(d) * log10(d)));
if(mode>1){ // Medium city (Europe)
Gr = (42.57 + 13.7 * log10(f)) * (log10(RxH) - 0.585);
}
return Afs+Abm-Gb-Gr;
}
double EricssonpathLoss(float f,float TxH, float RxH, float d, int mode){
/*
http://research.ijcaonline.org/volume84/number7/pxc3892830.pdf
AKA Ericsson 9999 model
*/
// Default is Urban which bizarrely has lowest loss
double a0=36.2, a1=30.2, a2=-12, a3=0.1;
if(f<150 || f>3500){
printf("Error: Ericsson9999 model frequency range 150-3500MHz\n");
exit(EXIT_FAILURE);
}
if(mode==2){ // Suburban / Med loss
a0=43.2;
a1=68.93;
}
if(mode==1){ // "Rural" but has highest loss according to Ericsson.
a0=45.95;
a1=100.6;
}
double g1 = (11.75 * RxH) * (11.75 * RxH);
double g2 = (44.49 * log10(f)) - 4.78 * ((log10(f) * log10(f)));
return a0 + a1 * log10(d) + a2 * log10(TxH) + a3 * log10(TxH) * log10(d) - (3.2 * log10(g1)) + g2;
}
double FSPLpathLoss(float f, float d){
/*
Free Space Path Loss (ITU-R P.525) model
Frequency: Any
Distance: Any
*/
//MHz to GHz
f = f / 1000;
double dbloss = (20 * log10(d)) + (20 * log10(f)) + 92.45;
return dbloss;
}
/*
int main(int argc, char* argv[]){
if(argc<5){
printf("Need freq,TxH,RxH,dist,terr\n");
return 0;
}
int dis, ter;
double frq, TxH, RxH;
sscanf(argv[1],"%lf",&frq);
sscanf(argv[2],"%lf",&TxH);
sscanf(argv[3],"%lf",&RxH);
sscanf(argv[4],"%d",&dis);
sscanf(argv[5],"%d",&ter);
// ALL are freq in MHz and distances in metres
printf("FSPL: %.2f dB\n",FSPLpathLoss(frq,dis));
printf("HATA (%d): %.2f dB\n",ter,HATApathLoss(frq,TxH,RxH,dis,ter));
printf("COST-HATA (%d): %.2f dB\n",ter,COST231pathLoss(frq,TxH,RxH,dis,ter));
printf("SUI (%d): %.2f dB\n",ter,SUIpathLoss(frq,TxH,RxH,dis,ter));
printf("ECC33 (%d): %.2f dB\n",ter,ECC33pathLoss(frq,TxH,RxH,dis,ter));
printf("Ericsson (%d): %.2f dB\n",ter,EricssonpathLoss(frq,TxH,RxH,dis,ter));
}
*/

7
models/README Normal file
View File

@@ -0,0 +1,7 @@
Whilst every effort has been made to ensure the accuracy of the models, their
accuracy is not guaranteed.
Finding a reputable paper to source these models from took a while. There was
lots of bad copy-paste out there. A good paper:
http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf

60
models/cost.cc Normal file
View File

@@ -0,0 +1,60 @@
/*****************************************************************************
* COST231-HATA MODEL for Signal Server by Alex Farrant *
* 30 December 2013i *
* 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
double COST231pathLoss(float f, float TxH, float RxH, float d, int mode)
{
/*
COST231 extension to HATA model
Frequency 1500 to 2000MHz
TxH = Base station height 30 to 200m
RxH = Mobile station height 1 to 10m
Distance 1-20km
modes 1 = URBAN, 2 = SUBURBAN, 3 = OPEN
http://morse.colorado.edu/~tlen5510/text/classwebch3.html
*/
if (f < 150 || f > 2000) {
printf
("Error: COST231 Hata model frequency range 150-2000MHz\n");
exit(EXIT_FAILURE);
}
int C = 3; // 3dB for Urban
float lRxH = log10(11.75 * RxH);
float C_H = 3.2 * (lRxH * lRxH) - 4.97; // Large city (conservative)
int c0 = 69.55;
int cf = 26.16;
if (f > 1500) {
c0 = 46.3;
cf = 33.9;
}
if (mode == 2) {
C = 0; // Medium city (average)
C_H = 8.29 * (lRxH * lRxH) - 1.1;
}
if (mode == 3) {
C = -3; // Small city (Optimistic)
C_H = (1.1 * log10(f) - 0.7) * RxH - (1.56 * log10(f)) + 0.8;
}
float logf = log10(f);
double dbloss =
c0 + (cf * logf) - (13.82 * log10(TxH)) - C_H + (44.9 -
6.55 *
log10(TxH)) *
log10(d) + C;
return dbloss;
}

6
models/cost.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _COST_HH_
#define _COST_HH_
double COST231pathLoss(float f, float TxH, float RxH, float d, int mode);
#endif /* _COST_HH_ */

26
models/ecc33.cc Normal file
View File

@@ -0,0 +1,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double ECC33pathLoss(float f, float TxH, float RxH, float d, int mode)
{
if (f < 700 || f > 3500) {
printf("Error: ECC33 model frequency range 700-3500MHz\n");
exit(EXIT_FAILURE);
}
// MHz to GHz
f = f / 1000;
double Gr = 0.759 * RxH - 1.862; // Big city with tall buildings (1)
// PL = Afs + Abm - Gb - Gr
double Afs = 92.4 + 20 * log10(d) + 20 * log10(f);
double Abm =
20.41 + 9.83 * log10(d) + 7.894 * log10(f) +
9.56 * (log10(f) * log10(f));
double Gb = log10(TxH / 200) * (13.958 + 5.8 * (log10(d) * log10(d)));
if (mode > 1) { // Medium city (Europe)
Gr = (42.57 + 13.7 * log10(f)) * (log10(RxH) - 0.585);
}
return Afs + Abm - Gb - Gr;
}

6
models/ecc33.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _ECC33_HH_
#define _ECC33_HH_
double ECC33pathLoss(float f, float TxH, float RxH, float d, int mode);
#endif /* _ECC33_HH_ */

33
models/ericsson.cc Normal file
View File

@@ -0,0 +1,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double EricssonpathLoss(float f, float TxH, float RxH, float d, int mode)
{
/*
http://research.ijcaonline.org/volume84/number7/pxc3892830.pdf
AKA Ericsson 9999 model
*/
// Default is Urban which bizarrely has lowest loss
double a0 = 36.2, a1 = 30.2, a2 = -12, a3 = 0.1;
if (f < 150 || f > 3500) {
printf
("Error: Ericsson9999 model frequency range 150-3500MHz\n");
exit(EXIT_FAILURE);
}
if (mode == 2) { // Suburban / Med loss
a0 = 43.2;
a1 = 68.93;
}
if (mode == 1) { // "Rural" but has highest loss according to Ericsson.
a0 = 45.95;
a1 = 100.6;
}
double g1 = (11.75 * RxH) * (11.75 * RxH);
double g2 = (44.49 * log10(f)) - 4.78 * ((log10(f) * log10(f)));
return a0 + a1 * log10(d) + a2 * log10(TxH) +
a3 * log10(TxH) * log10(d) - (3.2 * log10(g1)) + g2;
}

6
models/ericsson.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _ERICSSON_HH_
#define _ERICSSON_HH_
double EricssonpathLoss(float f, float TxH, float RxH, float d, int mode);
#endif /* _ERICSSON_HH_ */

View File

@@ -12,13 +12,10 @@
* for more details. *
* */
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
double FsplLinkdB(float f, float d){
double FSPLpathLoss(float f, float d)
{
/*
Free Space Path Loss model
Frequency: Any

6
models/fspl.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _FSPL_HH_
#define _FSPL_HH_
double FSPLpathLoss(float f, float d);
#endif /* _FSPL_HH_ */

56
models/hata.cc Normal file
View File

@@ -0,0 +1,56 @@
/*****************************************************************************
* 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 <math.h>
double HATApathLoss(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;
}

6
models/hata.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _HATA_HH_
#define _HATA_HH_
double HATApathLoss(float f, float h_B, float h_M, float d, int mode);
#endif /* _HATA_HH_ */

1574
models/itm.cc Normal file

File diff suppressed because it is too large Load Diff

2963
models/itwom3.0.cc Normal file

File diff suppressed because it is too large Load Diff

14
models/itwom3.0.hh Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _ITWOM30_HH_
#define _ITWOM30_HH_
void point_to_point_ITM(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);
void point_to_point(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);
#endif /* _ITWOM30_HH_ */

864
models/los.cc Normal file
View File

@@ -0,0 +1,864 @@
#include <stdio.h>
#include <math.h>
#include "../common.h"
#include "../main.hh"
#include "cost.hh"
#include "ecc33.hh"
#include "ericsson.hh"
#include "fspl.hh"
#include "hata.hh"
#include "itwom3.0.hh"
#include "sui.hh"
/*
* Acute Angle from Rx point to an obstacle of height (opp) and
* distance (adj)
*/
static double incidenceAngle(double opp, double adj)
{
return atan2(opp, adj) * 180 / PI;
}
/*
* Knife edge diffraction:
* This is based upon a recognised formula like Huygens, but trades
* thoroughness for increased speed which adds a proportional diffraction
* effect to obstacles.
*/
static double ked(double freq, double rxh, double dkm)
{
double obh, obd, rxobaoi = 0, d, dipheight = 25;
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] < (obh + dipheight)) {
// 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 / (300 / freq); // Diffraction angle divided by wavelength (m)
} else {
return 0;
}
}
void PlotLOSPath(struct site source, struct site destination, char mask_value,
FILE *fd)
{
/* This function analyzes the path between the source and
destination locations. It determines which points along
the path have line-of-sight visibility to the source.
Points along with path having line-of-sight visibility
to the source at an AGL altitude equal to that of the
destination location are stored by setting bit 1 in the
mask[][] array, which are displayed in green when PPM
maps are later generated by ss. */
char block;
int x, y;
register double cos_xmtr_angle, cos_test_angle, test_alt;
double distance, rx_alt, tx_alt;
ReadPath(source, destination);
for (y = 0; y < path.length; y++) {
/* Test this point only if it hasn't been already
tested and found to be free of obstructions. */
if ((GetMask(path.lat[y], path.lon[y]) & mask_value) == 0) {
distance = 5280.0 * path.distance[y];
tx_alt = earthradius + source.alt + path.elevation[0];
rx_alt =
earthradius + destination.alt + path.elevation[y];
/* Calculate the cosine of the elevation of the
transmitter as seen at the temp rx point. */
cos_xmtr_angle =
((rx_alt * rx_alt) + (distance * distance) -
(tx_alt * tx_alt)) / (2.0 * rx_alt * distance);
for (x = y, block = 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 PlotPropPath(struct site source, struct site destination,
unsigned char mask_value, FILE * fd, int propmodel,
int knifeedge, int pmenv)
{
int x, y, ifs, ofs, errnum;
char block = 0, strmode[100];
double loss, azimuth, pattern = 0.0,
xmtr_alt, dest_alt, xmtr_alt2, dest_alt2,
cos_rcvr_angle, cos_test_angle = 0.0, test_alt,
elevation = 0.0, distance = 0.0, four_thirds_earth,
field_strength = 0.0, rxp, dBm, txelev, dkm, diffloss;
struct site temp;
ReadPath(source, destination);
four_thirds_earth = FOUR_THIRDS * EARTHRADIUS;
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);
/* Copy ending points without clutter */
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;
/* Since the only energy the Longley-Rice model considers
reaching the destination is based on what is scattered
or deflected from the first obstruction along the path,
we first need to find the location and elevation angle
of that first obstruction (if it exists). This is done
using a 4/3rds Earth radius to match the model used by
Longley-Rice. This information is required for properly
integrating the antenna's elevation pattern into the
calculation for overall path loss. */
for (y = 2; (y < (path.length - 1) && path.distance[y] <= max_range);
y++) {
/* Process this point only if it
has not already been processed. */
if ((GetMask(path.lat[y], path.lon[y]) & 248) !=
(mask_value << 3)) {
distance = 5280.0 * path.distance[y];
xmtr_alt =
four_thirds_earth + source.alt + path.elevation[0];
dest_alt =
four_thirds_earth + destination.alt +
path.elevation[y];
dest_alt2 = dest_alt * dest_alt;
xmtr_alt2 = xmtr_alt * xmtr_alt;
/* Calculate the cosine of the elevation of
the receiver as seen by the transmitter. */
cos_rcvr_angle =
((xmtr_alt2) + (distance * distance) -
(dest_alt2)) / (2.0 * xmtr_alt * distance);
if (cos_rcvr_angle > 1.0)
cos_rcvr_angle = 1.0;
if (cos_rcvr_angle < -1.0)
cos_rcvr_angle = -1.0;
if (got_elevation_pattern || fd != NULL) {
/* Determine the elevation angle to the first obstruction
along the path IF elevation pattern data is available
or an output (.ano) file has been designated. */
for (x = 2, block = 0; (x < y && block == 0);
x++) {
distance = 5280.0 * path.distance[x];
test_alt =
four_thirds_earth +
(path.elevation[x] ==
0.0 ? path.elevation[x] : path.
elevation[x] + clutter);
/* Calculate the cosine of the elevation
angle of the terrain (test point)
as seen by the transmitter. */
cos_test_angle =
((xmtr_alt2) +
(distance * distance) -
(test_alt * test_alt)) / (2.0 *
xmtr_alt
*
distance);
if (cos_test_angle > 1.0)
cos_test_angle = 1.0;
if (cos_test_angle < -1.0)
cos_test_angle = -1.0;
/* 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 sense of the
following "if" statement is reversed from
what it would be if the angles themselves
were compared. */
if (cos_rcvr_angle >= cos_test_angle)
block = 1;
}
if (block)
elevation =
((acos(cos_test_angle)) / DEG2RAD) -
90.0;
else
elevation =
((acos(cos_rcvr_angle)) / DEG2RAD) -
90.0;
}
/* Determine attenuation for each point along the
path using a prop model starting at y=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]);
if (path.elevation[y] < 1) {
path.elevation[y] = 1;
}
dkm = (elev[1] * elev[0]) / 1000; // km
switch (propmodel) {
case 1:
// Longley Rice ITM
point_to_point_ITM(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 1, 2 & 3
loss =
HATApathLoss(LR.frq_mhz, txelev,
path.elevation[y] +
(destination.alt *
METERS_PER_FOOT), dkm, pmenv);
break;
case 4:
// COST231-HATA
loss =
ECC33pathLoss(LR.frq_mhz, txelev,
path.elevation[y] +
(destination.alt *
METERS_PER_FOOT), dkm,
pmenv);
break;
case 5:
// SUI
loss =
SUIpathLoss(LR.frq_mhz, txelev,
path.elevation[y] +
(destination.alt *
METERS_PER_FOOT), dkm, pmenv);
break;
case 6:
loss =
COST231pathLoss(LR.frq_mhz, txelev,
path.elevation[y] +
(destination.alt *
METERS_PER_FOOT), dkm,
pmenv);
break;
case 7:
// ITU-R P.525 Free space path loss
loss = FSPLpathLoss(LR.frq_mhz, dkm);
break;
case 8:
// ITWOM 3.0
point_to_point(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 9:
// Ericsson
loss =
EricssonpathLoss(LR.frq_mhz, txelev,
path.elevation[y] +
(destination.alt *
METERS_PER_FOOT), dkm,
pmenv);
break;
default:
point_to_point_ITM(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,
destination.alt * METERS_PER_FOOT, dkm);
loss += (diffloss); // ;)
}
//Key stage. Link dB for p2p is returned as 'loss'.
temp.lat = path.lat[y];
temp.lon = path.lon[y];
azimuth = (Azimuth(source, temp));
if (fd != NULL)
fprintf(fd, "%.7f, %.7f, %.3f, %.3f, ",
path.lat[y], path.lon[y], azimuth,
elevation);
/* If ERP==0, write path loss to alphanumeric
output file. Otherwise, write field strength
or received power level (below), as appropriate. */
if (fd != NULL && LR.erp == 0.0)
fprintf(fd, "%.2f", loss);
/* Integrate the antenna's radiation
pattern into the overall path loss. */
x = (int)rint(10.0 * (10.0 - elevation));
if (x >= 0 && x <= 1000) {
azimuth = rint(azimuth);
pattern =
(double)LR.antenna_pattern[(int)azimuth][x];
if (pattern != 0.0) {
pattern = 20.0 * log10(pattern);
loss -= pattern;
}
}
if (LR.erp != 0.0) {
if (dbm) {
/* dBm is based on EIRP (ERP + 2.14) */
rxp =
LR.erp /
(pow(10.0, (loss - 2.14) / 10.0));
dBm = 10.0 * (log10(rxp * 1000.0));
if (fd != NULL)
fprintf(fd, "%.3f", dBm);
/* Scale roughly between 0 and 255 */
ifs = 200 + (int)rint(dBm);
if (ifs < 0)
ifs = 0;
if (ifs > 255)
ifs = 255;
ofs =
GetSignal(path.lat[y], path.lon[y]);
if (ofs > ifs)
ifs = ofs;
PutSignal(path.lat[y], path.lon[y],
(unsigned char)ifs);
}
else {
field_strength =
(139.4 +
(20.0 * log10(LR.frq_mhz)) -
loss) +
(10.0 * log10(LR.erp / 1000.0));
ifs = 100 + (int)rint(field_strength);
if (ifs < 0)
ifs = 0;
if (ifs > 255)
ifs = 255;
ofs =
GetSignal(path.lat[y], path.lon[y]);
if (ofs > ifs)
ifs = ofs;
PutSignal(path.lat[y], path.lon[y],
(unsigned char)ifs);
if (fd != NULL)
fprintf(fd, "%.3f",
field_strength);
}
}
else {
if (loss > 255)
ifs = 255;
else
ifs = (int)rint(loss);
ofs = GetSignal(path.lat[y], path.lon[y]);
if (ofs < ifs && ofs != 0)
ifs = ofs;
PutSignal(path.lat[y], path.lon[y],
(unsigned char)ifs);
}
if (fd != NULL) {
if (block)
fprintf(fd, " *");
fprintf(fd, "\n");
}
/* Mark this point as having been analyzed */
PutMask(path.lat[y], path.lon[y],
(GetMask(path.lat[y], path.lon[y]) & 7) +
(mask_value << 3));
}
}
}
void PlotLOSMap(struct site source, double altitude, char *plo_filename)
{
/* This function performs a 360 degree sweep around the
transmitter site (source location), and plots the
line-of-sight coverage of the transmitter 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 WritePPM() function
is later invoked. */
int x, y, z;
struct site edge;
double lat, lon, minwest, maxnorth, th;
static unsigned char mask_value = 1;
FILE *fd = NULL;
if (plo_filename[0] != 0)
fd = fopen(plo_filename, "wb");
if (fd != NULL) {
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 = ppd / loops;
z = (int)(th * ReduceAngle(max_west - min_west));
minwest = dpp + (double)min_west;
maxnorth = (double)max_north - dpp;
for (lon = minwest, x = 0, y = 0;
(LonDiff(lon, (double)max_west) <= 0.0);
y++, lon = minwest + (dpp * (double)y)) {
if (lon >= 360.0)
lon -= 360.0;
edge.lat = max_north;
edge.lon = lon;
edge.alt = altitude;
PlotLOSPath(source, edge, mask_value, fd);
}
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)) {
edge.lat = lat;
edge.lon = min_west;
edge.alt = altitude;
PlotLOSPath(source, edge, mask_value, fd);
}
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)) {
if (lon >= 360.0)
lon -= 360.0;
edge.lat = min_north;
edge.lon = lon;
edge.alt = altitude;
PlotLOSPath(source, edge, mask_value, fd);
}
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)) {
edge.lat = lat;
edge.lon = max_west;
edge.alt = altitude;
PlotLOSPath(source, edge, mask_value, fd);
}
switch (mask_value) {
case 1:
mask_value = 8;
break;
case 8:
mask_value = 16;
break;
case 16:
mask_value = 32;
}
}
void PlotPropagation(struct site source, double altitude, char *plo_filename,
int propmodel, int knifeedge, int haf, int pmenv)
{
int y, z, count;
struct site edge;
double lat, lon, minwest, maxnorth, th;
unsigned char x;
static unsigned char mask_value = 1;
FILE *fd = NULL;
minwest = dpp + (double)min_west;
maxnorth = (double)max_north - dpp;
count = 0;
if (LR.erp == 0.0 && debug)
fprintf(stdout, "path loss");
else {
if (debug) {
if (dbm)
fprintf(stdout, "signal power level");
else
fprintf(stdout, "field strength");
}
}
if (debug) {
fprintf(stdout,
" contours of \"%s\"\nout to a radius of %.2f %s with Rx antenna(s) at %.2f %s AGL\n",
source.name,
metric ? max_range * KM_PER_MILE : max_range,
metric ? "kilometers" : "miles",
metric ? altitude * METERS_PER_FOOT : altitude,
metric ? "meters" : "feet");
}
if (clutter > 0.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 (plo_filename[0] != 0)
fd = fopen(plo_filename, "wb");
if (fd != NULL) {
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 = 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)) {
if (lon >= 360.0)
lon -= 360.0;
edge.lat = max_north;
edge.lon = lon;
edge.alt = altitude;
PlotPropPath(source, edge, mask_value, fd, propmodel,
knifeedge, pmenv);
count++;
if (count == z) {
count = 0;
if (x == 3)
x = 0;
else
x++;
}
}
}
//S2
if (haf == 0 || haf == 1) {
count = 0;
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)) {
edge.lat = lat;
edge.lon = min_west;
edge.alt = altitude;
PlotPropPath(source, edge, mask_value, fd, propmodel,
knifeedge, pmenv);
count++;
if (count == z) {
count = 0;
if (x == 3)
x = 0;
else
x++;
}
}
}
//S3
if (haf == 0 || haf == 2) {
count = 0;
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)) {
if (lon >= 360.0)
lon -= 360.0;
edge.lat = min_north;
edge.lon = lon;
edge.alt = altitude;
PlotPropPath(source, edge, mask_value, fd, propmodel,
knifeedge, pmenv);
count++;
if (count == z) {
count = 0;
if (x == 3)
x = 0;
else
x++;
}
}
}
//S4
if (haf == 0 || haf == 2) {
count = 0;
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)) {
edge.lat = lat;
edge.lon = max_west;
edge.alt = altitude;
PlotPropPath(source, edge, mask_value, fd, propmodel,
knifeedge, pmenv);
count++;
if (count == z) {
count = 0;
if (x == 3)
x = 0;
else
x++;
}
}
} //S4
if (fd != NULL)
fclose(fd);
if (mask_value < 30)
mask_value++;
}
void PlotPath(struct site source, struct site destination, char mask_value)
{
/* This function analyzes the path between the source and
destination locations. It determines which points along
the path have line-of-sight visibility to the source.
Points along with path having line-of-sight visibility
to the source at an AGL altitude equal to that of the
destination location are stored by setting bit 1 in the
mask[][] array, which are displayed in green when PPM
maps are later generated by SPLAT!. */
char block;
int x, y;
register double cos_xmtr_angle, cos_test_angle, test_alt;
double distance, rx_alt, tx_alt;
ReadPath(source, destination);
for (y = 0; y < path.length; y++) {
/* Test this point only if it hasn't been already
tested and found to be free of obstructions. */
if ((GetMask(path.lat[y], path.lon[y]) & mask_value) == 0) {
distance = 5280.0 * path.distance[y];
tx_alt = earthradius + source.alt + path.elevation[0];
rx_alt =
earthradius + destination.alt + path.elevation[y];
/* Calculate the cosine of the elevation of the
transmitter as seen at the temp rx point. */
cos_xmtr_angle =
((rx_alt * rx_alt) + (distance * distance) -
(tx_alt * tx_alt)) / (2.0 * rx_alt * distance);
for (x = y, block = 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);
}
}
}

18
models/los.hh Normal file
View File

@@ -0,0 +1,18 @@
#ifndef _LOS_HH_
#define _LOS_HH_
#include <stdio.h>
#include "../common.h"
void PlotLOSPath(struct site source, struct site destination, char mask_value,
FILE *fd);
void PlotPropPath(struct site source, struct site destination,
unsigned char mask_value, FILE * fd, int propmodel,
int knifeedge, int pmenv);
void PlotLOSMap(struct site source, double altitude, char *plo_filename);
void PlotPropagation(struct site source, double altitude, char *plo_filename,
int propmodel, int knifeedge, int haf, int pmenv);
void PlotPath(struct site source, struct site destination, char mask_value);
#endif /* _LOS_HH_ */

49
models/sui.cc Normal file
View File

@@ -0,0 +1,49 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double SUIpathLoss(float f, float TxH, float RxH, float d, int mode)
{
/*
f = Frequency (MHz)
TxH = Transmitter height (m)
RxH = Receiver height (m)
d = distance (km)
mode 1 = Hilly + trees
mode 2 = Flat + trees OR hilly + light foliage
mode 3 = Flat + light foliage
http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf
*/
d = d * 1000; // km to m
if (f < 1900 || f > 11000) {
printf("Error: SUI model frequency range 1.9-11GHz\n");
exit(EXIT_FAILURE);
}
// Terrain mode A is default
double a = 4.6;
double b = 0.0075;
double c = 12.6;
double s = 10.6; // Optional fading value
int XhCF = -10.8;
if (mode == 2) {
a = 4.0;
b = 0.0065;
c = 17.1;
s = 6; // average
}
if (mode == 3) {
a = 3.6;
b = 0.005;
c = 20;
s = 3; // Optimistic
XhCF = -20;
}
double d0 = 100;
double A = 20 * log10((4 * M_PI * d0) / (300 / f));
double y = (a - b * TxH) + c / TxH;
double Xf = 6 * log10(f / 2000);
double Xh = XhCF * log10(RxH / 2);
return A + (10 * y * log10(d / d0)) + Xf + Xh + s;
}

6
models/sui.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _SUI_HH_
#define _SUI_HH_
double SUIpathLoss(float f, float TxH, float RxH, float d, int mode);
#endif /* _SUI_HH_ */

1994
outputs.cc Normal file

File diff suppressed because it is too large Load Diff

17
outputs.hh Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _OUTPUT_HH_
#define _OUTPUT_HH_
void DoPathLoss(char *filename, unsigned char geo, unsigned char kml,
unsigned char ngs, struct site *xmtr, unsigned char txsites);
void DoSigStr(char *filename, unsigned char geo, unsigned char kml,
unsigned char ngs, struct site *xmtr, unsigned char txsites);
void DoRxdPwr(char *filename, unsigned char geo, unsigned char kml,
unsigned char ngs, struct site *xmtr, unsigned char txsites);
void DoLOS(char *filename, unsigned char geo, unsigned char kml,
unsigned char ngs, struct site *xmtr, unsigned char txsites);
void PathReport(struct site source, struct site destination, char *name,
char graph_it, int propmodel, int pmenv);
void SeriesData(struct site source, struct site destination, char *name,
unsigned char fresnel_plot, unsigned char normalised);
#endif /* _OUTPUT_HH_ */

2953
ppa.cpp

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#!/bin/bash
mkdir test
RAD=10
RAD=5
MAXRAD=30
FRQ=800
ERP=20
@@ -11,6 +11,13 @@ while [ $RAD -lt $MAXRAD ]; do
convert test/$RAD.ppm test/$RAD.png
rm test/$RAD.ppm
rm test/$RAD.*cf
echo "Calculating $FRQ MHz @ $ERP Watts for $RAD km radius (HD mode)..."
time ./signalserverHD -m -d /var/SRTM1 -lat 51.47 -lon -1.50 -txh 15 -gc 2 -rxh 2 -m -dbm -rt -120 -R $RAD -erp $ERP -f $FRQ -o test/$RAD.hd -pm 1 -res 3600 -t
convert test/$RAD.hd.ppm test/$RAD.hd.png
rm test/$RAD.hd.ppm
rm test/$RAD.*cf
let RAD=RAD+5
done

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB