Antenna and propagation formulas
Wavelength, gain and aperture, dipole directivity, EIRP, Friis, Fresnel clearance, Doppler and coherence time, and the TR 38.901 and ITU-R path loss models, with code and a path loss chart.
This sheet is for engineers who need a propagation number fast: how much gain a dish gives, how much clearance a hop needs, how quickly the channel changes, or what a standard model predicts at 3.5 GHz. The formulas were checked against the ITU-R Recommendations and 3GPP TR 38.901 (study on channel model for frequencies from 0.5 to 100 GHz) named in each section. For the link arithmetic around them, see the decibels and link budget sheet.
Basics
| Quantity | Formula | Handy value |
|---|---|---|
| Wavelength | λ = c / f | 12.5 cm at 2.4 GHz, 8.6 cm at 3.5 GHz, 1.07 cm at 28 GHz |
| Antenna gain from aperture | G = 4π A_e / λ² | Isotropic antenna: A_e = λ² / 4π (ITU-R P.525) |
| Dish gain | G = η (π D / λ)², η the aperture efficiency | 0.6 m at 12 GHz, η = 0.6: 35.3 dBi |
| dBd to dBi | dBi = dBd + 2.15 | A half-wave dipole has directivity 1.64 (computed below) |
| Short dipole | Directivity 1.5 | 1.76 dBi |
| EIRP | P_tx (dBm) − L_feed (dB) + G_tx (dBi) | 20 dBm into a 6 dBi antenna with 1 dB feed loss: 25 dBm |
| Polarisation mismatch | Loss = −20 log10 cos ψ, ψ the angle between linear polarisations | 3 dB at 45°, very large at 90° |
Gain at a fixed aperture rises with frequency as 20 log10 f. That is why a fixed-size dish link loses nothing as frequency rises, even though free-space loss between isotropic antennas grows.
The Friis transmission equation
P_rx = P_tx G_tx G_rx (λ / (4π d))² (linear)
P_rx (dBm) = P_tx (dBm) + G_tx (dBi) + G_rx (dBi) - L_bf (dB)
L_bf = 20 log10(4π d / λ) = 32.4 + 20 log10(f_MHz) + 20 log10(d_km) (ITU-R P.525-5)
The second form of L_bf has the same constant with f in GHz and d in metres, which is how TR 38.901 writes it. The equation holds in the far field, beyond roughly 2D²/λ for an antenna of largest dimension D. See the glossary entries for Friis transmission equation and free-space path loss.
Clearance and ground reflection
| Quantity | Formula | Source |
|---|---|---|
| First Fresnel zone radius | F1 = 17.3 √(d1 d2 / (f d)) m, f in GHz, d1, d2, d in km | ITU-R P.530-19 eq. (3) |
| Clearance target | Keep at least 60 % of F1 clear of obstacles for free-space conditions | ITU-R P.530-19 |
| Two-ray breakpoint | R_bp = 4 h1 h2 / λ | ITU-R P.1411-13 eq. (3), lower bound for line-of-sight street links |
| Beyond the breakpoint | The lower-bound slope rises from 20 to 40 dB per decade (UHF) | ITU-R P.1411-13 |
A 10 km hop at 5.8 GHz has F1 = 11.4 m at mid-path. Mount heights follow from that number plus the earth bulge, not from line of sight alone.
Time and frequency variation
| Quantity | Formula | Source |
|---|---|---|
| Maximum Doppler shift | f_d = v f / c | |
| Doppler spread | D_s = 2 f_d (paths from all directions) | Tse and Viswanath, chapter 2 |
| Coherence time | T_c ≈ 1 / (4 D_s) | Tse and Viswanath eq. (2.44). They note others use 1/D_s or 1/(8 D_s) |
| Coherence bandwidth | W_c ≈ 1 / (2 T_d), T_d the delay spread | Tse and Viswanath, chapter 2 |
At 120 km/h and 3.5 GHz, f_d = 389 Hz and T_c is about 0.32 ms, shorter than one 0.5 ms NR slot at 30 kHz spacing. These are order-of-magnitude rules. Use them to choose pilot spacing and then test with a channel model.
Path loss models
3GPP TR 38.901 (0.5 to 100 GHz)
fc in GHz, distances in metres, d3D the straight-line distance. NLOS loss is the larger of the LOS formula and the NLOS formula shown. σ_SF is the log-normal shadow fading standard deviation.
| Scenario | Formula (before the breakpoint for LOS) | σ_SF | Default heights |
|---|---|---|---|
| UMa LOS | 28.0 + 22 log10(d3D) + 20 log10(fc) | 4 dB | BS 25 m, UE 1.5 to 22.5 m |
| UMa NLOS | 13.54 + 39.08 log10(d3D) + 20 log10(fc) − 0.6 (h_UT − 1.5) | 6 dB | |
| UMi street canyon LOS | 32.4 + 21 log10(d3D) + 20 log10(fc) | 4 dB | BS 10 m |
| UMi street canyon NLOS | 35.3 log10(d3D) + 22.4 + 21.3 log10(fc) − 0.3 (h_UT − 1.5) | 7.82 dB | |
| Indoor hotspot LOS | 32.4 + 17.3 log10(d3D) + 20 log10(fc) | 3 dB | |
| Indoor hotspot NLOS | 38.3 log10(d3D) + 17.30 + 24.9 log10(fc) | 8.03 dB |
Beyond the breakpoint d’_BP = 4 h’_BS h’_UT fc / c, the LOS slope becomes 40 dB per decade. The primed heights are the actual heights minus an effective environment height h_E (1 m for UMi, and 1 m or larger for UMa). The table also has rural macro, indoor factory and optional simplified NLOS forms. Read TR 38.901 for applicability ranges before you use any of them.
ITU-R P.1238-13 (indoor)
L_total = 20 log10(f_MHz) - 28 + N log10(d_m) + L_f(n)
N is the distance power loss coefficient, tabulated by frequency and environment. L_f(n) is the floor penetration loss for n floors. Both come from measurements in the Recommendation’s tables. Look them up for your band.
ITU-R P.838-3 (rain)
Specific attenuation γ_R = k R^α dB/km, with R the rain rate in mm/h and k and α tabulated against frequency from 1 to 1000 GHz. ITU-R P.530 uses γ_R in its rain attenuation prediction for line-of-sight hops.
Code
The first block computes the directivities and the worked numbers above. Short dipole and half-wave dipole patterns are integrated numerically.
import numpy as np
from scipy.integrate import quad
C = 299_792_458.0
def directivity(pattern) -> float:
"""Peak directivity of a pattern U(theta) that does not depend on phi."""
theta = np.linspace(1e-6, np.pi - 1e-6, 20001)
u_max = pattern(theta).max()
integral, _ = quad(lambda t: pattern(t) * np.sin(t), 1e-9, np.pi - 1e-9, limit=200)
return 4 * np.pi * u_max / (2 * np.pi * integral)
short_dipole = lambda t: np.sin(t) ** 2
half_wave = lambda t: (np.cos(np.pi / 2 * np.cos(t)) / np.sin(t)) ** 2
for name, pat in [("short dipole", short_dipole), ("half-wave dipole", half_wave)]:
d = directivity(pat)
print(f"{name}: D = {d:.3f} = {10*np.log10(d):.2f} dBi")
def dish_gain_dbi(diameter_m: float, f_hz: float, efficiency: float = 0.6) -> float:
lam = C / f_hz
return 10 * np.log10(efficiency * (np.pi * diameter_m / lam) ** 2)
print(f"0.6 m dish at 12 GHz, efficiency 0.6: {dish_gain_dbi(0.6, 12e9):.1f} dBi")
def fresnel_r1_m(f_ghz: float, d1_km: float, d2_km: float) -> float:
"""First Fresnel zone radius, ITU-R P.530 eq. (3)."""
return 17.3 * np.sqrt(d1_km * d2_km / (f_ghz * (d1_km + d2_km)))
print(f"Fresnel radius at mid-path, 5.8 GHz, 10 km hop: {fresnel_r1_m(5.8, 5, 5):.1f} m")
v_kmh, f_hz = 120, 3.5e9
fd = v_kmh / 3.6 * f_hz / C
print(f"max Doppler at {v_kmh} km/h, 3.5 GHz: {fd:.0f} Hz, coherence time 1/(4 Ds) with Ds = 2 fd: {1e3/(8*fd):.2f} ms")
Expected output:
short dipole: D = 1.500 = 1.76 dBi
half-wave dipole: D = 1.641 = 2.15 dBi
0.6 m dish at 12 GHz, efficiency 0.6: 35.3 dBi
Fresnel radius at mid-path, 5.8 GHz, 10 km hop: 11.4 m
max Doppler at 120 km/h, 3.5 GHz: 389 Hz, coherence time 1/(4 Ds) with Ds = 2 fd: 0.32 ms
The second block evaluates TR 38.901 UMa and UMi against free space at 3.5 GHz. It fixes h_E at 1 m, which TR 38.901 makes random for UMa, so treat the UMa LOS curve beyond the breakpoint as indicative.
import numpy as np
C = 3.0e8 # TR 38.901 uses c = 3.0e8 m/s
def fspl(d3d_m, fc_ghz):
return 32.4 + 20 * np.log10(fc_ghz) + 20 * np.log10(d3d_m)
def uma(d2d_m, fc_ghz, h_bs=25.0, h_ut=1.5, h_e=1.0):
"""TR 38.901 Table 7.4.1-1 UMa, LOS and NLOS, with h_E fixed at 1 m."""
d3d = np.sqrt(d2d_m ** 2 + (h_bs - h_ut) ** 2)
d_bp = 4 * (h_bs - h_e) * (h_ut - h_e) * fc_ghz * 1e9 / C
pl1 = 28.0 + 22 * np.log10(d3d) + 20 * np.log10(fc_ghz)
pl2 = (28.0 + 40 * np.log10(d3d) + 20 * np.log10(fc_ghz)
- 9 * np.log10(d_bp ** 2 + (h_bs - h_ut) ** 2))
los = np.where(d2d_m <= d_bp, pl1, pl2)
nlos_p = 13.54 + 39.08 * np.log10(d3d) + 20 * np.log10(fc_ghz) - 0.6 * (h_ut - 1.5)
return los, np.maximum(los, nlos_p), d_bp
def umi_nlos(d2d_m, fc_ghz, h_bs=10.0, h_ut=1.5, h_e=1.0):
"""TR 38.901 Table 7.4.1-1 UMi street canyon NLOS."""
d3d = np.sqrt(d2d_m ** 2 + (h_bs - h_ut) ** 2)
d_bp = 4 * (h_bs - h_e) * (h_ut - h_e) * fc_ghz * 1e9 / C
pl1 = 32.4 + 21 * np.log10(d3d) + 20 * np.log10(fc_ghz)
pl2 = (32.4 + 40 * np.log10(d3d) + 20 * np.log10(fc_ghz)
- 9.5 * np.log10(d_bp ** 2 + (h_bs - h_ut) ** 2))
los = np.where(d2d_m <= d_bp, pl1, pl2)
nlos_p = 35.3 * np.log10(d3d) + 22.4 + 21.3 * np.log10(fc_ghz) - 0.3 * (h_ut - 1.5)
return np.maximum(los, nlos_p)
fc = 3.5
d = np.array([10, 20, 50, 100, 200, 300, 500, 700, 1000, 1500, 2000], dtype=float)
uma_los, uma_nlos, d_bp = uma(d, fc)
umi = umi_nlos(d, fc)
free = fspl(np.sqrt(d ** 2 + 23.5 ** 2), fc)
print(f"UMa breakpoint at {fc} GHz: {d_bp:.0f} m")
for name, v in [("free space", free), ("UMa LOS", uma_los), ("UMa NLOS", uma_nlos), ("UMi NLOS", umi)]:
print(name, [[int(x), round(float(y), 1)] for x, y in zip(d, v)])
It prints a UMa breakpoint of 560 m and the values plotted here.
At 1 km the UMa NLOS median is about 38 dB above free space. That gap, plus a shadow fading margin of one or two σ_SF, is what a cellular link budget has to carry.
Pitfalls
- Mixing units between forms of the same formula. P.525 uses MHz and km. TR 38.901 uses GHz and metres. The constant 32.4 happens to fit both.
- Using peak antenna gain for a user well off boresight. Read the pattern.
- Applying a model outside its stated range of distance, height or frequency.
- Forgetting shadow fading. The formulas give a median, not a guarantee.
- Treating a coherence time rule as exact. The factor in front of 1/D_s is a convention.
Sources
- ITU-R P.525-5, free-space attenuation.
- ITU-R P.530-19, terrestrial line-of-sight systems, for Fresnel clearance.
- ITU-R P.1411-13, short-range outdoor propagation, for the two-ray breakpoint.
- ITU-R P.1238-13, indoor propagation.
- ITU-R P.838-3, rain attenuation.
- 3GPP TR 38.901, Table 7.4.1-1, path loss models.
- D. Tse and P. Viswanath, Fundamentals of Wireless Communication, Cambridge University Press, 2005, doi:10.1017/CBO9780511807213, chapter 2.
- Glossary: path loss, multipath, beamwidth, mmWave.