Initial Commit

This commit is contained in:
N9OZB
2019-07-20 05:44:58 -05:00
parent b5116ba61e
commit 047c2f9d27
67 changed files with 18854 additions and 36 deletions

23
CHANGELOG Normal file → Executable file
View File

@@ -1,5 +1,28 @@
SIGNAL SERVER CHANGELOG
3.20 Beta - 14 Jul 2019 - N9OZB Mods
1. Added .GZ (Gzip) file processing for .sdf.gz DEM tiles.
2. Added .BZ2 (Bzip2) file processing for .sdf.bz2 DEM tiles.
3. Added much improved Antenna file options, new command line options for:
a. AZ/EL file/path with a unique filename, no longer locked to output filename.
b. Can specify command line pattern rotation azimuth, overrides value in file.
c. Can specify command line pattern downtilt and direction, overrides file.
4. Added command line option for color palette file, not locked to output name,
filename/path is used for .scf, .lcf and .dcf files, depending on mode.
5. Fixed major bug in .udt file processing in West (negative) longitudes.
6. Fixed ITM "Conf" and "Rel" options (ITM "situations" and "times") on cmdline.
7. Increased HD Version capacity from 9 to 32 DEM tiles (.sdf files).
8. Updated command line help msg, CHANGELOG, and README.md documentation.
9. Removed extra unused variables, cleaned up code and fixed a few logic issues.
10. Restructured src tree, updated Makefile. Much cleaner directory structure.
11. Added Antenna & UDT test file "ant-udt_test" to ./test.sh suite.
12. Added sample color palette files in ./color.
13. Added some conversion & postdownload scripts to ./utils/sdf.
14. Added sample antenna file DB413-B in ./antenna.
15. Tried to keep cmdline color/antenna and all changes backward compatible.
16. Added base run (runsig.sh) and kmz conversion script (genkmz.sh) files.
17. Added dandy User Manual for reference.
3.11 - 25 Sept 2018
More LIDAR edge cases, tidying of many meridian hacks(!) and regression tested with different LIDAR resolutions and configurations eg. 1x2, 2x1..
Meridian issue fixed for 30m but deliberately broken for 2m due to previous crap hacks causing a headache. Can be fixed in DEM by re-processing LIDAR tiles to NOT span the meridian.

107
README.md
View File

@@ -4,6 +4,7 @@ Multi-threaded radio propagation simulator based upon SPLAT! by Alex Farrant QCV
SPLAT! Project started in 1997 by John A. Magliacane, KD2BD
This server application will generate RF coverage predictions, producing either 2D profile plots (Point-to-Point) or 360 degree polar plots in WGS-84 projection as PPM Bitmaps.
For detailed information and historical reference data related to this project see the SPLAT! documentation. Propagation models added to this project have been sourced from reputable academic sources and all efforts have been taken to ensure their accurate implementation. Not all models are ITU ratified and you use them entirely at your own risk.
WARNING: The accuracy of the output is directly proportional to the accuracy of the inputs and the time taken defining and validating them.
@@ -18,11 +19,36 @@ WARNING: The accuracy of the output is directly proportional to the accuracy of
Signal Server is a very resource intensive multicore application. Only publish it for common use if you know what you are doing and you are advised to wrap it with another script to perform input validation.
Additional programs/scripts will be required to prepare inputs such as .sdf tiles (srtm2sdf.c), 3D antenna patterns (.ant) and user defined clutter (.udt) or manipulate the bitmap output (.ppm). More information can be found in the SPLAT! project.
Additional programs/scripts will be required to prepare inputs such as .hgt tiles (srtm2sdf.c), 3D antenna patterns (.ant) and user defined clutter (.udt) or manipulate the bitmap output (.ppm). More information can be found in the SPLAT! project.
## File extensions and types used by signalserver:
.asc LIDAR topo data file in ASCII grid format.
.jpg LIDAR topo data file in JPEG format.
.sdf SPLAT! topo data file in SPLAT! format, lo-res 90m (from SRTM3).
.sdf.gz topo data file in SPLAT! data format, gzip compressed, lo-res 90m.
.sdf.bz2 topo data file in SPLAT! data format, bzip2 compressed, lo-res 90m.
-hd.sdf SPLAT! topo data file in SPLAT! format, hi-res 30m (from SRTM1).
-hd.sdf.gz topo data file in SPLAT! data format, gzip compressed, hi-res 30m.
-hd.sdf.bz2 topo data file in SPLAT! data format, bzip2 compressed, lo-res 90m.
.scf signal level color palette file.
.lcf loss level color palette file.
.dcf dbm level color palette file.
.az SPLAT! antenna pattern azimuth data file.
.el SPLAT! antenna pattern elevation data file.
.lrp LIDAR antenna pattern data file.
.udt user defined terrain data clutter data text file.
.sh miscellaneous shell scripts and batch files.
.ppm portable pixmap - output plot graphic rendering (native).
.png portable network graphics - output plot graphic rendering (converted).
.kml Google Earth Keyhole Markup Language - output viewable with Google Earth.
.kmz Google Earth Keyhole Markup Language, compressed.
## Installation
```
make
cd src
make install
```
## Test
@@ -32,48 +58,60 @@ make
## Parameters
```
Version: Signal Server 3.05 (Built for 100 DEM tiles at 1200 pixels)
Version: Signal Server 3.20 (Built for 100 DEM tiles at 1200 pixels)
License: GNU General Public License (GPL) version 2
Radio propagation simulator by Alex Farrant QCVS, 2E0TDW
Based upon SPLAT! by John Magliacane, KD2BD
Some feature enhancements/additions by Aaron A. Collins, N9OZB
Usage: signalserver [data options] [input options] [output options] -o outputfile
Usage: signalserver [data options] [input options] [antenna options] [output options] -o outputfile
Data:
-sdf Directory containing SRTM derived .sdf DEM tiles
-sdf Directory containing SRTM derived .sdf DEM tiles (may be .gz or .bz2)
-lid ASCII grid tile (LIDAR) with dimensions and resolution defined in header
-udt User defined point clutter as decimal co-ordinates: 'latitude,longitude,height'
-clt MODIS 17-class wide area clutter in ASCII grid format
-color File to pre-load .scf/.lcf/.dcf for Signal/Loss/dBm color palette
Input:
-lat Tx Latitude (decimal degrees) -70/+70
-lon Tx Longitude (decimal degrees) -180/+180
-txh Tx Height (above ground)
-rla (Optional) Rx Latitude for PPA (decimal degrees) -70/+70
-rlo (Optional) Rx Longitude for PPA (decimal degrees) -180/+180
-f Tx Frequency (MHz) 20MHz to 100GHz (LOS after 20GHz)
-erp Tx Effective Radiated Power (Watts) including Tx+Rx gain
-rxh Rx Height(s) (optional. Default=0.1)
-rxg Rx gain dBi (optional for text report)
-hp Horizontal Polarisation (default=vertical)
-erp Tx Total Effective Radiated Power in Watts (dBd) inc Tx+Rx gain. 2.14dBi = 0dBd
-gc Random ground clutter (feet/meters)
-m Metric units of measurement
-te Terrain code 1-6 (optional)
-te Terrain code 1-6 (optional - 1. Water, 2. Marsh, 3. Farmland,
4. Mountain, 5. Desert, 6. Urban
-terdic Terrain dielectric value 2-80 (optional)
-tercon Terrain conductivity 0.01-0.0001 (optional)
-cl Climate code 1-6 (optional)
-rel Reliability for ITM model 50 to 99 (optional)
-resample Resample Lidar input to specified resolution in meters (optional)
-cl Climate code 1-7 (optional - 1. Equatorial 2. Continental subtropical
3. Maritime subtropical 4. Desert 5. Continental temperate
6. Maritime temperate (Land) 7. Maritime temperate (Sea)
-rel Reliability for ITM model (% of 'time') 1 to 99 (optional, default 50%)
-conf Confidence for ITM model (% of 'situations') 1 to 99 (optional, default 50%)
-resample Reduce Lidar resolution by specified factor (2 = 50%)
Output:
-dbm Plot Rxd signal power instead of field strength
-o basename (Output file basename - required)
-dbm Plot Rxd signal power instead of field strength in dBuV/m
-rt Rx Threshold (dB / dBm / dBuV/m)
-o Filename. Required.
-R Radius (miles/kilometers)
-res Pixels per tile. 300/600/1200/3600 (Optional. LIDAR res is within the tile)
-pm Propagation model. 1: ITM, 2: LOS, 3: Hata, 4: ECC33,
5: SUI, 6: COST-Hata, 7: FSPL, 8: ITWOM, 9: Ericsson, 10: Plane earth, 11: Egli VHF/UHF
5: SUI, 6: COST-Hata, 7: FSPL, 8: ITWOM, 9: Ericsson,
10: Plane earth, 11: Egli VHF/UHF, 12: Soil
-pe Propagation model mode: 1=Urban,2=Suburban,3=Rural
-ked Knife edge diffraction (Already on for ITM)
Antenna:
-ant (antenna pattern file basename+path for .az and .el files)
-txh Tx Height (above ground)
-rxh Rx Height(s) (optional. Default=0.1)
-rxg Rx gain dBd (optional for PPA text report)
-hp Horizontal Polarisation (default=vertical)
-rot ( 0.0 - 359.0 degrees, default 0.0) Antenna Pattern Rotation
-dt ( -10.0 - 90.0 degrees, default 0.0) Antenna Downtilt
-dtdir ( 0.0 - 359.0 degrees, default 0.0) Antenna Downtilt Direction
Debugging:
-t Terrain greyscale background
-dbg Verbose debug messages
@@ -84,16 +122,20 @@ Debugging:
### REFERENCE DATA
Signal server is designed for most of the environments and climates on Planet Earth but Polar region support is limited above extreme latitudes. (Svalbard is ok).
It can run with or without terrain data and can even be used to simulate radiation of other EM emissions like light.
It can run with or without terrain data and can even be used to simulate radiation of other EM emissions like light.
#### -sdf
##### Directory containing Digital Elevation Models (DEM)
SDF formatted tiles can be created by converting SRTM tiles (30m or 90m) in HGT format with the [srtm2sdf.c](https://www.google.co.uk/search?q=srtm2sdf.c) utility from SPLAT!. At the time of writing these tiles can be obtained for free from the [USGS website](https://dds.cr.usgs.gov/srtm/).
Note these can be compressed using gzip or bzip2 if desired to save disk space and speed up loading the files. For hi-res (HD) SRTM1 (30m) data, bzip2 compresses best, and for lo-res SRTM3 (90m) data, gzip seems to achieve the best compression. Either will work fine for whichever data format and resolution is used.
#### -lid
##### WGS84 ASCII grid tile (LIDAR) with dimensions and resolution defined in header
LIDAR data can be used providing it is in ASCII grid format with WGS84 projection. Resolutions up to 25cm have been tested. 2m is recommended for a good trade off. Cellsize should be in degrees and co-ordinates must be in WGS84 decimal degrees.
To load multiple tiles use commas eg. -lid tile1.asc,tile2.asc. You can load in different resolution tiles and use -resample to set the desired resolution (limited by data limit).
```
ncols 2454
@@ -101,24 +143,27 @@ nrows 1467
xllcorner -1.475333294357
yllcorner 53.378635095801
cellsize 0.000006170864
NODATA_value 0
NODATA_value 0
0 0 0 0 0 0 0 0 0 0 0 0 0 ...
```
#### -udt
##### User defined CSV clutter file
This text file allows you to define buildings with co-ordinates and heights.
Elevations in the UDT file are evaluated and then copied into a temporary file under /tmp. Then the contents of the temp file are scanned, and if found to be unique,
are added to the ground elevations described by the digital elevation data in memory. Height units are determined by appending M for meters or nothing for feet.
Format: latitude,longitude,height
Elevations in the UDT file are evaluated and then copied into a temporary file under /tmp. Then the contents of the temp file are scanned, and if found to be unique, are added to the ground elevations described by the digital elevation data in memory. Height units are determined by appending M for meters or nothing for feet.
There is no special parsing for comments, so any lines of data that don't contain 3 numbers separated by commas are interpreted as a comment.
Format: latitude,longitude,height(M)
```
// This is a comment!
54.555,-2.221,10M
54.555,-2.222,10M
54.555,-2.223,10M
```
### Antenna radiation pattern(s)
Antenna pattern data is read from a pair of files having the same base name as the output file (-o), but with .az and .el extensions for azimuth and elevation patterns.
Antenna pattern data is read from a pair of files having the same base name as the output file (-o), but with .az and .el extensions for azimuth and elevation patterns. This name can be overridden with the command line option -ant followed by a base filename or path and base filename for the .az and .el files. The program will first search for command line specified antenna files with -ant, then it will default to searching for antenna files having the same name as the output file.
```
045.0
0 0.8950590
@@ -128,11 +173,11 @@ Format: latitude,longitude,height
4 0.9009535
5 0.9022749
```
The first line of the .az file specifies the direction measured clockwise in degrees from True North. This is followed by azimuth headings (0 to 360 degrees) and their associated normalized field patterns (0.000 to 1.000) separated by whitespace.
The first line of the .az file specifies the direction measured clockwise in degrees from True North. This is followed by azimuth headings (0 to 360 degrees) and their associated normalized field patterns (0.000 to 1.000) separated by whitespace. This direction can be overridden by the command line option -rot followed by a positive direction value from 0 to 360 degrees. This value will override any direction specified in the first line of the .az file. If not specified on the command line, the program will default to using the direction from the first line of the .az file.
The structure of SPLAT! elevation pattern files is slightly different. The first line of the .el file specifies the amount of mechanical beamtilt applied to the antenna. A downward tilt is expressed as a positive angle, while an upward tilt is expressed as a negative angle. This data is followed by the azimuthal direction of the tilt, separated by whitespace.
The remainder of the file consists of elevation angles and their radiation pattern (0.000 to 1.000) values separated by whitespace. Elevation angles must be specified over a -10.0 to +90.0 degree range. In this example, the antenna is tilted down 2
degrees towards an azimuth of 045.0 degrees.
The structure of SPLAT! elevation pattern files is slightly different. The first line of the .el file specifies the amount of mechanical beamtilt applied to the antenna. A downward tilt is expressed as a positive angle, while an upward tilt is expressed as a negative angle. This data is followed by the azimuthal direction of the tilt, 0 to 360 degrees, separated by whitespace. These can be overridden by the command line options -dt for downtilt and -dtdir for downtilt azimuthal direction. The options, like -rot above, will override any values embedded in the .el file if specified on the command line.
The remainder of the file consists of elevation angles and their radiation pattern (0.000 to 1.000) values separated by whitespace. Elevation angles must be specified over a -10.0 to +90.0 degree range. In this example, the antenna is tilted down 2 degrees towards an azimuth of 045.0 degrees.
```
2.0 045.0
-10.0 0.172
@@ -163,3 +208,11 @@ degrees towards an azimuth of 045.0 degrees.
```
./signalserverLIDAR -lid /data/LIDAR/Gloucester_2m.asc -lat 51.849 -lon -2.2299 -txh 15 -f 1800 -erp 1 -rxh 2 -rt -90 -dbm -m -o test3 -R 1 -pm 1
```
### Scripting
By using wrapper scripts like runsig.sh and genkmz.sh, you can streamline running signalserver by pre-setting some commonly used options in the runsig.sh file. Those options should the be ones you use every time you run signalserver, like "-m" for metric or "-sdf ./sdf_file_path", for example, so you won't have to specify those options every time you run it. The genkmz.sh file will convert the output ppm file into a .png with transparent background, then will convert it to a Google Earth Keyhole Markup Language (KML) file, and then it compresses it for size to a (KMZ) file. For example, using the provided sample runsig.sh and genkmz.sh:
### Plot 70cm Service contour, 700W ERP, 300 feet AGL, DB413-B, to 150 mi:
sudo ./runsig.sh -lat 42.428889 -lon -87.812500 -txh 300 -f 446.000 -erp 700 -R 150 -res 600 -rel 50 -rt 39 -ant antenna/DB413-B -rot 225 -color color/blue -o example-service | ./genkmz.sh
### Plot 70cm Interference contour, 700W ERP, 300 feet AGL, DB413-B, to 150 mi:
sudo ./runsig.sh -lat 42.428889 -lon -87.812500 -txh 300 -f 446.000 -erp 700 -R 150 -res 600 -rel 10 -rt 21 -ant antenna/DB413-B -rot 225 -color color/blue -o example-service | ./genkmz.sh

