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, Any]
|
Dictionary with: - total_nf_db: Cascaded noise figure in dB - total_gain_db: Cascaded gain in dB - noise_temp_k: Equivalent noise temperature - stage_contribution_pct: Each stage's share of the total excess noise factor (F_total - 1); sums to 100 - stage_nf_delta_db: dB of total NF saved if that stage were noiseless (0 dB NF, same gain) |
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
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | |
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