Skip to content

Commit

Permalink
Merge bba6d92 into 5ba2f70
Browse files Browse the repository at this point in the history
  • Loading branch information
bwinkel committed Apr 28, 2019
2 parents 5ba2f70 + bba6d92 commit 95837c5
Show file tree
Hide file tree
Showing 21 changed files with 1,989 additions and 806 deletions.
2 changes: 1 addition & 1 deletion docs/gui/index.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. pycraf-gui:
.. _pycraf-gui:

*****************************************************************
Graphical user interface (`pycraf-gui`)
Expand Down
95 changes: 92 additions & 3 deletions docs/pathprof/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Path attenuation
The `~pycraf.pathprof` package implements `ITU-R Recommendation P.452-16
<https://www.itu.int/rec/R-REC-P.452-16-201507-I/en>`_ for path propagation
loss calculations. In `~pycraf.pathprof` this is a two-step procedure.
First a helper object, a `~pycraf.pathprof.PathProf` object, has to be
First a helper object, a `~pycraf.pathprof.PathProp` object, has to be
instantiated. It contains all kinds of parameters that define the path
geometry and hold other necessary quantities (there are many!). Second, one
feeds this object into one of the functions that calculate attenuation
Expand Down Expand Up @@ -205,7 +205,7 @@ With the PathProp object, it is now just one function call to get the path
loss::

