169 lines
6.0 KiB
Python
169 lines
6.0 KiB
Python
# pathloss-func.py
|
|
|
|
# (C) 2016 by Harald Welte <laforge@gnumonks.org>
|
|
# All Rights Reserved
|
|
#
|
|
# 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
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be 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.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from Gnumeric import GnumericError, GnumericErrorVALUE
|
|
import Gnumeric
|
|
import string
|
|
import math
|
|
|
|
def lambda_by_mhz(freq_mhz):
|
|
return 300/freq_mhz
|
|
|
|
def func_fsl(freq_mhz, dist_m):
|
|
'@FUNCTION=PATHLOSS_FREESPACE\n'\
|
|
'@SYNTAX=pathloss_freespace(freq_mhz, dist_m)\n'\
|
|
'@DESCRIPTION=Compute Free Space Path Loss (in dB)\n'\
|
|
'@SEEALSO=pathloss_egli,pathloss_hata\n'
|
|
|
|
wavelen = lambda_by_mhz(freq_mhz)
|
|
|
|
return -20 * math.log10(wavelen / (4*3.1416*dist_m))
|
|
|
|
def func_fsl_inverse(freq_mhz, path_loss):
|
|
'@FUNCTION=RF_RANGE_FREESPACE\n'\
|
|
'@SYNTAX=rf_range_freespace(freq_mhz, path_loss_db)\n'\
|
|
'@DESCRIPTION=Compute Signal Range (in m) as per Free Space Loss Model\n'\
|
|
'@SEEALSO=pathloss_freespace,rf_range_egli,rf_range_hata\n'
|
|
|
|
wavelen = lambda_by_mhz(freq_mhz)
|
|
dist_m = (wavelen/10**(path_loss/-20)) / (4*3.1416)
|
|
return dist_m
|
|
|
|
|
|
def hata_ch(envi, freq_mhz, rx_ant_m):
|
|
logfreq = math.log10(freq_mhz)
|
|
ch = 0
|
|
if envi == 'city_small' or envi == 'city_medium':
|
|
ch = 0.8 + (1.1 * logfreq - 0.7)*rx_ant_m - (1.56 * logfreq)
|
|
elif envi == 'city_large':
|
|
if freq_mhz < 200:
|
|
ch = 8.29 * math.pow(math.log10(1.54*rx_ant_m), 2) - 1.1
|
|
elif freq_mhz > 200:
|
|
ch = 3.2 * math.pow(math.log10(11.75*rx_ant_m), 2) - 4.97
|
|
return ch
|
|
|
|
def hata_cm(envi, freq_mhz):
|
|
logfreq = math.log10(freq_mhz)
|
|
att = 0
|
|
if freq_mhz <= 1500:
|
|
if envi == 'open_area' or envi == 'rural':
|
|
# https://en.wikipedia.org/wiki/Hata_model_for_open_areas
|
|
att = -4.78 * math.pow(logfreq, 2) + 18.33 * logfreq - 40.94
|
|
elif envi == 'suburban':
|
|
# https://en.wikipedia.org/wiki/Hata_model_for_suburban_areas
|
|
att = -2 * math.pow(logfreq/28, 2) - 5.4
|
|
else:
|
|
if envi == 'city_large':
|
|
att = 3
|
|
else:
|
|
att = 0
|
|
return att
|
|
|
|
def hata_c0(freq_mhz):
|
|
# http://morse.colorado.edu/~tlen5510/text/classwebch3.html
|
|
if freq_mhz <= 1500:
|
|
c0 = 69.55
|
|
else:
|
|
c0 = 46.3
|
|
return c0
|
|
|
|
def hata_cf(freq_mhz):
|
|
# http://morse.colorado.edu/~tlen5510/text/classwebch3.html
|
|
if freq_mhz <= 1500:
|
|
cf = 26.16
|
|
else:
|
|
cf = 33.9
|
|
return cf
|
|
|
|
def func_hata(envi, freq_mhz, dist_m, bts_ant_m, ms_ant_m):
|
|
'@FUNCTION=PATHLOSS_HATA\n'\
|
|
'@SYNTAX=pathloss_hata(environment, freq_mhz, dist_m, bts_ant_m, ms_ant_m)\n'\
|
|
'@DESCRIPTION=Compute Path Loss (in dB) as per Hata Model\n'\
|
|
'@SEEALSO=pathloss_freespace,pathloss_hata\n'
|
|
|
|
# FIXME: valid for 150MHz - 2GHz, MS 1-10m, BS 30-200m, dist # 1-10km
|
|
environs = ('open_area', 'rural', 'suburban', 'city_small',
|
|
'city_medium', 'city_large')
|
|
if not envi in environs:
|
|
raise GnumericError(GnumericErrorVALUE)
|
|
|
|
# https://en.wikipedia.org/wiki/Hata_model_for_urban_areas
|
|
hata = hata_c0(freq_mhz) + hata_cf(freq_mhz) * math.log10(freq_mhz)
|
|
hata -= 13.82 * math.log10(bts_ant_m)
|
|
hata -= hata_ch(envi, freq_mhz, ms_ant_m)
|
|
hata += (44.9 - 6.55 * math.log10(bts_ant_m)) * math.log10(dist_m/1000)
|
|
# subtract correction for open_area / suburban
|
|
hata += hata_cm(envi, freq_mhz)
|
|
|
|
return hata
|
|
|
|
def func_hata_inverse(envi, freq_mhz, path_loss, bts_ant_m, ms_ant_m):
|
|
'@FUNCTION=RF_RANGE_HATA\n'\
|
|
'@SYNTAX=rf_range_hata(environment, freq_mhz, path_loss_db, bts_ant_m, ms_ant_m)\n'\
|
|
'@DESCRIPTION=Compute Signal Range (in m) as per Hata Model\n'\
|
|
'@SEEALSO=pathloss_hata,rf_range_freespace,rF_range_egli\n'
|
|
|
|
l = hata_c0(freq_mhz) + hata_cf(freq_mhz) * math.log10(freq_mhz)
|
|
l -= 13.82 * math.log10(bts_ant_m)
|
|
l -= hata_ch(envi, freq_mhz, ms_ant_m)
|
|
l += hata_cm(envi, freq_mhz)
|
|
# subtract all non-distance related losses from path loss,
|
|
# remainder is the only term depending on distance
|
|
r = path_loss - l
|
|
mult = (44.9 - 6.55 * math.log10(bts_ant_m))
|
|
att_dist = r / mult
|
|
# now we just need the inverse of log10
|
|
dist_km = 10 ** att_dist
|
|
|
|
return dist_km * 1000
|
|
|
|
|
|
def func_egli(freq_mhz, dist_m, tx_ant_m, rx_ant_m):
|
|
'@FUNCTION=PATHLOSS_EGLI\n'\
|
|
'@SYNTAX=pathloss_egli(freq_mhz, dist_m, tx_ant_m, rx_ant_m)\n'\
|
|
'@DESCRIPTION=Compute Path Loss (in dB) as per Egli Model\n'\
|
|
'@SEEALSO=pathloss_freespace,pathloss_hata\n'
|
|
|
|
# https://en.wikipedia.org/wiki/Egli_model
|
|
att = -20 * math.log10(rx_ant_m*tx_ant_m / (dist_m*dist_m))
|
|
att += 20 * math.log10(freq_mhz/40)
|
|
|
|
return att
|
|
|
|
def func_egli_inverse(freq_mhz, path_loss, bts_ant_m, ms_ant_m):
|
|
'@FUNCTION=RF_RANGE_EGLI\n'\
|
|
'@SYNTAX=rf_range_egli(freq_mhz, path_loss_db, bts_ant_m, ms_ant_m)\n'\
|
|
'@DESCRIPTION=Compute Signal Range (in m) as per Egli Model\n'\
|
|
'@SEEALSO=pathloss_egli,rf_range_freespace,rf_range_hata\n'
|
|
|
|
l = 20 * math.log10(freq_mhz/40)
|
|
r = path_loss - l
|
|
x = ms_ant_m*bts_ant_m
|
|
dist_m = math.sqrt(x/(10**(r/-20)))
|
|
return dist_m
|
|
|
|
|
|
pathlossfunc_functions = {
|
|
'pathloss_freespace': ('ff', 'freq_mhz, dist_m', func_fsl),
|
|
'rf_range_freespace': ('ff', 'freq_mhz, path_loss', func_fsl_inverse),
|
|
'pathloss_egli': ('ffff', 'freq_mhz, dist_m, tx_ant_m, rx_ant_m', func_egli),
|
|
'rf_range_egli': ('ffff', 'freq_mhz, path_loss_db, bts_ant_m, ms_ant_m', func_egli_inverse),
|
|
'pathloss_hata': ('sffff', 'environ, freq_mhz, dist_m, bts_ant_m, ms_ant_m', func_hata),
|
|
'rf_range_hata': ('sffff', 'environ, freq_mhz, path_loss_db, bts_ant_m, ms_ant_m', func_hata_inverse),
|
|
}
|