diff --git a/CHANGELOG b/CHANGELOG index 693010f..5d203f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ SIGNAL SERVER CHANGELOG +2.9 - 01 September 2016 +MODIS Landcover support in ASCII Grid format. Works for 1200/3600 SRTM only. + 2.82 - 15 July 2016 Fixed bug in SUI model which was making it over optimistic. diff --git a/Makefile b/Makefile index 2cdc783..a82615a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ LIBS = -lm -lpthread 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 + los.o sui.o pel.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) @@ -43,10 +43,10 @@ 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 + fspl.hh hata.hh itwom3.0.hh sui.hh pel.hh los.o: los.cc common.h main.hh cost.hh ecc33.hh ericsson.hh fspl.hh hata.hh \ - itwom3.0.hh sui.hh + itwom3.0.hh sui.hh pel.hh .PHONY: clean clean: diff --git a/inputs.cc b/inputs.cc index 922fc18..19ecb62 100644 --- a/inputs.cc +++ b/inputs.cc @@ -6,6 +6,131 @@ #include "common.h" #include "main.hh" +int loadClutter(char *filename, double radius, struct site tx) +{ + /* This function reads a MODIS 17-class clutter file in ASCII Grid format. + The nominal heights it applies to each value, eg. 5 (Mixed forest) = 15m are + taken from ITU-R P.452-11. + It doesn't have it's own matrix, instead it boosts the DEM matrix like point clutter + AddElevation(lat, lon, height); + If tiles are standard 2880 x 3840 then cellsize is constant at 0.004166 + */ + int x, y, z, clh, result, h, w; + double xll, yll, xur, yur, cellsize, cellsize2, xOffset, yOffset, lat, lon, i, j; + char line[50000]; + char * pch; + FILE *fd; + + fd = fopen(filename, "rb"); + + if (fd != NULL) { + + if (fgets(line, 19, fd) != NULL) { + pch = strtok (line," "); + pch = strtok (NULL, " "); + w = atoi(pch); + } + + if (fgets(line, 19, fd) != NULL) { + //pch = strtok (line," "); + //pch = strtok (NULL, " "); + h = atoi(pch); + } + + if(w==2880 && h==3840){ + cellsize=0.004167; + cellsize2 = cellsize * 2; + }else{ + return 0; // can't work with this yet + } + if (debug) { + fprintf(stdout, "\nLoading clutter file \"%s\" %d x %d...\n", filename, w,h); + fflush(stdout); + } + if (fgets(line, 25, fd) != NULL) { + sscanf(pch, "%lf", &xll); + } + + fgets(line, 25, fd); + if (fgets(line, 25, fd) != NULL) { + sscanf(pch, "%lf", &yll); + } + + if (debug) { + fprintf(stdout, "\nxll %.2f yll %.2f\n", xll, yll); + fflush(stdout); + } + + fgets(line, 25, fd); // cellsize + + //loop over matrix + for (y = h; y > 0; y--) { + x = 0; + if (fgets(line, 100000, fd) != NULL) { + pch = strtok(line, " "); + while (pch != NULL && x < w) { + z = atoi(pch); + + // Apply ITU-R P.452-11 + // Treat classes 0, 9, 10, 11, 15, 16 as water, (Water, savanna, grassland, wetland, snow, barren) + clh = 0; + + // evergreen, evergreen, urban + if(z == 1 || z == 2 || z == 13) + clh = 20; + + // deciduous, deciduous, mixed + if(z==3 || z==4 || z==5) + clh = 15; + if(z==6) + clh = 4; + if(z==7 || z==12 || z==14) + clh = 2; + + if(clh>1){ + clh/=2; // Because heights are deliberately conservative + xOffset=x*cellsize; // 12 deg wide + yOffset=y*cellsize; // 16 deg high + + // make all longitudes positive + if(xll+xOffset>0){ + lon=360-(xll+xOffset); + }else{ + lon=(xll+xOffset)*-1; + } + lat = yll+yOffset; + + // bounding box + if(lat > tx.lat - radius && lat < tx.lat + radius && lon > tx.lon - radius && lon < tx.lon + radius){ + + // not in near field + if((lat > tx.lat+cellsize2 || lat < tx.lat-cellsize2) || (lon > tx.lon + cellsize2 || lon < tx.lon - cellsize2)){ + AddElevation(lat,lon,clh); + + // Create rectangle of dimensions cellsize x cellsize + for(i=cellsize*-1; i < cellsize; i=i+0.0005){ + for(j=cellsize*-1; j < cellsize; j=j+0.0005){ + AddElevation(lat+i,lon+j,clh); + } + + } + } + + } + } + + x++; + pch = strtok(NULL, " "); + }//while + } else { + fprintf(stdout, "Clutter error @ x %d y %d\n", x, y); + }//if + }//for + } + fclose(fd); + return 0; +} + void readLIDAR(FILE *fd, int hoffset, int voffset, int h, int w, int indx, double n, double e, double s, double west) { diff --git a/inputs.hh b/inputs.hh index 8a19945..eb0b086 100644 --- a/inputs.hh +++ b/inputs.hh @@ -12,5 +12,6 @@ void LoadDBMColors(struct site xmtr); void LoadTopoData(int max_lon, int min_lon, int max_lat, int min_lat); void LoadUDT(char *filename); int loadLIDAR(char *filename); +int loadClutter(char *filename, double radius, struct site tx); #endif /* _INPUTS_HH_ */ diff --git a/main.cc b/main.cc index 4c83952..9cd609f 100644 --- a/main.cc +++ b/main.cc @@ -1,4 +1,4 @@ -double version = 2.82; +double version = 2.9; /****************************************************************************\ * Signal Server: Radio propagation simulator by Alex Farrant QCVS, 2E0TDW * ****************************************************************************** @@ -33,6 +33,7 @@ double version = 2.82; #include "outputs.hh" #include "models/itwom3.0.hh" #include "models/los.hh" +#include "models/pel.hh" int MAXPAGES = 64; int ARRAYSIZE = 76810;//76810; @@ -1011,7 +1012,7 @@ int main(int argc, char *argv[]) unsigned char LRmap = 0, txsites = 0, topomap = 0, geo = 0, kml = 0, area_mode = 0, max_txsites, ngs = 0; - char mapfile[255], udt_file[255], ano_filename[255], lidar_tiles[512]; + char mapfile[255], udt_file[255], ano_filename[255], lidar_tiles[512], clutter_file[255]; double altitude = 0.0, altitudeLR = 0.0, tx_range = 0.0, rx_range = 0.0, deg_range = 0.0, deg_limit = 0.0, deg_range_lon; @@ -1040,7 +1041,8 @@ int main(int argc, char *argv[]) fprintf(stdout, "Data:\n"); fprintf(stdout, " -sdf Directory containing SRTM derived .sdf DEM tiles\n"); fprintf(stdout, " -lid ASCII grid tile (LIDAR) with dimensions and resolution defined in header\n"); - fprintf(stdout, " -udt User defined CSV clutter file\n"); + fprintf(stdout, " -udt User defined point clutter as decimal co-ordinates: 'latitude,longitude,height'\n"); + fprintf(stdout, " -clt MODIS 17-class wide area clutter in ASCII grid format\n"); fprintf(stdout, "Input:\n"); fprintf(stdout, " -lat Tx Latitude (decimal degrees) -70/+70\n"); fprintf(stdout, " -lon Tx Longitude (decimal degrees) -180/+180\n"); @@ -1052,7 +1054,7 @@ int main(int argc, char *argv[]) fprintf(stdout, " -rxh Rx Height(s) (optional. Default=0.1)\n"); fprintf(stdout, " -rxg Rx gain dBi (optional for text report)\n"); fprintf(stdout, " -hp Horizontal Polarisation (default=vertical)\n"); - fprintf(stdout, " -gc Ground clutter (feet/meters)\n"); + fprintf(stdout, " -gc Random ground clutter (feet/meters)\n"); fprintf(stdout, " -m Metric units of measurement\n"); fprintf(stdout, " -te Terrain code 1-6 (optional)\n"); fprintf(stdout, " -terdic Terrain dielectric value 2-80 (optional)\n"); @@ -1065,7 +1067,7 @@ int main(int argc, char *argv[]) fprintf(stdout, " -R Radius (miles/kilometers)\n"); fprintf(stdout, " -res Pixels per tile. 300/600/1200/3600 (Optional. LIDAR res is within the tile)\n"); fprintf(stdout, " -pm Propagation model. 1: ITM, 2: LOS, 3: Hata, 4: ECC33,\n"); - fprintf(stdout, " 5: SUI, 6: COST-Hata, 7: FSPL, 8: ITWOM, 9: Ericsson\n"); + fprintf(stdout, " 5: SUI, 6: COST-Hata, 7: FSPL, 8: ITWOM, 9: Ericsson, 10: Plane earth\n"); fprintf(stdout, " -pe Propagation model mode: 1=Urban,2=Suburban,3=Rural\n"); fprintf(stdout, " -ked Knife edge diffraction (Already on for ITM)\n"); fprintf(stdout, "Debugging:\n"); @@ -1082,8 +1084,8 @@ int main(int argc, char *argv[]) /* * If we're not called as signalserverLIDAR we can allocate various - * memory now. For LIDAR stuff we need to wait until we've pasred - * the headers in the .asc file to know how much memory to allocate. + * memory now. For LIDAR we need to wait until we've parsed + * the headers in the .asc file to know how much memory to allocate... */ if (!lidar) do_allocs(); @@ -1096,6 +1098,7 @@ int main(int argc, char *argv[]) metric = 0; string[0] = 0; mapfile[0] = 0; + clutter_file[0] = 0; clutter = 0.0; forced_erp = -1.0; forced_freq = 0.0; @@ -1162,6 +1165,14 @@ int main(int argc, char *argv[]) } } + if (strcmp(argv[x], "-clt") == 0) { + z = x + 1; + + if (z <= y && argv[z][0] && argv[z][0] != '-') { + strncpy(clutter_file, argv[z], 253); + } + } + if (strcmp(argv[x], "-o") == 0) { z = x + 1; @@ -1606,7 +1617,9 @@ int main(int argc, char *argv[]) } }else{ + // DEM first LoadTopoData(max_lon, min_lon, max_lat, min_lat); + if (area_mode || topomap) { for (z = 0; z < txsites && z < max_txsites; z++) { /* "Ball park" estimates used to load any additional @@ -1704,6 +1717,15 @@ int main(int argc, char *argv[]) // User defined clutter file LoadUDT(udt_file); + // Enrich with Clutter + if(strlen(clutter_file) > 1){ + /* + Clutter tiles cover 16 x 12 degs but we only need a fraction of that area. + Limit by max_range / miles per degree (at equator) + */ + loadClutter(clutter_file,max_range/45,tx_site[0]); + } + if (ppa == 0) { if (propmodel == 2) { PlotLOSMap(tx_site[0], altitudeLR, ano_filename, use_threads); diff --git a/models/README b/models/README index a2502d1..6a29ae8 100644 --- a/models/README +++ b/models/README @@ -5,3 +5,5 @@ 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 + +Plane earth loss model taken from "Antennas and Propagation for Wireless systems" by Simon Saunders diff --git a/models/los.cc b/models/los.cc index 816fefa..7b47ff4 100644 --- a/models/los.cc +++ b/models/los.cc @@ -9,6 +9,7 @@ #include "hata.hh" #include "itwom3.0.hh" #include "sui.hh" +#include "pel.hh" #include #define NUM_SECTIONS 4 @@ -467,7 +468,7 @@ void PlotPropPath(struct site source, struct site destination, METERS_PER_FOOT), dkm, pmenv); break; case 4: - // COST231-HATA + // ECC33 loss = ECC33pathLoss(LR.frq_mhz, txelev, path.elevation[y] + @@ -484,6 +485,7 @@ void PlotPropPath(struct site source, struct site destination, METERS_PER_FOOT), dkm, pmenv); break; case 6: + // COST231-Hata loss = COST231pathLoss(LR.frq_mhz, txelev, path.elevation[y] + @@ -517,6 +519,11 @@ void PlotPropPath(struct site source, struct site destination, pmenv); break; + case 10: + // Plane earth + loss = PlaneEarthLoss(dkm, txelev, path.elevation[y] + (destination.alt * METERS_PER_FOOT)); + break; + default: point_to_point_ITM(source.alt * METERS_PER_FOOT, destination.alt * @@ -529,7 +536,7 @@ void PlotPropPath(struct site source, struct site destination, loss, strmode, errnum); } - + if (knifeedge == 1) { diffloss = ked(LR.frq_mhz, diff --git a/models/pel.cc b/models/pel.cc new file mode 100644 index 0000000..e6da80e --- /dev/null +++ b/models/pel.cc @@ -0,0 +1,29 @@ +/***************************************************************************** +* Plane Earth Path Loss model for Signal Server by Alex Farrant * +* Taken from "Antennas and Propagation for wireless communication systems" * +* ISBN 978-0-470-84879-1 * +* 10 August 2016 * +* 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 + +double PlaneEarthLoss(float d, float TxH, float RxH) +{ +/* +Plane Earth Loss model +Frequency: N/A +Distance (km): Any +*/ + // Plane earth loss is independent of frequency. + double dbloss = 40*log10(d) + 20*log10(TxH) + 20*log10(RxH); + return dbloss; +} diff --git a/models/pel.hh b/models/pel.hh new file mode 100644 index 0000000..3951ebb --- /dev/null +++ b/models/pel.hh @@ -0,0 +1,6 @@ +#ifndef _PEL_HH_ +#define _PEL_HH_ + +double PlaneEarthLoss(float d, float TxH, float RxH); + +#endif /* _PEL_HH_ */ diff --git a/signalserver b/signalserver new file mode 100755 index 0000000..d244aa9 Binary files /dev/null and b/signalserver differ diff --git a/signalserverHD b/signalserverHD new file mode 120000 index 0000000..2e55dc6 --- /dev/null +++ b/signalserverHD @@ -0,0 +1 @@ +signalserver \ No newline at end of file diff --git a/signalserverLIDAR b/signalserverLIDAR new file mode 120000 index 0000000..2e55dc6 --- /dev/null +++ b/signalserverLIDAR @@ -0,0 +1 @@ +signalserver \ No newline at end of file