BIN
SignalServer_Manual.odt Normal file

Binary file not shown.

720
antenna/DB413-B.ant Normal file
View File

@@ -0,0 +1,720 @@
0
0
0
0
0
0
0
0
0
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
-0.2
-0.2
-0.2
-0.2
-0.2
-0.3
-0.3
-0.3
-0.3
-0.4
-0.4
-0.4
-0.5
-0.5
-0.5
-0.6
-0.6
-0.6
-0.7
-0.7
-0.8
-0.8
-0.8
-0.9
-0.9
-1
-1
-1.1
-1.1
-1.2
-1.2
-1.3
-1.4
-1.4
-1.5
-1.5
-1.6
-1.6
-1.7
-1.8
-1.9
-1.9
-2
-2.1
-2.1
-2.2
-2.3
-2.4
-2.5
-2.5
-2.6
-2.7
-2.8
-2.9
-3
-3
-3.1
-3.2
-3.3
-3.4
-3.5
-3.6
-3.7
-3.8
-3.9
-4
-4.1
-4.3
-4.4
-4.5
-4.6
-4.7
-4.8
-4.9
-5
-5.2
-5.3
-5.4
-5.5
-5.6
-5.8
-5.9
-6
-6.1
-6.2
-6.4
-6.5
-6.6
-6.7
-6.8
-7
-7.1
-7.2
-7.3
-7.4
-7.6
-7.7
-7.8
-7.9
-8
-8.1
-8.2
-8.3
-8.4
-8.5
-8.6
-8.7
-8.8
-8.9
-8.9
-9
-9.1
-9.2
-9.2
-9.3
-9.3
-9.4
-9.4
-9.5
-9.5
-9.6
-9.6
-9.6
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.8
-9.8
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.5
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.6
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.8
-9.8
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.7
-9.6
-9.6
-9.6
-9.5
-9.5
-9.4
-9.4
-9.3
-9.3
-9.2
-9.2
-9.1
-9
-8.9
-8.9
-8.8
-8.7
-8.6
-8.5
-8.4
-8.3
-8.2
-8.1
-8
-7.9
-7.8
-7.7
-7.6
-7.4
-7.3
-7.2
-7.1
-7
-6.8
-6.7
-6.6
-6.5
-6.4
-6.2
-6.1
-6
-5.9
-5.8
-5.6
-5.5
-5.4
-5.3
-5.2
-5
-4.9
-4.8
-4.7
-4.6
-4.5
-4.4
-4.3
-4.1
-4
-3.9
-3.8
-3.7
-3.6
-3.5
-3.4
-3.3
-3.2
-3.1
-3
-3
-2.9
-2.8
-2.7
-2.6
-2.5
-2.5
-2.4
-2.3
-2.2
-2.1
-2.1
-2
-1.9
-1.9
-1.8
-1.7
-1.6
-1.6
-1.5
-1.5
-1.4
-1.4
-1.3
-1.2
-1.2
-1.1
-1.1
-1
-1
-0.9
-0.9
-0.8
-0.8
-0.8
-0.7
-0.7
-0.6
-0.6
-0.6
-0.5
-0.5
-0.5
-0.4
-0.4
-0.4
-0.3
-0.3
-0.3
-0.3
-0.2
-0.2
-0.2
-0.2
-0.2
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
-0.1
0
0
0
0
0
0
0
0
-40
-32.8
-26.7
-23.1
-20.6
-18.6
-17
-15.6
-14.4
-13.4
-12.5
-11.7
-11
-10.5
-10
-9.6
-9.3
-9.1
-9.1
-9.1
-9.4
-9.7
-10.3
-11.2
-12.3
-13.8
-15.8
-18.4
-21.8
-23.9
-21.9
-19
-16.8
-15.3
-14.5
-14.2
-14.4
-15.2
-16.7
-19.2
-23
-27.9
-26.5
-22.2
-19.5
-18.2
-17.8
-18.3
-19.8
-22.5
-26.7
-28.3
-24.4
-21.3
-19.7
-19.2
-19.7
-21.3
-24.2
-27.9
-27.1
-23.4
-21
-19.8
-19.8
-20.9
-23.4
-27.4
-27.8
-23.2
-20.1
-18.4
-18.1
-19.1
-22.2
-28.2
-24.9
-18.8
-15.5
-14
-14
-15.9
-22
-23.5
-13.2
-8
-4.7
-2.5
-1
-0.2
0
-0.3
-1.3
-2.9
-5.4
-9.3
-16
-40
-18.5
-14.4
-13.3
-13.9
-16.1
-20.2
-26.7
-25.3
-21
-19.1
-18.9
-19.9
-21.9
-24.6
-26.4
-25.4
-23.5
-22.2
-21.5
-21.4
-22.1
-23.6
-26.1
-28.5
-27.2
-24.1
-21.9
-20.8
-20.7
-21.8
-24.4
-29.8
-34.8
-26.9
-22.5
-20.1
-19
-18.9
-19.7
-21.7
-25.5
-34.3
-34.3
-25.4
-21.5
-19.5
-18.4
-18.2
-18.8
-20.2
-23
-28.5
-37.7
-26.2
-20.7
-17.4
-15
-13.4
-12.1
-11.2
-10.6
-10.1
-9.8
-9.7
-9.7
-9.9
-10.1
-10.5
-10.9
-11.5
-12.1
-12.8
-13.6
-14.6
-15.6
-16.8
-18.2
-19.8
-21.8
-24.4
-27.9
-34
-40
-34
-28
-24.5
-22
-20
-18.4
-17.1
-15.9
-14.9
-14
-13.2
-12.5
-11.9
-11.4
-11
-10.7
-10.5
-10.4
-10.4
-10.6
-10.9
-11.4
-12.1
-13.1
-14.4
-16.1
-18.5
-21.8
-26.7
-30.3
-26
-22.3
-20
-18.7
-18.1
-18.1
-18.8
-19.9
-21.6
-23.4
-24.1
-23.2
-21.8
-20.7
-20.3
-20.6
-21.6
-23.5
-25.8
-27
-25.6
-23.7
-22.5
-22.3
-22.9
-24.5
-26.8
-28.1
-26.8
-25
-23.9
-23.8
-24.7
-26.4
-28.2
-28.2
-26.8
-25.5
-25.1
-25.6
-26.8
-28.3
-29.4
-29.4
-28.9
-28.3
-28.1
-28.2
-28.5
-28.3
-26
-22.2
-18.5
-15.4
-12.9
-11
-9.6
-8.6
-8.1
-8
-8.5
-9.5
-11.3
-14.2
-18.6
-23.7
-21.2
-17.8
-16.3
-16.3
-17.8
-21.1
-28.5
-37.9
-25.4
-22
-21.3
-22.5
-25.9
-33.8
-32.2
-25.9
-23.3
-22.8
-23.9
-26.8
-31.4
-30.7
-26.6
-24.3
-23.5
-24
-25.6
-27.9
-28.7
-27.1
-25.3
-24.2
-24.1
-24.5
-25.2
-25.4
-24.8
-23.8
-23.1
-22.9
-23.3
-24.3
-25.4
-25.5
-24
-21.9
-20.1
-18.8
-17.9
-17.6
-17.6
-17.9
-18.5
-19
-19.2
-18.7
-17.6
-16.3
-15
-13.8
-12.8
-12.1
-11.5
-11
-10.8
-10.6
-10.6
-10.7
-10.9
-11.2
-11.6
-12.1
-12.7
-13.4
-14.2
-15.1
-16.2
-17.5
-19
-20.9
-23.4
-26.9
-32.8

