RF Cascade Models API¶
Noise figure, gain cascade, and dynamic range calculations for RF receiver/transmitter chains.
Overview¶
from phased_array_systems.models.rf import (
# Noise figure
friis_noise_figure,
noise_figure_to_temp,
noise_temp_to_figure,
system_noise_temperature,
# Gain
cascade_gain,
cascade_gain_db,
# Dynamic range
cascade_iip3,
cascade_oip3,
sfdr_from_iip3,
sfdr_from_oip3,
mds_from_noise_figure,
# Complete cascade
RFStage,
cascade_analysis,
)
Noise Figure Functions¶
Functions for calculating cascaded noise figure and noise temperature conversions.
noise_figure_to_temp
¶
Convert noise figure to equivalent noise temperature.
Te = T0 * (F - 1)
| PARAMETER | DESCRIPTION |
|---|---|
nf_db
|
Noise figure in dB
TYPE:
|
t0
|
Reference temperature in Kelvin (default 290K)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
Equivalent noise temperature in Kelvin |
Source code in src/phased_array_systems/models/rf/cascade.py
noise_temp_to_figure
¶
Convert equivalent noise temperature to noise figure.
F = 1 + Te/T0
| PARAMETER | DESCRIPTION |
|---|---|
te
|
Equivalent noise temperature in Kelvin
TYPE:
|
t0
|
Reference temperature in Kelvin (default 290K)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
Noise figure in dB |
Source code in src/phased_array_systems/models/rf/cascade.py
friis_noise_figure
¶
Calculate cascaded noise figure using Friis equation.
The Friis formula for cascaded noise figure
F_total = F1 + (F2-1)/G1 + (F3-1)/(G1*G2) + ...
This shows why low-noise amplifiers (LNAs) are placed first - the first stage dominates the system noise figure.
| PARAMETER | DESCRIPTION |
|---|---|
stages
|
List of (gain_db, noise_figure_db) tuples for each stage Stages are in signal flow order (first = input)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with: - total_nf_db: Cascaded noise figure in dB - total_gain_db: Cascaded gain in dB - noise_temp_k: Equivalent noise temperature - stage_contributions_db: NF contribution from each stage |
Source code in src/phased_array_systems/models/rf/cascade.py
system_noise_temperature
¶
system_noise_temperature(antenna_temp_k: float, receiver_nf_db: float, line_loss_db: float = 0.0, line_temp_k: float = T0) -> dict[str, float]
Calculate system noise temperature including antenna and losses.
T_sys = T_ant + T_line + T_rx
Where T_line accounts for loss between antenna and receiver.
| PARAMETER | DESCRIPTION |
|---|---|
antenna_temp_k
|
Antenna noise temperature in Kelvin
TYPE:
|
receiver_nf_db
|
Receiver noise figure in dB
TYPE:
|
line_loss_db
|
Transmission line loss in dB (default 0)
TYPE:
|
line_temp_k
|
Physical temperature of line in Kelvin
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with: - system_temp_k: Total system noise temperature - antenna_contribution_k: Antenna noise contribution - line_contribution_k: Line loss contribution - receiver_contribution_k: Receiver contribution - system_nf_db: Effective system noise figure |
Source code in src/phased_array_systems/models/rf/cascade.py
Gain Functions¶
Functions for calculating cascaded gain through multi-stage RF chains.
cascade_gain
¶
Calculate total cascaded gain.
Simply sums gains in dB (multiplies in linear).
| PARAMETER | DESCRIPTION |
|---|---|
gains_db
|
List of stage gains in dB (negative for loss)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
Total gain in dB |
Source code in src/phased_array_systems/models/rf/cascade.py
cascade_gain_db
¶
Calculate total cascaded gain from stage tuples.
| PARAMETER | DESCRIPTION |
|---|---|
stages
|
List of (gain_db, noise_figure_db) tuples
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
float
|
Total gain in dB |
Source code in src/phased_array_systems/models/rf/cascade.py
Dynamic Range Functions¶
Functions for calculating cascaded intercept points and spurious-free dynamic range.
cascade_iip3
¶
Calculate cascaded input third-order intercept point.
For cascaded stages
1/IIP3_total = 1/IIP3_1 + G1/IIP3_2 + G1*G2/IIP3_3 + ...
(All values in linear power, not dB)
| PARAMETER | DESCRIPTION |
|---|---|
stages
|
List of (gain_db, iip3_dbm) tuples for each stage
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with: - iip3_dbm: Cascaded input IP3 in dBm - oip3_dbm: Cascaded output IP3 in dBm - total_gain_db: Cascaded gain |
Source code in src/phased_array_systems/models/rf/cascade.py
cascade_oip3
¶
Calculate cascaded output third-order intercept point.
Same as cascade_iip3 but with OIP3 inputs.
| PARAMETER | DESCRIPTION |
|---|---|
stages
|
List of (gain_db, oip3_dbm) tuples for each stage
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with iip3_dbm, oip3_dbm, total_gain_db |
Source code in src/phased_array_systems/models/rf/cascade.py
sfdr_from_iip3
¶
Calculate spurious-free dynamic range from IIP3.
SFDR is the range between the noise floor and the signal level where third-order intermodulation products equal the noise.
SFDR = (2/3) * (IIP3 - Noise Floor)
| PARAMETER | DESCRIPTION |
|---|---|
iip3_dbm
|
Input third-order intercept point in dBm
TYPE:
|
noise_floor_dbm_hz
|
Noise floor spectral density in dBm/Hz
TYPE:
|
bandwidth_hz
|
Signal bandwidth for integrated noise
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with: - sfdr_db: Spurious-free dynamic range in dB - noise_floor_dbm: Integrated noise floor - max_signal_dbm: Maximum signal before spurs exceed noise |
Source code in src/phased_array_systems/models/rf/cascade.py
sfdr_from_oip3
¶
sfdr_from_oip3(oip3_dbm: float, noise_floor_dbm_hz: float, bandwidth_hz: float, gain_db: float) -> dict[str, float]
Calculate spurious-free dynamic range from OIP3.
| PARAMETER | DESCRIPTION |
|---|---|
oip3_dbm
|
Output third-order intercept point in dBm
TYPE:
|
noise_floor_dbm_hz
|
Noise floor spectral density in dBm/Hz
TYPE:
|
bandwidth_hz
|
Signal bandwidth for integrated noise
TYPE:
|
gain_db
|
Total system gain in dB
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with sfdr_db, noise_floor_dbm, max_signal_dbm |
Source code in src/phased_array_systems/models/rf/cascade.py
mds_from_noise_figure
¶
mds_from_noise_figure(noise_figure_db: float, bandwidth_hz: float, snr_required_db: float = 0.0, t0: float = T0) -> dict[str, float]
Calculate minimum detectable signal from noise figure.
MDS = kTB + NF + SNR_required
| PARAMETER | DESCRIPTION |
|---|---|
noise_figure_db
|
System noise figure in dB
TYPE:
|
bandwidth_hz
|
Receiver bandwidth in Hz
TYPE:
|
snr_required_db
|
Required SNR for detection (default 0 dB)
TYPE:
|
t0
|
Reference temperature in Kelvin
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float]
|
Dictionary with: - mds_dbm: Minimum detectable signal in dBm - noise_floor_dbm: Noise floor in dBm - ktb_dbm: Thermal noise power |
Source code in src/phased_array_systems/models/rf/cascade.py
Complete Cascade Analysis¶
Classes and functions for comprehensive RF chain analysis.
RFStage
dataclass
¶
RFStage(name: str, gain_db: float, noise_figure_db: float, iip3_dbm: float = 100.0, p1db_dbm: float = 100.0)
A single stage in an RF chain.
| ATTRIBUTE | DESCRIPTION |
|---|---|
name |
Descriptive name for the stage
TYPE:
|
gain_db |
Stage gain in dB (negative for loss)
TYPE:
|
noise_figure_db |
Stage noise figure in dB
TYPE:
|
iip3_dbm |
Input third-order intercept point in dBm
TYPE:
|
p1db_dbm |
Input 1dB compression point in dBm (optional)
TYPE:
|
cascade_analysis
¶
cascade_analysis(stages: list[RFStage], bandwidth_hz: float = 1000000.0, input_power_dbm: float = -60.0) -> dict[str, float | list]
Perform complete cascaded analysis of an RF chain.
This is the main function for analyzing a complete receiver or transmitter chain, computing noise figure, gain, linearity, and dynamic range.
| PARAMETER | DESCRIPTION |
|---|---|
stages
|
List of RFStage objects in signal flow order
TYPE:
|
bandwidth_hz
|
Analysis bandwidth in Hz
TYPE:
|
input_power_dbm
|
Reference input power for level tracking
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, float | list]
|
Dictionary with comprehensive cascade results: - total_gain_db: Cascaded gain - total_nf_db: Cascaded noise figure - noise_temp_k: Equivalent noise temperature - iip3_dbm: Cascaded input IP3 - oip3_dbm: Cascaded output IP3 - sfdr_db: Spurious-free dynamic range - mds_dbm: Minimum detectable signal - stage_levels_dbm: Signal level at each stage output - stage_names: Names of each stage |
Source code in src/phased_array_systems/models/rf/cascade.py
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | |
Output Metrics¶
| Metric | Units | Description |
|---|---|---|
total_gain_db |
dB | Cascaded system gain |
total_nf_db |
dB | Cascaded noise figure |
noise_temp_k |
K | Equivalent noise temperature |
iip3_dbm |
dBm | Input third-order intercept point |
oip3_dbm |
dBm | Output third-order intercept point |
sfdr_db |
dB | Spurious-free dynamic range |
mds_dbm |
dBm | Minimum detectable signal |
noise_floor_dbm |
dBm | Integrated noise floor |
Usage Examples¶
Friis Noise Figure Cascade¶
from phased_array_systems.models.rf import friis_noise_figure
# LNA -> Mixer -> IF Amp chain
result = friis_noise_figure([
(20, 1.5), # LNA: 20 dB gain, 1.5 dB NF
(-8, 8), # Mixer: -8 dB gain (loss), 8 dB NF
(30, 4), # IF Amp: 30 dB gain, 4 dB NF
])
print(f"System NF: {result['total_nf_db']:.2f} dB")
print(f"System Gain: {result['total_gain_db']:.1f} dB")
print(f"Noise Temperature: {result['noise_temp_k']:.1f} K")
System Noise Temperature¶
from phased_array_systems.models.rf import system_noise_temperature
# Satellite receiver with cold sky
result = system_noise_temperature(
antenna_temp_k=50, # Cold sky
receiver_nf_db=2.0, # Low-noise receiver
line_loss_db=0.5, # Cable/waveguide loss
)
print(f"System Temperature: {result['system_temp_k']:.1f} K")
print(f"Antenna contribution: {result['antenna_contribution_k']:.1f} K")
print(f"Receiver contribution: {result['receiver_contribution_k']:.1f} K")
Cascaded IIP3 and SFDR¶
from phased_array_systems.models.rf import cascade_iip3, sfdr_from_iip3
# Calculate cascaded linearity
iip3_result = cascade_iip3([
(20, -5), # LNA: 20 dB gain, -5 dBm IIP3
(-8, 15), # Mixer: -8 dB gain, +15 dBm IIP3
(30, 10), # IF Amp: 30 dB gain, +10 dBm IIP3
])
print(f"Cascaded IIP3: {iip3_result['iip3_dbm']:.1f} dBm")
print(f"Cascaded OIP3: {iip3_result['oip3_dbm']:.1f} dBm")
# Calculate SFDR
sfdr_result = sfdr_from_iip3(
iip3_dbm=iip3_result['iip3_dbm'],
noise_floor_dbm_hz=-170, # -174 dBm/Hz + 4 dB NF
bandwidth_hz=10e6,
)
print(f"SFDR: {sfdr_result['sfdr_db']:.1f} dB")
Minimum Detectable Signal¶
from phased_array_systems.models.rf import mds_from_noise_figure
result = mds_from_noise_figure(
noise_figure_db=3,
bandwidth_hz=1e6,
snr_required_db=10,
)
print(f"MDS: {result['mds_dbm']:.1f} dBm")
print(f"Noise Floor: {result['noise_floor_dbm']:.1f} dBm")
print(f"kTB: {result['ktb_dbm']:.1f} dBm")
Complete RF Chain Analysis¶
from phased_array_systems.models.rf import RFStage, cascade_analysis
# Define receiver chain
stages = [
RFStage("LNA", gain_db=20, noise_figure_db=1.5, iip3_dbm=-5),
RFStage("BPF", gain_db=-2, noise_figure_db=2, iip3_dbm=30),
RFStage("Mixer", gain_db=-8, noise_figure_db=8, iip3_dbm=15),
RFStage("IF Amp", gain_db=30, noise_figure_db=4, iip3_dbm=10),
RFStage("ADC Driver", gain_db=10, noise_figure_db=6, iip3_dbm=20),
]
result = cascade_analysis(
stages=stages,
bandwidth_hz=10e6,
input_power_dbm=-60,
)
print(f"System NF: {result['total_nf_db']:.2f} dB")
print(f"System Gain: {result['total_gain_db']:.1f} dB")
print(f"IIP3: {result['iip3_dbm']:.1f} dBm")
print(f"SFDR: {result['sfdr_db']:.1f} dB")
print(f"MDS: {result['mds_dbm']:.1f} dBm")
print(f"Output Power: {result['output_power_dbm']:.1f} dBm")
Key Equations¶
Friis Noise Figure¶
Noise Figure to Temperature¶
Where \(T_0 = 290\) K (reference temperature).
Cascaded IIP3¶
Spurious-Free Dynamic Range¶
Minimum Detectable Signal¶
Where \(kT = -174\) dBm/Hz at 290 K.
Design Guidelines¶
LNA Placement¶
The Friis equation shows why low-noise amplifiers (LNAs) must be placed first:
- First stage dominates system noise figure
- High gain in first stage reduces impact of subsequent stages
- Trade-off: high-gain LNA can degrade linearity
Typical NF Budget¶
| Stage | Typical NF | Typical Gain |
|---|---|---|
| LNA | 1-3 dB | 15-25 dB |
| Filter | 1-3 dB | -1 to -3 dB |
| Mixer | 6-10 dB | -6 to -10 dB |
| IF Amp | 3-6 dB | 20-40 dB |
Dynamic Range Considerations¶
- IIP3 limited by early high-gain stages
- SFDR balances noise and linearity
- Back-off from P1dB typically 10-12 dB below IIP3
See Also¶
- Digital Models - ADC/DAC and digital beamforming
- Communications Models - Link budget calculations
- Theory: Link Budget Equations