>>> tot_loss = pathprof.loss_complete(pprop, G_t, G_r) # doctest: +REMOTE_DATA
>>> print('L_bfsg: {:5.2f} - Free-space loss\n' # doctest: +REMOTE_DATA
>>> print('L_b0p: {:5.2f} - Free-space loss\n' # doctest: +REMOTE_DATA
... 'L_bd: {:5.2f} - Basic transmission loss associated '
... 'with diffraction\n'
... 'L_bs: {:5.2f} - Tropospheric scatter loss\n'
Expand All @@ -215,7 +215,7 @@ loss::
... 'L: {:5.2f} - As L_b_corr but with gain '
... 'correction'.format(*tot_loss)
... )
L_bfsg: 123.34 dB - Free-space loss
L_b0p: 122.37 dB - Free-space loss
L_bd: 173.73 dB - Basic transmission loss associated with diffraction
L_bs: 225.76 dB - Tropospheric scatter loss
L_ba: 212.81 dB - Ducting/layer reflection loss
Expand Down Expand Up @@ -447,6 +447,95 @@ For a more illustrative example, have a look at the Jupyter `tutorial notebook
<https://github.com/bwinkel/pycraf/tree/master/notebooks/03c_attenuation_maps.ipynb>`_
on this topic.

Quick analysis of a single path
---------------------------------------
Sometimes, one needs to analyse a single path (i.e., fixed transmitter and
receiver location), which means one wants to know the propagation losses
as a function of various parameters, such as frequency, time-percentages,
or antenna heights. Depending on the number of desired samples, the approach
of creating a `~pycraf.pathprof.PathProp` instance and then run one of
the loss-functions on it (see
:ref:`pathprof-getting-started-path-attenuation`) can be slow.

Therefore, another convenience function is provided,
`~pycraf.pathprof.losses_complete`, which has a very similar function
signature as `~pycraf.pathprof.PathProp`, but accepts `~numpy.ndarrays`
(or rather arrays of `~astropy.units.Quantity`) for most of the inputs.
Obviously, parameters such as Tx and Rx location cannot be arrays, and
as a consequence, the terrain height profile can only be a 1D array.

The following shows a typical use case (which is also contained in the
:ref:`pycraf-gui`):


.. plot::
:include-source:

import numpy as np
import matplotlib.pyplot as plt
from astropy import units as u
from pycraf import pathprof, conversions as cnv


lon_tx, lat_tx = 6.8836 * u.deg, 50.525 * u.deg
lon_rx, lat_rx = 7.3334 * u.deg, 50.635 * u.deg
hprof_step = 100 * u.m # resolution of height profile
omega = 0. * u.percent
temperature = 290. * u.K
pressure = 1013. * u.hPa
h_tg, h_rg = 5 * u.m, 50 * u.m
G_t, G_r = 0 * cnv.dBi, 15 * cnv.dBi
zone_t, zone_r = pathprof.CLUTTER.URBAN, pathprof.CLUTTER.SUBURBAN

frequency = np.array([0.1, 0.5, 1, 2, 5, 10, 20, 50, 100])
time_percent = np.logspace(-3, np.log10(50), 100)

# as frequency and time_percent are arrays, we need to add
# new axes to allow proper broadcasting
results = pathprof.losses_complete(
frequency[:, np.newaxis] * u.GHz,
temperature,
pressure,
lon_tx, lat_tx,
lon_rx, lat_rx,
h_tg, h_rg,
hprof_step,
time_percent[np.newaxis] * u.percent,
zone_t=zone_t, zone_r=zone_r,
)

fig, ax = plt.subplots(1, figsize=(8, 8))
L_b_corr = results['L_b_corr'].value
t = time_percent.squeeze()
lidx = np.argmin(np.abs(t - 2e-3))
for idx, f in enumerate(frequency.squeeze()):
p = ax.semilogx(t, L_b_corr[idx], '-')
ax.text(
2e-3, L_b_corr[idx][lidx] - 1,
'{:.1f} GHz'.format(f),
ha='left', va='top', color=p[0].get_color(),
)

ax.grid()
ax.set_xlim((time_percent[0], time_percent[-1]))
ax.set_xlabel('Time percent [%]')
ax.set_ylabel('L_b_corr [dB]')

.. note::

Even with the Tx/Rx location and the terrain height profile being constant
for one call of the `~pycraf.pathprof.losses_complete` function, the
computing time can be substantial. This is because changes in the
parameters `frequency`, `h_tg`, `h_rg`, `version`, `zone_t`, and ` zone_r`
have influence on the propagation path geometry. In the ` broadcasted
arrays <https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html>`_,
the axes associated with the mentioned parameters should vary as slow as
possible. The underlying implementation will trigger a re-computation of
the path geometry if one of these parameters changes. Therefore, if the
broadcast axes for `frequency` and `time_percent` would have been chosen
in the opposite manner, the function would run about an order of magnitude
slower!

See Also
========

Expand Down
94 changes: 28 additions & 66 deletions notebooks/03a_path_propagation_basic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline"
Expand All @@ -47,9 +45,7 @@
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
Expand Down Expand Up @@ -132,9 +128,7 @@
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"(\n",
Expand All @@ -148,9 +142,7 @@
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
Expand Down Expand Up @@ -202,9 +194,7 @@
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"lons, lats, heightmap = pathprof.srtm_height_map(\n",
Expand All @@ -224,9 +214,7 @@
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
Expand Down Expand Up @@ -320,9 +308,7 @@
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Create PathProp object\n",
Expand Down Expand Up @@ -364,9 +350,7 @@
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
Expand All @@ -383,9 +367,7 @@
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
Expand Down Expand Up @@ -480,9 +462,7 @@
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
Expand All @@ -506,15 +486,13 @@
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"L_bfsg: 123.34 dB - Free-space loss\n",
"L_b0p: 123.34 dB - Free-space loss\n",
"L_bd: 173.73 dB - Basic transmission loss associated with diffraction\n",
"L_bs: 225.76 dB - Tropospheric scatter loss\n",
"L_ba: 212.81 dB - Ducting/layer reflection loss\n",
Expand All @@ -526,8 +504,8 @@
],
"source": [
"tot_loss = pathprof.loss_complete(pprop, G_t, G_r)\n",
"(L_bfsg, L_bd, L_bs, L_ba, L_b, L_b_corr, L) = tot_loss\n",
"print('L_bfsg: {0.value:5.2f} {0.unit} - Free-space loss'.format(L_bfsg))\n",
"(L_b0p, L_bd, L_bs, L_ba, L_b, L_b_corr, L) = tot_loss\n",
"print('L_b0p: {0.value:5.2f} {0.unit} - Free-space loss'.format(L_b0p))\n",
"print('L_bd: {0.value:5.2f} {0.unit} - Basic transmission loss associated with diffraction'.format(L_bd))\n",
"print('L_bs: {0.value:5.2f} {0.unit} - Tropospheric scatter loss'.format(L_bs))\n",
"print('L_ba: {0.value:5.2f} {0.unit} - Ducting/layer reflection loss'.format(L_ba))\n",
Expand All @@ -546,9 +524,7 @@
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# hprof_step = \n",
Expand All @@ -563,9 +539,7 @@
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# have to avoid the first few pixels, as each profile needs to have at\n",
Expand Down Expand Up @@ -611,9 +585,7 @@
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# do the same, but much faster!\n",
Expand Down Expand Up @@ -652,9 +624,7 @@
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
Expand Down Expand Up @@ -699,9 +669,7 @@
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"hprof_data = pathprof.height_path_data(\n",
Expand All @@ -720,9 +688,7 @@
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
Expand Down Expand Up @@ -761,15 +727,13 @@
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"dict_keys(['L_b', 'L_bd', 'eps_pr', 'L_b_corr', 'path_type', 'eps_pt', 'L_ba', 'd_lr', 'd_lt', 'L_bs', 'L_bfsg'])\n"
"dict_keys(['L_b', 'L_bd', 'eps_pr', 'L_b_corr', 'path_type', 'eps_pt', 'L_ba', 'd_lr', 'd_lt', 'L_bs', 'L_b0p'])\n"
]
}
],
Expand All @@ -787,9 +751,7 @@
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
Expand All @@ -807,7 +769,7 @@
"fig = plt.figure(figsize=(14, 8))\n",
"ax = fig.add_axes((0.1, 0.1, 0.8, 0.8))\n",
"for key, name, style in zip(\n",
" ['L_bfsg', 'L_bd', 'L_bs', 'L_ba', 'L_b', 'L_b_corr'],\n",
" ['L_b0p', 'L_bd', 'L_bs', 'L_ba', 'L_b', 'L_b_corr'],\n",
" attens.dtype.names[:-1], \n",
" ['b-', 'r-', 'c-', 'm-', 'g-', 'k-.']\n",
" ):\n",
Expand All @@ -833,9 +795,9 @@
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [conda root]",
"display_name": "Python 3",
"language": "python",
"name": "conda-root-py"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -847,9 +809,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 0
"nbformat_minor": 1
}
Loading

0 comments on commit 95837c5

Please sign in to comment.