361
antenna/DB413-B.az Normal file
View File

@@ -0,0 +1,361 @@
0
0 1.0000
1 1.0000
2 1.0000
3 1.0000
4 1.0000
5 1.0000
6 1.0000
7 1.0000
8 1.0000
9 0.9772
10 0.9772
11 0.9772
12 0.9772
13 0.9772
14 0.9772
15 0.9772
16 0.9772
17 0.9550
18 0.9550
19 0.9550
20 0.9550
21 0.9550
22 0.9333
23 0.9333
24 0.9333
25 0.9333
26 0.9120
27 0.9120
28 0.9120
29 0.8913
30 0.8913
31 0.8913
32 0.8710
33 0.8710
34 0.8710
35 0.8511
36 0.8511
37 0.8318
38 0.8318
39 0.8318
40 0.8128
41 0.8128
42 0.7943
43 0.7943
44 0.7762
45 0.7762
46 0.7586
47 0.7586
48 0.7413
49 0.7244
50 0.7244
51 0.7079
52 0.7079
53 0.6918
54 0.6918
55 0.6761
56 0.6607
57 0.6457
58 0.6457
59 0.6310
60 0.6166
61 0.6166
62 0.6026
63 0.5888
64 0.5754
65 0.5623
66 0.5623
67 0.5495
68 0.5370
69 0.5248
70 0.5129
71 0.5012
72 0.5012
73 0.4898
74 0.4786
75 0.4677
76 0.4571
77 0.4467
78 0.4365
79 0.4266
80 0.4169
81 0.4074
82 0.3981
83 0.3890
84 0.3715
85 0.3631
86 0.3548
87 0.3467
88 0.3388
89 0.3311
90 0.3236
91 0.3162
92 0.3020
93 0.2951
94 0.2884
95 0.2818
96 0.2754
97 0.2630
98 0.2570
99 0.2512
100 0.2455
101 0.2399
102 0.2291
103 0.2239
104 0.2188
105 0.2138
106 0.2089
107 0.1995
108 0.1950
109 0.1905
110 0.1862
111 0.1820
112 0.1738
113 0.1698
114 0.1660
115 0.1622
116 0.1585
117 0.1549
118 0.1514
119 0.1479
120 0.1445
121 0.1413
122 0.1380
123 0.1349
124 0.1318
125 0.1288
126 0.1288
127 0.1259
128 0.1230
129 0.1202
130 0.1202
131 0.1175
132 0.1175
133 0.1148
134 0.1148
135 0.1122
136 0.1122
137 0.1096
138 0.1096
139 0.1096
140 0.1072
141 0.1072
142 0.1072
143 0.1072
144 0.1072
145 0.1072
146 0.1072
147 0.1072
148 0.1047
149 0.1047
150 0.1072
151 0.1072
152 0.1072
153 0.1072
154 0.1072
155 0.1072
156 0.1072
157 0.1072
158 0.1072
159 0.1072
160 0.1072
161 0.1096
162 0.1096
163 0.1096
164 0.1096
165 0.1096
166 0.1096
167 0.1096
168 0.1096
169 0.1122
170 0.1122
171 0.1122
172 0.1122
173 0.1122
174 0.1122
175 0.1122
176 0.1122
177 0.1122
178 0.1122
179 0.1122
180 0.1122
181 0.1122
182 0.1122
183 0.1122
184 0.1122
185 0.1122
186 0.1122
187 0.1122
188 0.1122
189 0.1122
190 0.1122
191 0.1122
192 0.1096
193 0.1096
194 0.1096
195 0.1096
196 0.1096
197 0.1096
198 0.1096
199 0.1096
200 0.1072
201 0.1072
202 0.1072
203 0.1072
204 0.1072
205 0.1072
206 0.1072
207 0.1072
208 0.1072
209 0.1072
210 0.1072
211 0.1047
212 0.1047
213 0.1072
214 0.1072
215 0.1072
216 0.1072
217 0.1072
218 0.1072
219 0.1072
220 0.1072
221 0.1096
222 0.1096
223 0.1096
224 0.1122
225 0.1122
226 0.1148
227 0.1148
228 0.1175
229 0.1175
230 0.1202
231 0.1202
232 0.1230
233 0.1259
234 0.1288
235 0.1288
236 0.1318
237 0.1349
238 0.1380
239 0.1413
240 0.1445
241 0.1479
242 0.1514
243 0.1549
244 0.1585
245 0.1622
246 0.1660
247 0.1698
248 0.1738
249 0.1820
250 0.1862
251 0.1905
252 0.1950
253 0.1995
254 0.2089
255 0.2138
256 0.2188
257 0.2239
258 0.2291
259 0.2399
260 0.2455
261 0.2512
262 0.2570
263 0.2630
264 0.2754
265 0.2818
266 0.2884
267 0.2951
268 0.3020
269 0.3162
270 0.3236
271 0.3311
272 0.3388
273 0.3467
274 0.3548
275 0.3631
276 0.3715
277 0.3890
278 0.3981
279 0.4074
280 0.4169
281 0.4266
282 0.4365
283 0.4467
284 0.4571
285 0.4677
286 0.4786
287 0.4898
288 0.5012
289 0.5012
290 0.5129
291 0.5248
292 0.5370
293 0.5495
294 0.5623
295 0.5623
296 0.5754
297 0.5888
298 0.6026
299 0.6166
300 0.6166
301 0.6310
302 0.6457
303 0.6457
304 0.6607
305 0.6761
306 0.6918
307 0.6918
308 0.7079
309 0.7079
310 0.7244
311 0.7244
312 0.7413
313 0.7586
314 0.7586
315 0.7762
316 0.7762
317 0.7943
318 0.7943
319 0.8128
320 0.8128
321 0.8318
322 0.8318
323 0.8318
324 0.8511
325 0.8511
326 0.8710
327 0.8710
328 0.8710
329 0.8913
330 0.8913
331 0.8913
332 0.9120
333 0.9120
334 0.9120
335 0.9333
336 0.9333
337 0.9333
338 0.9333
339 0.9550
340 0.9550
341 0.9550
342 0.9550
343 0.9550
344 0.9772
345 0.9772
346 0.9772
347 0.9772
348 0.9772
349 0.9772
350 0.9772
351 0.9772
352 1.0000
353 1.0000
354 1.0000
355 1.0000
356 1.0000
357 1.0000
358 1.0000
359 1.0000

102
antenna/DB413-B.el Normal file
View File

@@ -0,0 +1,102 @@
0 0
-10 0.0398
-9 0.0257
-8 0.0063
-7 0.0045
-6 0.0479
-5 0.1585
-4 0.3388
-3 0.5623
-2 0.7943
-1 0.9550
0 1.0000
1 0.9333
2 0.7413
3 0.5129
4 0.2884
5 0.1175
6 0.0251
7 0.0001
8 0.0141
9 0.0363
10 0.0468
11 0.0407
12 0.0245
13 0.0095
14 0.0021
15 0.0030
16 0.0079
17 0.0123
18 0.0129
19 0.0102
20 0.0065
21 0.0035
22 0.0023
23 0.0029
24 0.0045
25 0.0060
26 0.0071
27 0.0072
28 0.0062
29 0.0044
30 0.0025
31 0.0014
32 0.0019
33 0.0039
34 0.0065
35 0.0083
36 0.0085
37 0.0066
38 0.0036
39 0.0010
40 0.0003
41 0.0020
42 0.0056
43 0.0098
44 0.0126
45 0.0129
46 0.0107
47 0.0068
48 0.0028
49 0.0004
50 0.0004
51 0.0029
52 0.0071
53 0.0112
54 0.0145
55 0.0151
56 0.0132
57 0.0095
58 0.0050
59 0.0014
60 0.0002
61 0.0024
62 0.0085
63 0.0182
64 0.0316
65 0.0457
66 0.0617
67 0.0759
68 0.0871
69 0.0977
70 0.1047
71 0.1072
72 0.1072
73 0.1023
74 0.0977
75 0.0891
76 0.0813
77 0.0708
78 0.0617
79 0.0525
80 0.0437
81 0.0347
82 0.0275
83 0.0209
84 0.0151
85 0.0105
86 0.0066
87 0.0036
88 0.0016
89 0.0004
90 0.0001

3
color/black.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 0, 0, 0
0: 0, 0, 0

3
color/blue.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 0, 0, 255
0: 0, 0, 255

3
color/cyan.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 0, 255, 255
0: 0, 255, 255

3
color/green.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 0, 255, 0
0: 0, 255, 0

3
color/magenta.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 255, 0, 255
0: 255, 0, 255

16
color/rainbow.dcf Normal file
View File

@@ -0,0 +1,16 @@
+0: 255, 0, 0
-10: 255, 128, 0
-20: 255, 165, 0
-30: 255, 206, 0
-40: 255, 255, 0
-50: 184, 255, 0
-60: 0, 255, 0
-70: 0, 208, 0
-80: 0, 196, 196
-90: 0, 148, 255
-100: 80, 80, 255
-110: 0, 38, 255
-120: 142, 63, 255
-130: 196, 54, 255
-140: 255, 0, 255
-150: 255, 194, 204

13
color/rainbow.scf Normal file
View File

@@ -0,0 +1,13 @@
128: 255, 0, 0
118: 255, 165, 0
108: 255, 206, 0
98: 255, 255, 0
88: 184, 255, 0
78: 0, 255, 0
68: 0, 208, 0
58: 0, 196, 196
48: 0, 148, 255
38: 80, 80, 255
28: 0, 38, 255
18: 142, 63, 255
8: 140, 0, 128

3
color/red.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 255, 0, 0
0: 255, 0, 0

3
color/yellow.scf Normal file
View File

@@ -0,0 +1,3 @@
200: 255, 255, 255
59: 255, 255, 0
0: 255, 255, 0

0
data/51:52:0:1-hd.sdf Executable file → Normal file
View File

0
data/51:52:0:1.sdf Executable file → Normal file
View File

File diff suppressed because one or more lines are too long

11
data/test.udt Normal file
View File

@@ -0,0 +1,11 @@
// Put a giant 5000 foot wall in the middle of Lake Michigan near Chicago!
42.280056,-87.772222,5000
42.281056,-87.772222,5000
42.282056,-87.772222,5000
42.283056,-87.772222,5000
42.284056,-87.772222,5000
42.285056,-87.772222,5000
42.286056,-87.772222,5000
42.287056,-87.772222,5000
42.288056,-87.772222,5000
42.289056,-87.772222,5000

42
genkmz.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
while read line
do
echo $line
if [[ $line == Writing* ]]
then
while IFS='"' read -ra writingline
do
# echo "writingline: ${writingline}"
filename=${writingline[1]%.*}
# echo "filename: ${filename}"
done <<< $line
fi
if [[ $line == \|* ]]
then
while IFS='|' read -ra coords
do
cat << EOF > doc.kml
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<GroundOverlay>
<name>${filename}</name>
<Icon>
<href>${filename}.png</href>
</Icon>
<LatLonBox>
<north>${coords[1]}</north>
<east>${coords[2]}</east>
<south>${coords[3]}</south>
<west>${coords[4]}</west>
</LatLonBox>
</GroundOverlay>
</kml>
EOF
done <<< $line
fi
done
#echo "filename: ${filename}"
zip "${filename}" "${filename}.png" "doc.kml"
mv "${filename}".zip "${filename}".kmz
rm "doc.kml"
echo Generated "${filename}".kmz

