Decibels and link budget formulas
dB, dBm, dBW, dBi and dBc on one page, the thermal noise floor, cascaded noise figure, free-space loss from ITU-R P.525 and a link budget template with runnable code.
This sheet is for anyone who needs to close a link on paper before touching a radio. It collects the unit conversions, the noise floor, the free-space loss and the budget arithmetic in one place. For the reasoning behind them, read the decibels and link budgets lesson and the noise, SNR and capacity lesson.
The units
| Unit | Meaning | Conversion |
|---|---|---|
| dB | Ratio of two powers | 10 log10(P2 / P1) |
| dB (amplitude) | Ratio of two voltages across the same impedance | 20 log10(V2 / V1) |
| dBm | Power relative to 1 mW | 10 log10(P / 1 mW) |
| dBW | Power relative to 1 W | dBW = dBm − 30 |
| dBi | Antenna gain relative to an isotropic radiator | See the antenna formulas sheet for dBd |
| dBc | Power relative to the carrier, used for spurs, harmonics and phase noise | Negative for anything below the carrier |
| dBm/Hz | Power spectral density | Add 10 log10(B) to get dBm in bandwidth B |
| dB/Hz | Ratio per hertz, as in C/N0 | C/N0 (dB/Hz) = C/N (dB) + 10 log10(B) |
Two rules cover most mental arithmetic. Gains and losses in dB add. Absolute levels in dBm only ever have dB added to or subtracted from them, never another dBm (adding two powers needs linear units).
Values worth remembering
| Ratio | dB | Power | dBm | dBW |
|---|---|---|---|---|
| × 2 | 3.01 | 1 µW | −30 | −60 |
| × 4 | 6.02 | 1 mW | 0 | −30 |
| × 10 | 10 | 100 mW | 20 | −10 |
| × 100 | 20 | 1 W | 30 | 0 |
| × 0.5 | −3.01 | 10 W | 40 | 10 |
| × 1/1000 | −30 | 1 kW | 60 | 30 |
Two equal uncorrelated signals add to 3 dB more than either. A 10 dB difference means the weaker one adds 0.41 dB to the stronger.
Thermal noise
Thermal noise power is kTB. ITU-R Recommendation P.372 (radio noise) takes Boltzmann’s constant as 1.38 × 10⁻²³ J/K and the reference temperature T0 as 290 K, which gives 10 log10(kT0) = −204 dBW/Hz. In milliwatts that is −174 dBm/Hz.
| Bandwidth | kT0B (noise figure 0 dB) | Typical use |
|---|---|---|
| 1 Hz | −174.0 dBm | Reference density |
| 125 kHz | −123.0 dBm | LoRa channel |
| 1 MHz | −114.0 dBm | Narrowband IoT, BLE |
| 20 MHz | −101.0 dBm | Wi-Fi or LTE channel |
| 100 MHz | −94.0 dBm | NR carrier at 30 kHz SCS |
Add the receiver noise figure to get the noise floor referred to the antenna port.
Cascaded noise figure
The Friis noise formula, with every term as a linear ratio (F = 10^(NF/10), G = 10^(gain/10)):
F_total = F1 + (F2 - 1)/G1 + (F3 - 1)/(G1 G2) + ...
A passive loss of L dB ahead of the first amplifier has a noise figure of L dB at 290 K, and it adds directly to the system noise figure. This is why the LNA goes as close to the antenna as the mechanics allow.
Free-space loss
ITU-R P.525-5 (calculation of free-space attenuation) gives the free-space basic transmission loss between isotropic antennas as 20 log10(4πd/λ). With frequency in MHz and distance in km it becomes:
L_bf (dB) = 32.4 + 20 log10(f_MHz) + 20 log10(d_km)
Every doubling of distance adds 6 dB. Every doubling of frequency adds 6 dB between isotropic antennas, though a fixed-aperture antenna gains it back (see the antenna sheet).
| Frequency | 100 m | 1 km | 10 km |
|---|---|---|---|
| 868 MHz | 71.2 dB | 91.2 dB | 111.2 dB |
| 2.4 GHz | 80.0 dB | 100.0 dB | 120.0 dB |
| 3.5 GHz | 83.3 dB | 103.3 dB | 123.3 dB |
| 28 GHz | 101.3 dB | 121.3 dB | 141.3 dB |
The table comes from the formula above. Real links add clutter, walls, foliage, rain and body loss. Treat free-space loss as the best case.
The link budget
P_rx (dBm) = P_tx + G_tx + G_rx - L_cable - L_path - L_misc
noise (dBm) = -174 + 10 log10(B_Hz) + NF
sensitivity = noise + SNR_required
margin (dB) = P_rx - sensitivity
| Line | Typical source of the number |
|---|---|
| P_tx | Radio datasheet or regulatory limit (EIRP caps include antenna gain) |
| G_tx, G_rx | Antenna datasheet, in dBi, at the angle you actually use |
| L_cable | Cable datasheet loss per metre at the frequency, plus each connector’s insertion loss from its datasheet |
| L_path | Free space for a first pass, then a measured or standardised model |
| NF | Receiver datasheet, or the cascade above |
| SNR_required | The demodulator’s needed SNR at the target error rate (see the BER sheet) |
| L_misc | Fade margin, body loss, polarisation mismatch, interference allowance |
Receiver sensitivity in a datasheet is measured at a stated data rate and error rate. Compare like with like. The link margin is what you keep in reserve for fading and for everything the budget left out.
Code
The block computes the noise floor, a cascaded noise figure and a short 2.4 GHz budget. It needs only NumPy.
import numpy as np
def db_to_lin(x_db: float) -> float:
return 10 ** (x_db / 10)
def lin_to_db(x: float) -> float:
return 10 * np.log10(x)
def fspl_db(f_mhz: float, d_km: float) -> float:
"""Free-space basic transmission loss, ITU-R P.525 eq. (6)."""
return 32.4 + 20 * np.log10(f_mhz) + 20 * np.log10(d_km)
def noise_floor_dbm(bw_hz: float, nf_db: float) -> float:
"""kT0B at 290 K plus noise figure."""
k = 1.380649e-23
return lin_to_db(k * 290 * bw_hz / 1e-3) + nf_db
def cascade_nf_db(stages: list[tuple[float, float]]) -> float:
"""Friis noise formula. stages = [(gain_dB, nf_dB), ...] in signal order."""
f_total, g_running = 0.0, 1.0
for i, (g_db, nf_db) in enumerate(stages):
f = db_to_lin(nf_db)
f_total += f if i == 0 else (f - 1) / g_running
g_running *= db_to_lin(g_db)
return lin_to_db(f_total)
# kT0 in dBm/Hz
print(f"kT0 = {noise_floor_dbm(1, 0):.2f} dBm/Hz")
for bw in [125e3, 1e6, 20e6, 100e6]:
print(f"noise floor, {bw/1e6:g} MHz, NF 0 dB: {noise_floor_dbm(bw, 0):.1f} dBm")
# Receiver chain: filter (-1.5 dB, NF 1.5), LNA (+20 dB, NF 1.0), mixer (-7 dB, NF 7), IF amp (+20 dB, NF 4)
chain = [(-1.5, 1.5), (20.0, 1.0), (-7.0, 7.0), (20.0, 4.0)]
print(f"cascaded NF = {cascade_nf_db(chain):.2f} dB")
# Link budget: 2.4 GHz, 500 m, 20 dBm TX, 2 dBi each end, 3 dB of cable and connector loss
pt_dbm, gt_dbi, gr_dbi, losses_db = 20.0, 2.0, 2.0, 3.0
loss = fspl_db(2400, 0.5)
pr_dbm = pt_dbm + gt_dbi + gr_dbi - losses_db - loss
bw_hz, nf_db, snr_req_db = 20e6, 6.0, 10.0
sens_dbm = noise_floor_dbm(bw_hz, nf_db) + snr_req_db
print(f"FSPL = {loss:.1f} dB, received = {pr_dbm:.1f} dBm")
print(f"sensitivity = {sens_dbm:.1f} dBm, margin = {pr_dbm - sens_dbm:.1f} dB")
Expected output:
kT0 = -173.98 dBm/Hz
noise floor, 0.125 MHz, NF 0 dB: -123.0 dBm
noise floor, 1 MHz, NF 0 dB: -114.0 dBm
noise floor, 20 MHz, NF 0 dB: -101.0 dBm
noise floor, 100 MHz, NF 0 dB: -94.0 dBm
cascaded NF = 2.88 dB
FSPL = 94.0 dB, received = -73.0 dBm
sensitivity = -85.0 dBm, margin = 12.0 dB
The filter in front of the LNA costs its full 1.5 dB. The mixer’s 7 dB noise figure costs only about 0.25 dB, because the LNA’s 20 dB of gain sits ahead of it.
Common mistakes
- Adding dBm to dBm. Convert to milliwatts, add, convert back.
- Using 20 log10 for a power ratio. Use 20 log10 only for voltage or field-strength ratios.
- Taking the antenna’s peak gain when the link runs off boresight.
- Forgetting that a regulatory limit is often EIRP, so a higher-gain antenna means less conducted power.
- Comparing sensitivity figures measured at different data rates or error rates.
- Treating free-space loss as a prediction for a link with obstructions. Check Fresnel clearance first.
Sources
- ITU-R P.525-5, calculation of free-space attenuation.
- ITU-R P.372, radio noise, for kT0 = −204 dBW/Hz at 290 K.
- Glossary: decibel, dBm, link budget, free-space path loss.