-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitur_p525.py
167 lines (116 loc) · 4.92 KB
/
itur_p525.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""Implementation of some of the ITU-R P.525 formulas
ITU-R Recommendation P.525 (08/2019) Calculation of Free-Space Attenuation
is a short Recommendation which specifies how to calculate free-space path
loss. In addition it contains several formulas for conversion between
electric field strength and power flux at a given distance from a transmitter.
Some extra formulas are included here that fit thematically, such as converting
from W/m2 to V/m and vice versa.
Notes:
1. These are strictly only valid in the case of propagation in vacuum.
"""
import numpy as np
from scipy.constants import speed_of_light, epsilon_0
np.seterr(divide='raise')
def free_space_path_loss(freq: float, distance: float) -> float:
"""Calculate free-space path loss
Standard formula, also known as (one of) the Friis formula(e).
Args:
freq: A `float` with the frequency of the transmitter.
Unites are GHz.
distance: A `float` with the path length. Units are metres.
Returns:
The path loss in dB as a `float` number.
Raises:
ZeroDivisionError: In case the frequency is given as zero.
"""
freq *= 1e9
try:
wavelength = speed_of_light / freq
except ZeroDivisionError as error:
raise ZeroDivisionError('Frequency must be > 0'). \
with_traceback(error.__traceback__)
path_loss = 20 * np.log10(4 * np.pi * distance / wavelength)
return path_loss
def field_strength_at_distance(power: float, distance: float,
mode: str = 'dBW') -> float:
"""Calculate E-field strength at a specified distance
Sometimes it is useful to know the field strength at a particular
distance away from a transmitter.
Args:
power: A `float` with the EIRP of the transmitter. See `mode`
for more info on the units.
distance: A `float` with the distance of interes. Units are km.
mode: A `str` specifying the units of `power`. Supported ones are
dBW, dBm, W, and mW. Default is dBW.
Returns:
The electric field strength in dBuV/m as a `float` number.
Raises:
RuntimeError: In case an unsupported unit is given for the `power`.
ValueError: In case distance is given as a negative number.
"""
if 'dbm' == mode.lower():
power -= 30
elif 'mw' == mode.lower():
power /= 1e3
power = 10 * np.log10(power)
elif 'w' == mode.lower():
power = 10 * np.log10(power)
elif 'dbw' == mode.lower():
pass
else:
raise RuntimeError('Unsupported power unit')
if 0 > distance:
raise ValueError('Distance must be > 0')
field_strength = power - 20 * np.log10(distance) + 74.8
return field_strength
def power_flux_at_distance(power: float, distance: float,
mode: str = 'dBW') -> float:
"""Calculate power flux at a specified distance
Another way to represent how much EM energy there is a specific
distance away from a transmitter. Calls `field_strength_at_distance()`
internally.
Args:
power: A `float` with the EIRP of the transmitter. See `mode`
for more info on the units.
distance: A `float` with the distance of interes. Units are km.
mode: A `str` specifying the units of `power`. Supported ones are
dBW, dBm, W, and mW. Default is dBW.
Returns:
The power flux in dBW/m2 as a `float` number.
Raises:
RuntimeError: In case an unsupported unit is given for the `power`.
ValueError: In case distance is given as a negative number.
"""
field_strength = field_strength_at_distance(power, distance, mode)
power_flux = field_strength - 145.8
return power_flux
def power_flux_to_field_strength(power: float) -> float:
"""Calculate E-field strength from average power flux
A quick and simple conversion between EM field power flux in W/m2
to electric field strength in V/m.
Args:
power: A `float` with the EM field power in W/m2
Returns:
The electric field strength in V/m as a `float` number. This is the
same as the magnitude of the electric field.
Raises:
Nothing
"""
field_strength = (2 * power) / (speed_of_light * epsilon_0)
field_strength = np.sqrt(field_strength)
return field_strength
def field_strength_to_power_flux(field: float) -> float:
"""Calculate average power from E-field amplitude
A quick and somple conversion between the amplitude of an electric field
in V/m to corresponding average power flux in W/m2. This essentially
implements the Poynting formula.
Args:
field: A `float` with the amplitude of the E-field. Units are V/m.
Returns:
The averaged power flux in W/m2 as a `float` number.
Raises:
Nothing
"""
power = np.float_power(np.abs(field), 2)
power *= (0.5 * speed_of_light * epsilon_0)
return power