18
runsig.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
set -e
if [[ $# -eq 0 ]] ; then
echo Usage:
echo $0 -lat 46.4879 -lon -123.2144 -txh 60 -f 145 -erp 30 -R 80 -o outfile | ./genkmz.sh
echo The last argument must be the output file name.
exit 1
fi
for name; do true; done
# This script should contain options common to every run on the target system.
#time ./signalserverHD -sdf /mnt/data -pm 1 -rxh 6 -te 3 -cl 5 -pe 2 -dbg $@ 2>&1
time ./signalserver -sdf /mnt/data -pm 1 -rxh 6 -te 3 -cl 5 -pe 2 -dbg $@ 2>&1
# to resize, add: -resize 7000x7000\>
convert $name.ppm -transparent white $name.png

77
src/Makefile Normal file
View File

@@ -0,0 +1,77 @@
SHELL = /bin/sh
CC = gcc
CXX = g++
CFLAGS = -Wall -O3 -s -ffast-math -DCROPPING
CXXFLAGS = -Wall -O3 -s -ffast-math
LIBS = -lm -lpthread -ldl -lbz2 -lz
INSTALL_PATH = ..
VPATH = models
objects = main.o cost.o ecc33.o ericsson.o fspl.o hata.o itwom3.0.o \
los.o sui.o pel.o egli.o soil.o inputs.o outputs.o image.o \
image-ppm.o tiles.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
@echo -e " SYMLNK\tsignalserverLIDAR -> $@"
@ln -sf $@ signalserverLIDAR
main.o: main.cc common.h inputs.hh outputs.hh itwom3.0.hh los.hh pel.hh \
image.hh
inputs.o: inputs.cc common.h main.hh tiles.hh
outputs.o: outputs.cc common.h main.hh inputs.hh cost.hh ecc33.hh ericsson.hh \
fspl.hh hata.hh itwom3.0.hh sui.hh image.hh
image.o: image.cc image-ppm.o image.hh image-ppm.hh
image-ppm.o: image-ppm.cc image.hh
los.o: los.cc los.hh main.hh cost.hh ecc33.hh ericsson.hh fspl.hh hata.hh \
itwom3.0.hh sui.hh pel.hh egli.hh soil.hh
tiles.o: tiles.cc tiles.hh common.h
testmodels.o: testmodels.cc cost.hh ecc33.hh ericsson.hh fspl.hh hata.hh \
egli.hh sui.hh itwom3.0.hh
testmodels: testmodels.o cost.o ecc33.o ericsson.o fspl.o hata.o egli.o sui.o itwom3.0.o
@echo -e " LNK\t$@"
@$(CXX) testmodels.o cost.o ecc33.o ericsson.o fspl.o hata.o egli.o \
sui.o itwom3.0.o -o $@ ${LIBS}
.PHONY: clean
clean:
rm -f $(objects) signalserver signalserverHD signalserverLIDAR testmodels
all: signalserver
install: all
cp -a signalserver signalserverHD signalserverLIDAR $(INSTALL_PATH)

131
src/common.h Normal file
View File

@@ -0,0 +1,131 @@
#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 FEET_PER_MILE 5280.0
#define FOUR_THIRDS 1.3333333333333
#define MAX(x,y)((x)>(y)?(x):(y))
struct dem {
float min_north;
float max_north;
float min_west;
float 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 double min_north;
extern double max_north;
extern double min_west;
extern double max_west;
extern int ippd;
extern int MAXRAD;
extern int mpi;
extern int max_elevation;
extern int min_elevation;
extern int contour_threshold;
extern int loops;
extern int jgets;
extern int width;
extern int height;
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 yppd;
extern double fzone_clearance;
extern double clutter;
extern double dBm;
extern double loss;
extern double field_strength;
extern __thread double *elev;
extern double westoffset;
extern double eastoffset;
extern double delta;
extern double cropLat;
extern double cropLon;
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 __thread struct path path;
extern struct LR LR;
extern struct region region;
extern int debug;
#endif /* _COMMON_H_ */

59
src/image-ppm.cc Normal file
View File

@@ -0,0 +1,59 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include "image.hh"
int ppm_init(image_ctx_t *ctx){
size_t buf_size;
/* Perform simple sanity checking */
if(ctx->canvas != NULL)
return EINVAL;
ctx->model = IMAGE_RGB; //Override this as we only support RGB
ctx->format = IMAGE_PPM;
ctx->extension = (char*)".ppm";
buf_size = ctx->width * ctx->height * RGB_SIZE;
/* Allocate the canvas buffer */
ctx->canvas = (uint8_t*) calloc(buf_size,sizeof(uint8_t));
ctx->next_pixel = ctx->canvas;
if(ctx->canvas == NULL)
return ENOMEM;
return 0;
}
int ppm_add_pixel(image_ctx_t *ctx,const uint8_t r,const uint8_t g,const uint8_t b,const uint8_t a){
register uint8_t* next;
next = ctx->next_pixel;
next[0] = r;
next[1] = g;
next[2] = b;
ctx->next_pixel += 3;
return 0;
}
int ppm_get_pixel(image_ctx_t *ctx,const size_t x,const size_t y,const uint8_t *r,const uint8_t *g,const uint8_t *b,const uint8_t *a){
/* STUB */
return 0;
}
int ppm_write(image_ctx_t *ctx, FILE* fd){
size_t written;
size_t count;
count = ctx->width * ctx->height * RGB_SIZE;
fprintf(fd, "P6\n%zu %zu\n255\n", ctx->width, ctx->height);
written = fwrite(ctx->canvas,sizeof(uint8_t),count,fd);
if(written < count)
return EPIPE;
return 0;
}

23
src/image-ppm.hh Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _IMAGE_PPM_HH
#define _IMAGE_PPM_HH
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "image.hh"
int ppm_init(image_ctx_t *ctx);
int ppm_add_pixel(image_ctx_t *ctx,const uint8_t r,const uint8_t g,const uint8_t b,const uint8_t a);
int ppm_get_pixel(image_ctx_t *ctx,const size_t x,const size_t y,const uint8_t *r,const uint8_t *g,const uint8_t *b,const uint8_t *a);
int ppm_write(image_ctx_t *ctx, FILE* fd);
image_dispatch_table_t ppm_dt = {\
.init = ppm_init, \
.add_pixel = ppm_add_pixel, \
.set_pixel = NULL, \
.get_pixel = ppm_get_pixel, \
.write = ppm_write, \
.free = NULL
};
#endif

275
src/image.cc Normal file
View File

@@ -0,0 +1,275 @@
/*
* Generic image output handling. This feature allows
* for extensible image output formats and permits for
* cleaner image rendering code in the model generation
* routines by moving all of the file-format specific
* logic to be handled here.
*/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <dlfcn.h>
#include "image.hh"
#include "image-ppm.hh"
int get_dt(image_dispatch_table_t *dt, int format);
int load_library(image_dispatch_table_t *dt);
#define DISPATCH_TABLE(ctx) ((image_dispatch_table_t*)(ctx)->_dt)
static int default_format = IMAGE_PPM;
char *dynamic_backend = NULL;
/*
* image_set_format
* Changes the default format for the next
* uninitialized image canvas
*/
int image_set_format(int format){
if(format <= IMAGE_DEFAULT || format >= IMAGE_FORMAT_MAX)
return EINVAL;
default_format = format;
return 0;
}
/*
* image_init
* Initialize an image context. Must be called
* before attempting to write any image data
*/
int image_init(image_ctx_t *ctx, \
const size_t width, \
const size_t height, \
const int model, \
const int format) {
int success = 0;
image_dispatch_table_t *dt;
/* Perform some sanity checking on provided arguments */
if(ctx == NULL)
return EINVAL;
if(width == 0 || height == 0)
return EINVAL;
if(model < 0 || model > IMAGE_MODEL_MAX)
return EINVAL;
if(format >= IMAGE_FORMAT_MAX || (format == IMAGE_LIBRARY && dynamic_backend == NULL))
return EINVAL;
memset(ctx,0x00,sizeof(image_ctx_t));
/* Assign the initialize values to the processing context */
ctx->width = width;
ctx->height = height;
ctx->model = model;
if(format == IMAGE_DEFAULT)
ctx->format = default_format;
else
ctx->format = format;
/* Get the dispatch table for this image format */
dt = (image_dispatch_table_t *) calloc(1,sizeof(image_dispatch_table_t));
if(dt == NULL){
fprintf(stderr,"Error allocating dispatch table\n");
return ENOMEM;
}
success = get_dt(dt,ctx->format);
if(success != 0){
fprintf(stderr,"Error locating dispatch table\n");
free(dt);
return success;
}
ctx->_dt = (void*)dt;
/* Call the format-specific initialization function */
success = dt->init(ctx);
if(success != 0){
fprintf(stderr,"Error initializing image context\n");
free(dt);
return success;
}
ctx->initialized = 1;
return success;
}
/*
* image_add_pixel, image_set_pixel, image_get_pixel, image_write, image_free
* Various setters ad getters for assigning pixel data. image_write
* takes an open file handle and writes image data to it.
* These functions simply wrap the underlying format-specific functions
*/
int image_add_pixel(image_ctx_t *ctx, const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a){
if(ctx->initialized != 1) return EINVAL;
return DISPATCH_TABLE(ctx)->add_pixel(ctx,r,g,b,a);
}
int image_set_pixel(image_ctx_t *ctx, const size_t x, const size_t y, const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a){
size_t block_size;
if(ctx->initialized != 1) return EINVAL;
/* Image format handlers have the option to specify a _set_pixel handler */
if(DISPATCH_TABLE(ctx)->set_pixel != NULL){
return DISPATCH_TABLE(ctx)->set_pixel(ctx,x,y,r,g,b,a);
}
block_size = ctx->model == IMAGE_RGB ? RGB_SIZE : RGBA_SIZE;
ctx->next_pixel = ctx->canvas + PIXEL_OFFSET(x,y,ctx->width,block_size);
return DISPATCH_TABLE(ctx)->add_pixel(ctx,r,g,b,a);
}
int image_get_pixel(image_ctx_t *ctx, const size_t x, const size_t y, const uint8_t *r, const uint8_t *g, const uint8_t *b, const uint8_t *a){
if(ctx->initialized != 1) return EINVAL;
if(DISPATCH_TABLE(ctx)->get_pixel != NULL)
return DISPATCH_TABLE(ctx)->get_pixel(ctx,x,y,r,g,b,a);
return ENOSYS;
}
int image_write(image_ctx_t *ctx, FILE *fd){
if(ctx->initialized != 1) return EINVAL;
return DISPATCH_TABLE(ctx)->write(ctx,fd);
}
void image_free(image_ctx_t *ctx){
if(ctx->initialized != 1) return;
if(DISPATCH_TABLE(ctx)->free != NULL){
DISPATCH_TABLE(ctx)->free(ctx);
}
if(ctx->canvas != NULL) free(ctx->canvas);
}
/*
* image_get_filename
* Creates an appropriate file name using data supplied
* by the user. If the extension is already correct, return
* that; if not append if there is space
*/
int image_get_filename(image_ctx_t *ctx, char *out, size_t len_out, char *in){
size_t len_src;
size_t len_ext;
int success = 0;
if(ctx->initialized != 1)
return EINVAL;
/* Get various lengths */
len_src = strlen(in);
len_ext = strlen(ctx->extension);
if(len_src == 0){
in = (char*)"output";
len_src = 6;
}
if(len_src > len_ext && strcmp(in+len_src-len_ext,ctx->extension) == 0){
/* Already has correct extension and fits in buffer */
if(len_src < len_out)
strncpy(in,out,len_out);
else
success = ENOMEM;
}else if(len_src > len_ext){
/* Doesn't have correct extension and fits */
if(len_src + len_ext < len_out){
strncpy(out,in,len_out);
strncat(out,ctx->extension,len_out);
}else
success = ENOMEM;
}else{
/* The input buffer plus an extension cannot fit in the output buffer */
fprintf(stderr,"Error building image output filename\n");
success = ENOMEM;
}
return success;
}
/*
* get_dt
* Load the dispatch table for the specified image
* format. Currently only pixmap supported.
*/
int get_dt(image_dispatch_table_t *dt, int format){
int success = 0;
memset((void*)dt,0x00,sizeof(image_dispatch_table_t));
switch(format){
case IMAGE_PPM:
*dt = ppm_dt;
break;
case IMAGE_LIBRARY:
success = load_library(dt);
break;
default:
success = EINVAL;
}
return success;
}
/*
* ==WARNING==: Here be dragons!
* Experimantal features beyond this point.
* Only use if you are sure you know what you
* are doing!
*/
/*
* image_set_library
* Set the library to use for generating images
*/
int image_set_library(char *library){
char *libname;
size_t length;
length = strlen(library) + 1;
libname = (char*)calloc(length,sizeof(char));
if(libname == NULL)
return ENOMEM;
strncpy(libname,library,length);
dynamic_backend = libname;
default_format = IMAGE_LIBRARY;
return 0;
}
/*
* image_get_library
* Returns the current saved image rendering
* library
*/
char* image_get_library(){
return dynamic_backend;
}
/*
* load_library
* External image processing: experimental feature
* Load an external library to perform image processing
* It must be a custom compatible library
*/
int load_library(image_dispatch_table_t *dt){
void *hndl;
int success = 0;
/* Validate object file */
if(dynamic_backend == NULL || strlen(dynamic_backend) == 0){
fprintf(stderr,"Custom image processor requested without specification\n");
return EINVAL;
}
/* Load shared object and locate required exports */
hndl = dlopen(dynamic_backend,RTLD_LAZY);
if(hndl == NULL){
fprintf(stderr,"Error loading shared object\n");
return EINVAL;
}
/* Perform symbol lookup */
if((dt->init = (_init*)dlsym(hndl,"lib_init")) == NULL ||
(dt->add_pixel = (_add_pixel*)dlsym(hndl,"lib_add_pixel")) == NULL ||
(dt->write = (_write*)dlsym(hndl,"lib_write")) == NULL){
fprintf(stderr,"Invalid image processing module specified\n\t%s",dlerror());
success = EINVAL;
(void) dlclose(hndl);
}
/* Lookup optional symbols, these can return NULL */
if(success == 0){
dt->get_pixel = (_get_pixel*)dlsym(hndl,"lib_get_pixel");
dt->set_pixel = (_set_pixel*)dlsym(hndl,"lib_set_pixel");
dt->free = (_free*)dlsym(hndl,"lib_free");
}
return success;
}

63
src/image.hh Normal file
View File

@@ -0,0 +1,63 @@
#ifndef _IMAGE_HH_
#define _IMAGE_HH_
#include <stdint.h>
#define RGB_SIZE 3
#define RGBA_SIZE 4
enum _image_format{ IMAGE_DEFAULT = 0, \
IMAGE_PPM, \
IMAGE_LIBRARY, \
IMAGE_FORMAT_MAX \
};
enum _image_model{ IMAGE_RGB, \
IMAGE_RGBA, \
IMAGE_MODEL_MAX
};
typedef struct _image_ctx{
size_t width;
size_t height;
int model;
int format;
uint8_t *canvas;
uint8_t *next_pixel;
uint32_t initialized;
char *extension;
void *_dt;
} image_ctx_t, *pimage_ctx_t;
typedef int _init(image_ctx_t*);
typedef int _add_pixel(image_ctx_t*,const uint8_t,const uint8_t,const uint8_t,const uint8_t);
typedef int _set_pixel(image_ctx_t*,const size_t,const size_t,const uint8_t,const uint8_t,const uint8_t,const uint8_t);
typedef int _get_pixel(image_ctx_t*,const size_t,const size_t,const uint8_t*,const uint8_t*,const uint8_t*,const uint8_t*);
typedef int _write(image_ctx_t*,FILE*);
typedef void _free(image_ctx_t*);
typedef struct _image_dispatch_table{
_init *init;
_add_pixel *add_pixel;
_set_pixel *set_pixel;
_get_pixel *get_pixel;
_write *write;
_free *free;
} image_dispatch_table_t;
int image_set_format(int);
int image_init(image_ctx_t*, const size_t, const size_t, const int, const int);
int image_add_pixel(image_ctx_t* ctx, const uint8_t, const uint8_t, const uint8_t, const uint8_t);
int image_set_pixel(image_ctx_t* ctx, const size_t, const size_t, const uint8_t, const uint8_t, const uint8_t, const uint8_t);
int image_get_pixel(image_ctx_t* ctx,const size_t,const size_t, uint8_t const*, uint8_t const*, uint8_t const*, uint8_t const*);
int image_get_filename(image_ctx_t*, char*, size_t, char*);
int image_write(image_ctx_t*, FILE*);
void image_free(image_ctx_t*);
int image_set_library(char*);
#define ADD_PIXEL(ctx,r,g,b) image_add_pixel((ctx),(r),(g),(b),0xff)
#define ADD_PIXELA(ctx,r,g,b,a) image_add_pixel((ctx),(r),(g),(b),(a))
#define PIXEL_OFFSET(x,y,width,pixel_size) (((x) * (pixel_size)) + ((width) * (pixel_size) * (y)))
#endif

2514
src/inputs.cc Normal file

File diff suppressed because it is too large Load Diff

29
src/inputs.hh Normal file
View File

@@ -0,0 +1,29 @@
#ifndef _INPUTS_HH_
#define _INPUTS_HH_
#include "common.h"
extern char scf_file[255];
/* Resample input tiles to new resolution */
int resample_data(int scaling_factor);
int resize_data(int resolution);
int LoadSDF_SDF(char *name, int winfiles);
char *BZfgets(char *output, BZFILE *bzfd, unsigned length);
int LoadSDF_GZ(char *name);
char *GZfgets(char *output, gzFile gzfd, unsigned length);
int LoadSDF_BZ(char *name);
int LoadSDF(char *name, int winfiles);
int LoadPAT(char *az_filename, char *el_filename);
int LoadSignalColors(struct site xmtr);
int LoadLossColors(struct site xmtr);
int LoadDBMColors(struct site xmtr);
int LoadTopoData(double max_lon, double min_lon, double max_lat, double min_lat);
int LoadUDT(char *filename);
int loadLIDAR(char *filename, int resample);
int loadClutter(char *filename, double radius, struct site tx);
int averageHeight(int h, int w, int x, int y);
static const char AZ_FILE_SUFFIX[] = ".az";
static const char EL_FILE_SUFFIX[] = ".el";
#endif /* _INPUTS_HH_ */

2057
src/main.cc Normal file

File diff suppressed because it is too large Load Diff

33
src/main.hh Normal file
View File

@@ -0,0 +1,33 @@
#ifndef _MAIN_HH_
#define _MAIN_HH_
#include <stdio.h>
#include "common.h"
int ReduceAngle(double angle);
double LonDiff(double lon1, double lon2);
void *dec2dms(double decimal, char *string);
int PutMask(double lat, double lon, int value);
int OrMask(double lat, double lon, int value);
int GetMask(double lat, double lon);
void 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, int size);
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);
void free_elev(void);
void free_path(void);
void free_dem(void);
void alloc_elev(void);
void alloc_path(void);
void alloc_dem(void);
void do_allocs(void);
#endif /* _MAIN_HH_ */

9
src/models/README Normal file
View File

@@ -0,0 +1,9 @@
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
Plane earth loss model taken from "Antennas and Propagation for Wireless systems" by Simon Saunders

61
src/models/cost.cc Normal file
View File

@@ -0,0 +1,61 @@
/*****************************************************************************
* 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) {
fprintf
(stderr,"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)
lRxH = log10(1.54 * RxH);
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
src/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_ */

33
src/models/ecc33.cc Normal file
View File

@@ -0,0 +1,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double ECC33pathLoss(float f, float TxH, float RxH, float d, int mode)
{
// Sanity check as this model operates within limited Txh/Rxh bounds
if(TxH-RxH<0){
RxH=RxH/(d*2);
}
/* if (f < 700 || f > 3500) {
fprintf(stderr,"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
src/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_ */

83
src/models/egli.cc Normal file
View File

@@ -0,0 +1,83 @@
/*****************************************************************************
* Egli VHF/UHF model for Signal Server by G6DTX *
* April 2017 *
* 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 v3 *
* for more details. *
******************************************************************************
Frequency 30 to 1000MHz
h1 = 1m and above
h2 = 1m and above
Distance 1 to 50km
http://people.seas.harvard.edu/~jones/es151/prop_models/propagation.html#pel
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//static float fcmin = 30.0;
//static float fcmax = 1000.0;
//static float dmin = 1.0;
//static float dmax = 50.0;
//static float h1min = 1.0;
//static float h2min = 1.0;
static __inline float _10log10f(float x)
{
return(4.342944f*logf(x));
}
double EgliPathLoss(float f, float h1, float h2, float d)
{
double Lp50 = NAN;
float C1, C2;
/* if ((f >= fcmin) && (f <= fcmax) &&
(h1 >= h1min) && (h2 >= h2min))
{*/
if (h1 > 10.0 && h2 > 10.0)
{
Lp50 = 85.9;
C1 = 2.0;
C2 = 2.0;
}
else if (h1 > 10.0)
{
Lp50 = 76.3;
C1 = 2.0;
C2 = 1.0;
}
else if (h2 > 10.0)
{
Lp50 = 76.3;
C1 = 1.0;
C2 = 2.0;
}
else // both antenna heights below 10 metres
{
Lp50 = 66.7;
C1 = 1.0;
C2 = 1.0;
} // end if
Lp50 += 4.0f*_10log10f(d) + 2.0f*_10log10f(f) - C1*_10log10f(h1) - C2*_10log10f(h2);
/*}
else
{
fprintf(stderr,"Parameter error: Egli path loss model f=%6.2f h1=%6.2f h2=%6.2f d=%6.2f\n", f, h1, h2, d);
exit(EXIT_FAILURE);
}*/
return(Lp50);
}

6
src/models/egli.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _EGLI_HH_
#define _EGLI_HH_
double EgliPathLoss(float f, float h1, float h2, float d);
#endif /* _EGLI_HH_ */

31
src/models/ericsson.cc Normal file
View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double EricssonpathLoss(float f, float TxH, float RxH, float d, int mode)
{
/*
AKA Ericsson 9999 model
*/
// Urban
double a0 = 36.2, a1 = 30.2, a2 = -12, a3 = 0.1;
/* if (f < 150 || f > 1900) {
fprintf
(stderr,"Error: Ericsson9999 model frequency range 150-1900MHz\n");
exit(EXIT_FAILURE);
}
*/
if (mode == 2) { // Suburban / Med loss
a0 = 43.2;
a1 = 68.93;
}
if (mode == 1) { // Rural
a0 = 45.95;
a1 = 100.6;
}
double g1 = 3.2 * (log10(11.75 * RxH) * log10(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) - g1 + g2;
}

6
src/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_ */

33
src/models/fspl.cc Normal file
View File

@@ -0,0 +1,33 @@
/*****************************************************************************
* ITU-R P.525 Free Space Path Loss model for Signal Server by Alex Farrant *
* 15 January 2014 *
* optimised G6DTX April 2017 *
* 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. *
*
* https://www.itu.int/rec/R-REC-P.525/en
* Free Space Path Loss model
* Frequency: Any
* Distance: Any
*/
#include <math.h>
// use call with log/ln as this may be faster
// use constant of value 20.0/log(10.0)
static __inline float _20log10f(float x)
{
return(8.685889f*logf(x));
}
double FSPLpathLoss(float f, float d)
{
return(32.44 + _20log10f(f) + _20log10f(d));
}

6
src/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_ */

58
src/models/hata.cc Normal file
View File

@@ -0,0 +1,58 @@
/*****************************************************************************
* 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;
float C_H;
float logf = log10(f);
if(f<200){
lh_M = log10(1.54 * h_M);
C_H = 8.29 * (lh_M * lh_M) - 1.1;
}else{
lh_M = log10(11.75 * h_M);
C_H = 3.2 * (lh_M * lh_M) - 4.97;
}
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
src/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
src/models/itm.cc Normal file

File diff suppressed because it is too large Load Diff

2964
src/models/itwom3.0.cc Normal file

File diff suppressed because it is too large Load Diff

14
src/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_ */

948
src/models/los.cc Normal file
View File

@@ -0,0 +1,948 @@
#include <stdio.h>
#include <math.h>
#include "../main.hh"
#include "los.hh"
#include "cost.hh"
#include "ecc33.hh"
#include "ericsson.hh"
#include "fspl.hh"
#include "hata.hh"
#include "itwom3.0.hh"
#include "sui.hh"
#include "pel.hh"
#include "egli.hh"
#include "soil.hh"
#include <pthread.h>
#define NUM_SECTIONS 4
namespace {
pthread_t threads[NUM_SECTIONS];
unsigned int thread_count = 0;
pthread_mutex_t maskMutex;
bool ***processed;
bool has_init_processed = false;
struct propagationRange {
double min_west, max_west, min_north, max_north;
double altitude;
bool eastwest, los, use_threads;
site source;
unsigned char mask_value;
FILE *fd;
int propmodel, knifeedge, pmenv;
};
void* rangePropagation(void *parameters)
{
propagationRange *v = (propagationRange*)parameters;
if(v->use_threads) {
alloc_elev();
alloc_path();
}
double minwest = dpp + (double)v->min_west;
double lon = v->eastwest ? minwest : v->min_west;
double lat = v->min_north;
int y = 0;
do {
if (lon >= 360.0)
lon -= 360.0;
site edge;
edge.lat = lat;
edge.lon = lon;
edge.alt = v->altitude;
if(v->los)
PlotLOSPath(v->source, edge, v->mask_value, v->fd);
else
PlotPropPath(v->source, edge, v->mask_value, v->fd, v->propmodel,
v->knifeedge, v->pmenv);
++y;
if(v->eastwest)
lon = minwest + (dpp * (double)y);
else
lat = (double)v->min_north + (dpp * (double)y);
} while ( v->eastwest
? (LonDiff(lon, (double)v->max_west) <= 0.0)
: (lat < (double)v->max_north) );
if(v->use_threads) {
free_elev();
free_path();
}
return NULL;
}
void init_processed()
{
int i;
int x;
int y;
processed = new bool **[MAXPAGES];
for (i = 0; i < MAXPAGES; i++) {
processed[i] = new bool *[ippd];
for (x = 0; x < ippd; x++)
processed[i][x] = new bool [ippd];
}
for (i = 0; i < MAXPAGES; i++) {
for (x = 0; x < ippd; x++) {
for (y = 0; y < ippd; y++)
processed[i][x][y] = false;
}
}
has_init_processed = true;
}
bool can_process(double lat, double lon)
{
/* Lines, text, markings, and coverage areas are stored in a
mask that is combined with topology data when topographic
maps are generated by ss. This function sets bits in
the mask based on the latitude and longitude of the area
pointed to. */
int x, y, indx;
char found;
bool rtn = false;
for (indx = 0, found = 0; indx < MAXPAGES && found == 0;) {
x = (int)rint(ppd * (lat - dem[indx].min_north));
y = mpi - (int)rint(yppd * (LonDiff(dem[indx].max_west, lon)));
if (x >= 0 && x <= mpi && y >= 0 && y <= mpi)
found = 1;
else
indx++;
}
if (found) {
/* As long as we only set this without resetting it we can
check outside a mutex first without worrying about race
conditions. But we must lock the mutex before updating the
value. */
if(!processed[indx][x][y]) {
pthread_mutex_lock(&maskMutex);
if(!processed[indx][x][y]) {
rtn = true;
processed[indx][x][y] = true;
}
pthread_mutex_unlock (&maskMutex);
}
}
return rtn;
}
void beginThread(void *arg)
{
if(!has_init_processed)
init_processed();
int rc = pthread_create(&threads[thread_count], NULL, rangePropagation, arg);
if (rc)
fprintf(stderr,"ERROR; return code from pthread_create() is %d\n", rc);
else
++thread_count;
}
void finishThreads()
{
void* status;
for(unsigned int i=0; i<thread_count; i++) {
int rc = pthread_join(threads[i], &status);
if (rc)
fprintf(stderr,"ERROR; return code from pthread_join() is %d\n", rc);
}
thread_count = 0;
}
}
/*
* 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;
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) {
// 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))+3; // Diffraction angle divided by wavelength (m)
} else {
return 1;
}
}
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 - 1) && path.distance[y] <= max_range);
y++) {
//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
&& can_process(path.lat[y], path.lon[y])) {
distance = FEET_PER_MILE * 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 =
FEET_PER_MILE * (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, diffloss;
struct site temp;
float dkm;
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;
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. */
//if(debug)
// fprintf(stderr,"four_thirds_earth %.1f source.alt %.1f path.elevation[0] %.1f\n",four_thirds_earth,source.alt,path.elevation[0]);
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) && can_process(path.lat[y], path.lon[y])) {
char fd_buffer[64];
int buffer_offset = 0;
distance = FEET_PER_MILE * 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 = FEET_PER_MILE * 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, source.alt * METERS_PER_FOOT,
(path.elevation[y] * METERS_PER_FOOT) + (destination.alt * METERS_PER_FOOT), dkm, pmenv);
break;
case 4:
// ECC33
loss =
ECC33pathLoss(LR.frq_mhz, source.alt * METERS_PER_FOOT,
(path.elevation[y] *
METERS_PER_FOOT) +
(destination.alt *
METERS_PER_FOOT), dkm,
pmenv);
break;
case 5:
// SUI
loss =
SUIpathLoss(LR.frq_mhz, source.alt * METERS_PER_FOOT,
(path.elevation[y] *
METERS_PER_FOOT) +
(destination.alt *
METERS_PER_FOOT), dkm, pmenv);
break;
case 6:
// COST231-Hata
loss =
COST231pathLoss(LR.frq_mhz, source.alt * METERS_PER_FOOT,
(path.elevation[y] *
METERS_PER_FOOT) +
(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, source.alt * METERS_PER_FOOT,
(path.elevation[y] *
METERS_PER_FOOT) +
(destination.alt *
METERS_PER_FOOT), dkm,
pmenv);
break;
case 10:
// Plane earth
loss = PlaneEarthLoss(dkm, source.alt * METERS_PER_FOOT, (path.elevation[y] * METERS_PER_FOOT) + (destination.alt * METERS_PER_FOOT));
break;
case 11:
// Egli VHF/UHF
loss = EgliPathLoss(LR.frq_mhz, source.alt * METERS_PER_FOOT, (path.elevation[y] * METERS_PER_FOOT) + (destination.alt * METERS_PER_FOOT),dkm);
break;
case 12:
// Soil
loss = SoilPathLoss(LR.frq_mhz, dkm, LR.eps_dielect);
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 && propmodel > 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)
buffer_offset += sprintf(fd_buffer+buffer_offset,
"%.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)
buffer_offset += sprintf(fd_buffer+buffer_offset,
"%.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)
buffer_offset += sprintf(fd_buffer+buffer_offset,
"%.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)
buffer_offset += sprintf(fd_buffer+buffer_offset,
"%.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)
buffer_offset += sprintf(fd_buffer+buffer_offset,
" *");
fprintf(fd, "%s\n", fd_buffer);
}
/* 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));
}
}
if(path.lat[y]>cropLat)
cropLat=path.lat[y];
if(y>cropLon)
cropLon=y;
//if(cropLon>180)
// cropLon-=360;
}
void PlotLOSMap(struct site source, double altitude, char *plo_filename,
bool use_threads)
{
/* 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. */
static __thread unsigned char mask_value = 1;
FILE *fd = NULL;
if (plo_filename[0] != 0)
fd = fopen(plo_filename, "wb");
if (fd != NULL) {
fprintf(fd,
"%.3f, %.3f\t; max_west, min_west\n%.3f, %.3f\t; max_north, min_north\n",
max_west, min_west, max_north, min_north);
}
// Four sections start here
// Process north edge east/west, east edge north/south,
// south edge east/west, west edge north/south
double range_min_west[] = {min_west, min_west, min_west, max_west};
double range_min_north[] = {max_north, min_north, min_north, min_north};
double range_max_west[] = {max_west, min_west, max_west, max_west};
double range_max_north[] = {max_north, max_north, min_north, max_north};
propagationRange* r[NUM_SECTIONS];
for(int i = 0; i < NUM_SECTIONS; ++i) {
propagationRange *range = new propagationRange;
r[i] = range;
range->los = true;
range->eastwest = (range_min_west[i] == range_max_west[i] ? false : true);
range->min_west = range_min_west[i];
range->max_west = range_max_west[i];
range->min_north = range_min_north[i];
range->max_north = range_max_north[i];
range->use_threads = use_threads;
range->altitude = altitude;
range->source = source;
range->mask_value = mask_value;
range->fd = fd;
if(use_threads)
beginThread(range);
else
rangePropagation(range);
}
if(use_threads)
finishThreads();
for(int i = 0; i < NUM_SECTIONS; ++i){
delete r[i];
}
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, bool
use_threads)
{
static __thread unsigned char mask_value = 1;
FILE *fd = NULL;
if (LR.erp == 0.0 && debug)
fprintf(stderr, "path loss");
else {
if (debug) {
if (dbm)
fprintf(stderr, "signal power level");
else
fprintf(stderr, "field strength");
}
}
if (debug) {
fprintf(stderr,
" contours of \"%s\" out 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(stderr, "\nand %.2f %s of ground clutter",
metric ? clutter * METERS_PER_FOOT : clutter,
metric ? "meters" : "feet");
if (plo_filename[0] != 0)
fd = fopen(plo_filename, "wb");
if (fd != NULL) {
fprintf(fd,
"%.3f, %.3f\t; max_west, min_west\n%.3f, %.3f\t; max_north, min_north\n",
max_west, min_west, max_north, min_north);
}
// Four sections start here
// Process north edge east/west, east edge north/south,
// south edge east/west, west edge north/south
double range_min_west[] = {min_west, min_west, min_west, max_west};
double range_min_north[] = {max_north, min_north, min_north, min_north};
double range_max_west[] = {max_west, min_west, max_west, max_west};
double range_max_north[] = {max_north, max_north, min_north, max_north};
propagationRange* r[NUM_SECTIONS];
for(int i = 0; i < NUM_SECTIONS; ++i) {
propagationRange *range = new propagationRange;
r[i] = range;
range->los = false;
// Only process correct half
if((NUM_SECTIONS - i) <= (NUM_SECTIONS / 2) && haf == 1)
continue;
if((NUM_SECTIONS - i) > (NUM_SECTIONS / 2) && haf == 2)
continue;
range->eastwest = (range_min_west[i] == range_max_west[i] ? false : true);
range->min_west = range_min_west[i];
range->max_west = range_max_west[i];
range->min_north = range_min_north[i];
range->max_north = range_max_north[i];
range->use_threads = use_threads;
range->altitude = altitude;
range->source = source;
range->mask_value = mask_value;
range->fd = fd;
range->propmodel = propmodel;
range->knifeedge = knifeedge;
range->pmenv = pmenv;
if(use_threads)
beginThread(range);
else
rangePropagation(range);
}
if(use_threads)
finishThreads();
for(int i = 0; i < NUM_SECTIONS; ++i){
delete r[i];
}
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 = FEET_PER_MILE * 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 =
FEET_PER_MILE * (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
src/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, bool use_threads);
void PlotPropagation(struct site source, double altitude, char *plo_filename,
int propmodel, int knifeedge, int haf, int pmenv, bool use_threads);
void PlotPath(struct site source, struct site destination, char mask_value);
#endif /* _LOS_HH_ */

29
src/models/pel.cc Normal file
View File

@@ -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 <math.h>
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;
}

6
src/models/pel.hh Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _PEL_HH_
#define _PEL_HH_
double PlaneEarthLoss(float d, float TxH, float RxH);
#endif /* _PEL_HH_ */

33
src/models/soil.cc Normal file
View File

@@ -0,0 +1,33 @@
/*****************************************************************************
* Soil Path Loss model for Signal Server by Alex Farrant *
* 21 February 2018 *
* *
* 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. *
*
* Frequency: Any MHz
* Distance: Any Km
* Terrain permittivity: 1 - 15 (Bad to Good)
*/
#include <math.h>
// use call with log/ln as this may be faster
// use constant of value 20.0/log(10.0)
static __inline float _20log10f(float x)
{
return(8.685889f*logf(x));
}
double SoilPathLoss(float f, float d, float terdic)
{
float soil = (120/terdic);
return(6.4 + _20log10f(d) + _20log10f(f)+(8.69*soil));
}

6
src/models/soil.hh Normal file
View File

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

65
src/models/sui.cc Normal file
View File

@@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// use call with log/ln as this may be faster
// use constant of value 20.0/log(10.0)
static __inline float _20log10f(float x)
{
return(8.685889f*logf(x));
}
double SUIpathLoss(double f, double TxH, double RxH, double d, int mode)
{
/*
f = Frequency (MHz) 1900 to 11000
TxH = Transmitter height (m)
RxH = Receiver height (m)
d = distance (km)
mode A1 = URBAN / OBSTRUCTED
mode B2 = SUBURBAN / PARTIALLY OBSTRUCTED
mode C3 = RURAL / OPEN
Paper 1 has a Rx height correction of / 2000
Paper 2 has the same correction as / 2 and gives better results
"Ranked number 2 University in the wurld"
http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf
https://mentor.ieee.org/802.19/file/08/19-08-0010-00-0000-sui-path-loss-model.doc
*/
d *= 1e3; // km to m
// Urban (A1) is default
float a = 4.6;
float b = 0.0075;
float c = 12.6;
float s = 8.2; // Optional fading value. 8.2 to 10.6dB
float XhCF = -10.8;
if (mode == 2) { // Suburban
a = 4.0;
b = 0.0065;
c = 17.1;
XhCF = -10.8;
}
if (mode == 3) { // Rural
a = 3.6;
b = 0.005;
c = 20;
XhCF = -20;
}
float d0 = 100.0;
float A = _20log10f((4 * M_PI * d0) / (300.0 / f));
float y = a - (b * TxH) + (c / TxH);
// Assume 2.4GHz
float Xf = 0;
float Xh = 0;
//Correction factors for > 2GHz
if(f>2000){
Xf=6.0 * log10(f / 2.0);
Xh=XhCF * log10(RxH / 2.0);
}
return A + (10 * y) * (log10(d / d0)) + Xf + Xh + s;
}

6
src/models/sui.hh Normal file
View File

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

118
src/models/testmodels.cc Normal file
View File

@@ -0,0 +1,118 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/stat.h>
/*
* Propagation model test script for signal server
* Requires gnuplot
* Compile: gcc -Wall -o test test.cc sui.cc cost.cc ecc33.cc ericsson.cc fspl.cc egli.cc hata.cc -lm
* Test 850Mhz: ./test 850
*
* 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. *
* *
\****************************************************************************/
extern double EgliPathLoss(float f, float TxH, float RxH, float d);
extern double SUIpathLoss(double f, double TxH, double RxH, double d, int mode);
extern double COST231pathLoss(float f, float TxH, float RxH, float d, int mode);
extern double ECC33pathLoss(float f, float TxH, float RxH, float d, int mode);
extern double EricssonpathLoss(float f, float TxH, float RxH, float d, int mode);
extern double FSPLpathLoss(float f, float d);
extern double HATApathLoss(float f, float TxH, float RxH, float d, int mode);
extern 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);
__thread double *elev;
int main(int argc, char** argv)
{
double a = 0;
double f = atof(argv[1]);
double r = 5.0;
float TxH = 30.0;
float RxH = 2.0;
mkdir("tests", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
FILE * fh;
/*fh = fopen("tests/ITM","w");
for(float d = 0.1; d <= r; d=d+0.2){
point_to_point_ITM(TxH,RxH,15.0,0.005,301.0,f,5,1,0.5,0.5,a,"",errno);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
*/
fh = fopen("tests/SUI.1","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = SUIpathLoss(f, TxH, RxH, d,1);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/COST231.1","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = COST231pathLoss(f, TxH, RxH, d,1);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/ECC33.1","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = ECC33pathLoss(f, TxH, RxH, d,1);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/Ericsson9999.1","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = EricssonpathLoss(f, TxH, RxH, d,1);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/FSPL","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = FSPLpathLoss(f, d);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/Hata.1","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = HATApathLoss(f, TxH, RxH, d, 1);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/Egli.VHF-UHF","w");
for(float d = 0.1; d <= r; d=d+0.1){
a = EgliPathLoss(f, TxH, RxH, d);
fprintf(fh,"%.1f\t%.1f\n",d,a);
}
fclose(fh);
fh = fopen("tests/gnuplot.plt","w");
fprintf(fh,"set terminal jpeg size 800,600\nset output '%.0fMHz_propagation_models.jpg'\nset title '%.0fMHz path loss by propagation model - CloudRF.com'\n",f,f);
fprintf(fh,"set key right bottom box\nset style line 1\nset grid\nset xlabel 'Distance KM'\nset ylabel 'Path Loss dB'\n");
fprintf(fh,"plot 'FSPL' with lines, 'Hata.1' with lines, 'COST231.1' with lines,'ECC33.1' with lines,'Ericsson9999.1' with lines,'SUI.1' with lines,'Egli.VHF-UHF' with lines");
fclose(fh);
system("cd tests && gnuplot gnuplot.plt");
return(0);
}

2024
src/outputs.cc Normal file

File diff suppressed because it is too large Load Diff

17
src/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);
int 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, double rxGain);
void SeriesData(struct site source, struct site destination, char *name,
unsigned char fresnel_plot, unsigned char normalised);
#endif /* _OUTPUT_HH_ */

64
src/suitest.cc Normal file
View File

@@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// use call with log/ln as this may be faster
// use constant of value 20.0/log(10.0)
static __inline float _20log10f(float x)
{
return(8.685889f*logf(x));
}
double SUIpathLoss(double f, double TxH, double RxH, double d, int mode)
{
/*
f = Frequency (MHz) 1900 to 11000
TxH = Transmitter height (m)
RxH = Receiver height (m)
d = distance (km)
mode A1 = URBAN / OBSTRUCTED
mode B2 = SUBURBAN / PARTIALLY OBSTRUCTED
mode C3 = RURAL / OPEN
http://www.cl.cam.ac.uk/research/dtg/lce-pub/public/vsa23/VTC05_Empirical.pdf
*/
//f /=1e3;
d *= 1e3; // km to m
// Urban (A1) is default
float a = 4.6;
float b = 0.0075;
float c = 12.6;
float s = 10.6; // Optional fading value. Max 10.6dB
float XhCF = -10.8;
if (mode == 2) { // Suburban
a = 4.0;
b = 0.0065;
c = 17.1;
}
if (mode == 3) { // Rural
a = 3.6;
b = 0.005;
c = 20;
XhCF = -20;
}
float d0 = 100;
float A = _20log10f((4 * M_PI * d0) / (300.0 / f));
float y = a - (b * TxH) + (c / TxH);
//Correction factors
float Xf = 6.0 * log10(f / 2000.0);
float Xh = XhCF * log10(RxH / 2000.0);
Xh *=-1;
fprintf(stdout,"A %lf y %lf Xf %lf Xh %lf\n",A,y,Xf,Xh);
return A + (10 * y * log10(d / d0)) + Xf + Xh + s;
}
int main(){
fprintf(stdout,"%lf\n",SUIpathLoss(3500.0,15.0,10.0,1,1));
fprintf(stdout,"%lf\n",SUIpathLoss(3500.0,15.0,10.0,1,2));
fprintf(stdout,"%lf\n",SUIpathLoss(3500.0,15.0,10.0,1,3));
}

246
src/tiles.cc Normal file
View File

@@ -0,0 +1,246 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include "tiles.hh"
#include "common.h"
#define MAX_LINE 50000
/* Computes the distance between two long/lat points */
double haversine_formula(double th1, double ph1, double th2, double ph2)
{
#define TO_RAD (3.1415926536 / 180)
int R = 6371;
double dx, dy, dz;
ph1 -= ph2;
ph1 *= TO_RAD, th1 *= TO_RAD, th2 *= TO_RAD;
dz = sin(th1) - sin(th2);
dx = cos(ph1) * cos(th1) - cos(th2);
dy = sin(ph1) * cos(th1);
return asin(sqrt(dx * dx + dy * dy + dz * dz) / 2) * 2 * R;
}
int tile_load_lidar(tile_t *tile, char *filename){
FILE *fd;
char line[MAX_LINE];
short nextval;
char *pch;
/* Clear the tile data */
memset(tile, 0x00, sizeof(tile_t));
/* Open the file handle and return on error */
if ( (fd = fopen(filename,"r")) == NULL )
return errno;
/* This is where we read the header data */
/* The string is split for readability but is parsed as a block */
if( fscanf(fd,"%*s %d\n" "%*s %d\n" "%*s %lf\n" "%*s %lf\n" "%*s %lf\n" "%*s %d\n",&tile->width,&tile->height,&tile->xll,&tile->yll,&tile->cellsize,(int *)&tile->nodata) != 6 ){
fclose(fd);
return -1;
}
tile->datastart = ftell(fd);
if(debug){
fprintf(stderr,"w:%d h:%d s:%lf\n", tile->width, tile->height, tile->cellsize);
fflush(stderr);
}
/* Set the filename */
tile->filename = strdup(filename);
/* Perform xur calcs */
tile->xur = tile->xll+(tile->cellsize*tile->width);
tile->yur = tile->yll+(tile->cellsize*tile->height);
if (tile->xur > eastoffset)
eastoffset = tile->xur;
if (tile->xll < westoffset)
westoffset = tile->xll;
if (debug)
fprintf(stderr,"%d, %d, %.7f, %.7f, %.7f, %.7f, %.7f\n",tile->width,tile->height,tile->xll,tile->yll,tile->cellsize,tile->yur,tile->xur);
// Greenwich straddling hack
/* if (tile->xll <= 0 && tile->xur > 0) {
tile->xll = (tile->xur - tile->xll); // full width
tile->xur = 0.0; // budge it along so it's west of greenwich
delta = eastoffset; // add to Tx longitude later
} else {*/
// Transform WGS84 longitudes into 'west' values as society finishes east of Greenwich ;)
if (tile->xll >= 0)
tile->xll = 360-tile->xll;
if(tile->xur >= 0)
tile->xur = 360-tile->xur;
if(tile->xll < 0)
tile->xll = tile->xll * -1;
if(tile->xur < 0)
tile->xur = tile->xur * -1;
// }
if (debug)
fprintf(stderr, "POST yll %.7f yur %.7f xur %.7f xll %.7f delta %.6f\n", tile->yll, tile->yur, tile->xur, tile->xll, delta);
/* Read the actual tile data */
/* Allocate the array for the lidar data */
if ( (tile->data = (short*) calloc(tile->width * tile->height, sizeof(short))) == NULL ) {
fclose(fd);
free(tile->filename);
return ENOMEM;
}
size_t loaded = 0;
for (size_t h = 0; h < (unsigned)tile->height; h++) {
if (fgets(line, MAX_LINE, fd) != NULL) {
pch = strtok(line, " "); // split line into values
for (size_t w = 0; w < (unsigned)tile->width && pch != NULL; w++) {
/* If the data is less than a *magic* minimum, normalize it to zero */
nextval = atoi(pch);
if (nextval <= 0)
nextval = 0;
tile->data[h*tile->width + w] = nextval;
loaded++;
if ( nextval > tile->max_el )
tile->max_el = nextval;
if ( nextval < tile->min_el )
tile->min_el = nextval;
pch = strtok(NULL, " ");
}//while
} else {
fprintf(stderr, "LIDAR error @ h %zu file %s\n", h, filename);
}//if
}
double current_res_km = haversine_formula(tile->max_north, tile->max_west, tile->max_north, tile->min_west);
tile->precise_resolution = (current_res_km/MAX(tile->width,tile->height)*1000);
// Round to nearest 0.5
tile->resolution = tile->precise_resolution < 0.5f ? 0.5f : ceil((tile->precise_resolution * 2)+0.5) / 2;
// Positive westing
tile->width_deg = tile->max_west - tile->min_west >= 0 ? tile->max_west - tile->min_west : tile->max_west + (360 - tile->min_west);
tile->height_deg = tile->max_north - tile->min_north;
tile->ppdx = tile->width / tile->width_deg;
tile->ppdy = tile->height / tile->height_deg;
if (debug)
fprintf(stderr,"Pixels loaded: %zu/%d (PPD %dx%d, Res %f (%.2f))\n", loaded, tile->width*tile->height, tile->ppdx, tile->ppdy, tile->precise_resolution, tile->resolution);
/* All done, close the LIDAR file */
fclose(fd);
return 0;
}
/*
* tile_rescale
* This is used to resample tile data. It is particularly designed for
* use with LIDAR tiles where the resolution can be anything up to 2m.
* This function is capable of merging neighbouring pixel values
* The scaling factor is the distance to merge pixels.
* NOTE: This means that new resolutions can only increment in multiples of the original
* (ie 2m LIDAR can be 4/6/8/... and 20m can be 40/60)
*/
int tile_rescale(tile_t *tile, float scale){
short *new_data;
size_t skip_count = 1;
size_t copy_count = 1;
if (scale == 1) {
return 0;
}
size_t new_height = tile->height * scale;
size_t new_width = tile->width * scale;
/* Allocate the array for the lidar data */
if ( (new_data = (short*) calloc(new_height * new_width, sizeof(short))) == NULL ) {
return ENOMEM;
}
tile->max_el = -32768;
tile->min_el = 32768;
/* Making the tile data smaller */
if (scale < 1) {
skip_count = 1 / scale;
} else {
copy_count = (size_t) scale;
}
if (debug) {
fprintf(stderr,"Resampling tile %s [%.1f]:\n\tOld %dx%d. New %zux%zu\n\tScale %f Skip %zu Copy %zu\n", tile->filename, tile->resolution, tile->width, tile->height, new_width, new_height, scale, skip_count, copy_count);
fflush(stderr);
}
/* Nearest neighbour normalization. For each subsample of the original, simply
* assign the value in the top left to the new pixel
* SOURCE: X / Y
* DEST: I / J */
for (size_t y = 0, j = 0; y < (unsigned)tile->height && j < new_height; y += skip_count, j += copy_count) {
for (size_t x = 0, i = 0; x < (unsigned)tile->width && i < new_width; x += skip_count, i += copy_count) {
/* These are for scaling up the data */
for (size_t copy_y = 0; copy_y < copy_count; copy_y++) {
for (size_t copy_x = 0; copy_x < copy_count; copy_x++) {
size_t new_j = j + copy_y;
size_t new_i = i + copy_x;
/* Do the copy */
new_data[ new_j * new_width + new_i ] = tile->data[y * tile->width + x];
}
}
/* Update local min / max values */
if (tile->data[y * tile->width + x] > tile->max_el)
tile->max_el = tile->data[y * tile->width + x];
if (tile->data[y * tile->width + x] < tile->min_el)
tile->min_el = tile->data[y * tile->width + x];
}
}
/* Update the date in the tile */
free(tile->data);
tile->data = new_data;
/* Update the height and width values */
tile->height = new_height;
tile->width = new_width;
tile->resolution *= 1/scale; // A scale of 2 is HALF the resolution
tile->ppdx = tile->width / tile->width_deg;
tile->ppdy = tile->height / tile->height_deg;
// tile->width_deg *= scale;
// tile->height_deg *= scale;
if (debug)
fprintf(stderr, "Resampling complete. New resolution: %.1f\n", tile->resolution);
return 0;
}
/*
* tile_resize
* This function works in conjuntion with resample_data. It takes a
* resolution value in meters as its argument. It then calculates the
* nearest (via averaging) resample value and calls resample_data
*/
int tile_resize(tile_t* tile, int resolution){
double current_res_km = haversine_formula(tile->max_north, tile->max_west, tile->max_north, tile->min_west);
int current_res = (int) ceil((current_res_km/IPPD)*1000);
float scaling_factor = resolution / current_res;
if (debug)
fprintf(stderr, "Resampling: Current %dm Desired %dm Scale %.1f\n", current_res, resolution, scaling_factor);
return tile_rescale(tile, scaling_factor);
}
/*
* tile_destroy
* This function simply destroys any data associated with a tile
*/
void tile_destroy(tile_t* tile){
if (tile->data != NULL)
free(tile->data);
}

48
src/tiles.hh Normal file
View File

@@ -0,0 +1,48 @@
#ifndef _TILES_HH_
#define _TILES_HH_
typedef struct _tile_t{
char *filename;
union{
int cols;
int width;
};
union{
int rows;
int height;
};
union{
double xll;
double max_west;
};
union{
double yll;
double min_north;
};
union{
double xur;
double min_west;
};
union{
double yur;
double max_north;
};
double cellsize;
long long datastart;
short nodata;
short max_el;
short min_el;
short *data;
float precise_resolution;
float resolution;
double width_deg;
double height_deg;
int ppdx;
int ppdy;
} tile_t, *ptile_t;
int tile_load_lidar(tile_t*, char *);
int tile_rescale(tile_t *, float);
void tile_destroy(tile_t *);
#endif

14
test.sh
View File

@@ -9,15 +9,23 @@ echo "Running 50cm LIDAR test..."
./signalserverLIDAR -lid data/sk3587_50cm.asc -lat 53.383 -lon -1.468 -txh 8 -f $FRQ -erp 1 -rxh 2 -m -dbm -rt -90 -o tests/1 -R 0.5 -t
echo "Converting to PNG..."
convert tests/1.ppm -transparent white -channel Alpha PNG32:tests/1.png
rm tests/1.ppm
rm tests/1.*cf
echo "Running 30m Meridian test..."
./signalserverLIDAR -lid data/N051E000_AVE_DSM.tif.asc,data/N051W001_AVE_DSM.tif.asc -lat 51.472 -lon 0.0096 -txh 12 -f $FRQ -erp 5 -rxh 2 -m -dbm -rt -100 -o tests/2 -R 10 -t
echo "Converting to PNG..."
convert tests/2.ppm -transparent white -channel Alpha PNG32:tests/2.png
rm tests/2.ppm
rm tests/2.*cf
echo "Running 446 Mhz Antenna and UDT Clutter test..."
./signalserver -sdf /mnt/data -lat 42.328889 -lon -87.862500 -txh 300 -rxh 2 -f $FRQ -erp 700 -R 50 -res 600 -rt 39 -ant antenna/DB413-B -rot 180 -udt data/test.udt -pm 1 -t -o tests/ant-udt_test
convert tests/ant-udt_test.ppm tests/ant-udt_test.png
rm tests/ant-udt_test.ppm
rm tests/ant-udt_test.*cf
echo "Running soak test out to $MAXRAD"
while [ $RAD -lt $MAXRAD ]; do
echo "Calculating $FRQ MHz @ $ERP Watts for $RAD km radius..."
time ./signalserver -m -sdf data -lat 51.5 -lon -0.50 -txh 15 -rxh 2 -m -dbm -rt -100 -R $RAD -erp $ERP -f $FRQ -o tests/$RAD -pm 1 -res 1200 -t
@@ -25,12 +33,10 @@ while [ $RAD -lt $MAXRAD ]; do
rm tests/$RAD.ppm
rm tests/$RAD.*cf
echo "Calculating $FRQ MHz @ $ERP Watts for $RAD km radius (HD mode)..."
echo "Calculating $FRQ MHz @ $ERP Watts for $RAD km radius (HD mode)..."
time ./signalserverHD -m -sdf data -lat 51.5 -lon -0.50 -txh 15 -rxh 2 -m -dbm -rt -100 -R $RAD -erp $ERP -f $FRQ -o tests/$RAD.hd -pm 1 -res 3600 -t
convert tests/$RAD.hd.ppm tests/$RAD.hd.png
rm tests/$RAD.hd.ppm
rm tests/$RAD.*cf
let RAD=RAD+5
done

View File

@@ -107,15 +107,15 @@ The usgs2sdf utility takes as an argument the name of an uncompressed
and record delimited Digital Elevation Model Data (DEM) downloaded from
the US Geological Survey, and generates a SPLAT Data File (SDF) compatible
with signalserver. usgs2sdf may be invoked manually, or via the
postdownload script.
postdownload.sh script.
postdownload
============
postdownload is a front-end to the usgs2sdf utility. postdownload
postdownload.sh
===============
postdownload.sh is a front-end to the usgs2sdf utility. postdownload.sh
takes as an argument the name of the gzipped Digital Elevation Model
(DEM) downloaded from the US Geological Survey (ie: wilmington-w.gz).
postdownload uncompresses the DEM file, adds necessary record delimiters,
postdownload.sh uncompresses the DEM file, adds necessary record delimiters,
and invokes usgs2sdf to produce a SPLAT! Data File (SDF).
USGS Digital Elevation Models may be downloaded from:

4
utils/sdf/convert_sdf.sh Executable file
View File

@@ -0,0 +1,4 @@
for file in *hgt
do
sudo ./srtm2sdf -d /dev/null $file
done

4
utils/sdf/convert_sdf_hd.sh Executable file
View File

@@ -0,0 +1,4 @@
for file in *hgt
do
sudo ./srtm2sdf-hd -d /dev/null $file
done

33
utils/sdf/postdownload.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Simple script for processing of downloaded undelimited gzipped
# USGS DEM files, and converting them to SPLAT Data Files.
# Written by John A. Magliacane, KD2BD May 2002.
# Last modified on Sunday 01-Mar-09.
if [ "$#" = "0" ]; then
echo
echo "This utility reads downloaded gzipped USGS DEM"
echo "files and generates equivalent SPLAT Data Files (SDFs)."
echo
echo "Files compatible with this SPLAT! utility may be"
echo "obtained at:"
echo
echo "http://edcftp.cr.usgs.gov/pub/data/DEM/250/"
echo
echo "Usage: postdownload.sh wilmington-w.gz"
echo
else
# gunzip the downloaded file...
echo -n "Uncompressing $1..."
gunzip -c $1 > unzipped_file
echo
echo "Adding record delimiters..."
dd if=unzipped_file of=delimited_file ibs=4096 cbs=1024 conv=unblock
# Invoke usgs2sdf to generate a SPLAT Data File...
usgs2sdf delimited_file
echo -n "Removing temp files..."
rm delimited_file unzipped_file
echo
echo "Done!"
fi