Skip to content

SWaP-C Models API

Size, Weight, Power, and Cost models.

Overview

from phased_array_systems.models.swapc import PowerModel, CostModel

Classes

PowerModel

PowerModel(overhead_factor: float = 0.2)

Power consumption calculator for phased array systems.

Computes DC power, RF power, and prime power based on architecture parameters and efficiency factors.

Power Equations

RF_peak = n_elements * tx_power_per_elem RF_avg = RF_peak * duty_cycle PA_DC = RF_avg / pa_efficiency RX_DC = n_elements * rx_power_w_per_elem ADC = n_digital_channels * FOM * 2^ENOB * fs DSP = beamformer_GOPS / dsp_efficiency DC_power = PA_DC + RX_DC + ADC + DSP Prime_power = DC_power * (1 + overhead_factor)

ATTRIBUTE DESCRIPTION
name

Model block name for identification

TYPE: str

overhead_factor

Additional power overhead (cooling, control, etc.)

Initialize power model.

PARAMETER DESCRIPTION
overhead_factor

Fraction of DC power for overhead (default 20%)

TYPE: float DEFAULT: 0.2

Source code in src/phased_array_systems/models/swapc/power.py
def __init__(self, overhead_factor: float = 0.2):
    """Initialize power model.

    Args:
        overhead_factor: Fraction of DC power for overhead (default 20%)
    """
    self.overhead_factor = overhead_factor

evaluate

evaluate(arch: Architecture, scenario: Scenario, context: dict[str, Any]) -> MetricsDict

Evaluate power metrics.

PARAMETER DESCRIPTION
arch

Architecture configuration

TYPE: Architecture

scenario

Scenario (duty_cycle and bandwidth_hz are read if present)

TYPE: Scenario

context

Additional context (unused)

TYPE: dict[str, Any]

RETURNS DESCRIPTION
MetricsDict

Dictionary with power metrics: - rf_power_w: Peak RF output power (W) - rf_avg_power_w: Average RF output power (W) - pa_dc_power_w: PA DC power (W) - rx_dc_power_w: Receive chain DC power (W) - adc_power_w: Total ADC power (W) - dsp_power_w: Digital beamformer power (W) - dc_power_w: Total DC power consumption (W) - prime_power_w: Prime/wall power (W) - duty_cycle: Transmit duty cycle - pa_efficiency: Power amplifier efficiency - n_elements: Number of array elements - heat_dissipation_w: Heat to remove (DC in minus RF out)

MetricsDict

When the scenario carries a frequency, also: - wavelength_m, cell_area_cm2, aperture_area_m2 - heat_flux_w_per_cm2: dissipation per aperture area (average) - radiated_power_density_peak_w_per_cm2 - radiated_power_density_avg_w_per_cm2

Source code in src/phased_array_systems/models/swapc/power.py
def evaluate(
    self,
    arch: Architecture,
    scenario: Scenario,
    context: dict[str, Any],
) -> MetricsDict:
    """Evaluate power metrics.

    Args:
        arch: Architecture configuration
        scenario: Scenario (duty_cycle and bandwidth_hz are read if present)
        context: Additional context (unused)

    Returns:
        Dictionary with power metrics:
            - rf_power_w: Peak RF output power (W)
            - rf_avg_power_w: Average RF output power (W)
            - pa_dc_power_w: PA DC power (W)
            - rx_dc_power_w: Receive chain DC power (W)
            - adc_power_w: Total ADC power (W)
            - dsp_power_w: Digital beamformer power (W)
            - dc_power_w: Total DC power consumption (W)
            - prime_power_w: Prime/wall power (W)
            - duty_cycle: Transmit duty cycle
            - pa_efficiency: Power amplifier efficiency
            - n_elements: Number of array elements
            - heat_dissipation_w: Heat to remove (DC in minus RF out)
        When the scenario carries a frequency, also:
            - wavelength_m, cell_area_cm2, aperture_area_m2
            - heat_flux_w_per_cm2: dissipation per aperture area (average)
            - radiated_power_density_peak_w_per_cm2
            - radiated_power_density_avg_w_per_cm2
    """
    n_elements = arch.array.n_elements
    tx_power_per_elem = arch.rf.tx_power_w_per_elem
    pa_efficiency = arch.rf.pa_efficiency
    duty_cycle = getattr(scenario, "duty_cycle", 1.0)

    # RF power: peak for the radar equation, average for the DC budget
    rf_power_w = n_elements * tx_power_per_elem
    rf_avg_power_w = rf_power_w * duty_cycle

    # PA DC power (accounting for PA efficiency)
    pa_dc_power_w = rf_avg_power_w / pa_efficiency

    # Receive chain DC power (LNA, phase shifter, control per element)
    rx_dc_power_w = n_elements * arch.rf.rx_power_w_per_elem

    # Digital section power (ADCs + DACs + beamformer compute)
    adc_power = 0.0
    dac_power = 0.0
    dsp_power = 0.0
    if arch.digital is not None:
        from phased_array_systems.models.digital.bandwidth import beamformer_operations
        from phased_array_systems.models.digital.converters import adc_power_w

        bandwidth_hz = getattr(scenario, "bandwidth_hz", 1e6)
        sample_rate_hz = bandwidth_hz * arch.digital.oversampling_ratio
        n_channels = arch.n_digital_channels

        adc_power = n_channels * adc_power_w(
            arch.digital.adc_enob, sample_rate_hz, arch.digital.adc_fom_fj
        )
        if arch.digital.dac_enob is not None:
            # Walden-form estimate applied to the DAC; same caveats as
            # for the ADC (survey-level scaling, not a datasheet number)
            dac_power = n_channels * adc_power_w(
                arch.digital.dac_enob, sample_rate_hz, arch.digital.dac_fom_fj
            )
        ops = beamformer_operations(n_channels, arch.digital.n_beams, sample_rate_hz)
        dsp_power = ops["total_gops"] / arch.digital.dsp_efficiency_gops_per_w

    dc_power_w = pa_dc_power_w + rx_dc_power_w + adc_power + dac_power + dsp_power

    # Prime power (including overhead)
    prime_power_w = dc_power_w * (1 + self.overhead_factor)

    # Heat to remove, from the single shared energy balance. The average
    # RF term is the right one here: what leaves as radiation over a
    # duty cycle does not heat the array.
    thermal = compute_thermal_load(dc_power_w, rf_avg_power_w)

    # Aperture power densities. Heat flux uses AVERAGE power because the
    # cold plate's time constant (seconds) is far longer than the PRI
    # (microseconds), so the plate sees the duty-cycle-averaged load.
    # The junction does not average that way; PAS has no thermal
    # transient model and does not claim a peak junction flux.
    density: dict[str, float] = {}
    try:
        geom = aperture_geometry(arch, scenario)
    except ValueError:
        geom = {}
    if geom:
        aperture_cm2 = geom["aperture_area_cm2"]
        density = {
            "wavelength_m": geom["wavelength_m"],
            "cell_area_cm2": geom["cell_area_cm2"],
            "aperture_area_m2": geom["aperture_area_m2"],
            "heat_flux_w_per_cm2": thermal["heat_dissipation_w"] / aperture_cm2,
            "radiated_power_density_peak_w_per_cm2": rf_power_w / aperture_cm2,
            "radiated_power_density_avg_w_per_cm2": rf_avg_power_w / aperture_cm2,
        }

    return {
        "rf_power_w": rf_power_w,
        "rf_avg_power_w": rf_avg_power_w,
        "pa_dc_power_w": pa_dc_power_w,
        "rx_dc_power_w": rx_dc_power_w,
        "adc_power_w": adc_power,
        "dac_power_w": dac_power,
        "dsp_power_w": dsp_power,
        "dc_power_w": dc_power_w,
        "prime_power_w": prime_power_w,
        "duty_cycle": duty_cycle,
        "pa_efficiency": pa_efficiency,
        "n_elements": n_elements,
        "heat_dissipation_w": thermal["heat_dissipation_w"],
        **density,
    }

CostModel

Parametric cost model for phased array systems.

Computes recurring and non-recurring costs based on array size and cost parameters.

Cost Equations

Recurring_cost = n_elements * cost_per_element Total_cost = Recurring_cost + NRE + Integration

ATTRIBUTE DESCRIPTION
name

Model block name for identification

TYPE: str

evaluate

evaluate(arch: Architecture, scenario: Scenario, context: dict[str, Any]) -> MetricsDict

Evaluate cost metrics.

PARAMETER DESCRIPTION
arch

Architecture configuration

TYPE: Architecture

scenario

Scenario (unused for basic cost model)

TYPE: Scenario

context

Additional context (unused)

TYPE: dict[str, Any]

RETURNS DESCRIPTION
MetricsDict

Dictionary with cost metrics: - recurring_cost_usd: Element-based recurring cost (USD) - nre_usd: Non-recurring engineering cost (USD) - integration_cost_usd: System integration cost (USD) - total_cost_usd: Total system cost (USD) - cost_per_element_usd: Cost per element (USD) - n_elements: Number of elements

Source code in src/phased_array_systems/models/swapc/cost.py
def evaluate(
    self,
    arch: Architecture,
    scenario: Scenario,
    context: dict[str, Any],
) -> MetricsDict:
    """Evaluate cost metrics.

    Args:
        arch: Architecture configuration
        scenario: Scenario (unused for basic cost model)
        context: Additional context (unused)

    Returns:
        Dictionary with cost metrics:
            - recurring_cost_usd: Element-based recurring cost (USD)
            - nre_usd: Non-recurring engineering cost (USD)
            - integration_cost_usd: System integration cost (USD)
            - total_cost_usd: Total system cost (USD)
            - cost_per_element_usd: Cost per element (USD)
            - n_elements: Number of elements
    """
    n_elements = arch.array.n_elements
    cost_per_elem = arch.cost.cost_per_elem_usd
    nre = arch.cost.nre_usd
    integration = arch.cost.integration_cost_usd

    # Recurring cost (scales with elements)
    recurring_cost = n_elements * cost_per_elem

    # Total cost
    total_cost = recurring_cost + nre + integration

    return {
        "recurring_cost_usd": recurring_cost,
        "nre_usd": nre,
        "integration_cost_usd": integration,
        "total_cost_usd": total_cost,
        "cost_per_element_usd": cost_per_elem,
        "cost_usd": total_cost,  # Canonical metric name
        "n_elements": n_elements,
    }

Functions

compute_thermal_load

compute_thermal_load(dc_power_w: float, rf_power_w: float, additional_dissipation_w: float = 0.0) -> dict[str, float]

Compute thermal dissipation for heat management.

The single energy balance in the package: PowerModel calls it for heat_dissipation_w, and the junction-temperature feed-forward in evaluate consumes that metric rather than recomputing it.

PARAMETER DESCRIPTION
dc_power_w

Total DC power consumption (W)

TYPE: float

rf_power_w

RF power leaving as radiation (W). Pass the duty-cycle average for a thermal budget; passing peak overstates the radiated fraction and understates the heat.

TYPE: float

additional_dissipation_w

Other heat sources (W)

TYPE: float DEFAULT: 0.0

RETURNS DESCRIPTION
dict[str, float]

Dictionary with thermal metrics: - heat_dissipation_w: Total heat to remove (W) - rf_efficiency: Fraction of DC converted to RF

Source code in src/phased_array_systems/models/swapc/power.py
def compute_thermal_load(
    dc_power_w: float,
    rf_power_w: float,
    additional_dissipation_w: float = 0.0,
) -> dict[str, float]:
    """Compute thermal dissipation for heat management.

    The single energy balance in the package: ``PowerModel`` calls it for
    ``heat_dissipation_w``, and the junction-temperature feed-forward in
    ``evaluate`` consumes that metric rather than recomputing it.

    Args:
        dc_power_w: Total DC power consumption (W)
        rf_power_w: RF power leaving as radiation (W). Pass the duty-cycle
            average for a thermal budget; passing peak overstates the
            radiated fraction and understates the heat.
        additional_dissipation_w: Other heat sources (W)

    Returns:
        Dictionary with thermal metrics:
            - heat_dissipation_w: Total heat to remove (W)
            - rf_efficiency: Fraction of DC converted to RF
    """
    # Heat = DC input - RF output + additional sources
    heat_dissipation_w = dc_power_w - rf_power_w + additional_dissipation_w
    rf_efficiency = rf_power_w / dc_power_w if dc_power_w > 0 else 0.0

    return {
        "heat_dissipation_w": heat_dissipation_w,
        "rf_efficiency": rf_efficiency,
    }

compute_cost_per_watt

compute_cost_per_watt(total_cost_usd: float, rf_power_w: float) -> float

Compute cost per Watt of RF power.

PARAMETER DESCRIPTION
total_cost_usd

Total system cost (USD)

TYPE: float

rf_power_w

RF output power (W)

TYPE: float

RETURNS DESCRIPTION
float

Cost per Watt (USD/W)

Source code in src/phased_array_systems/models/swapc/cost.py
def compute_cost_per_watt(total_cost_usd: float, rf_power_w: float) -> float:
    """Compute cost per Watt of RF power.

    Args:
        total_cost_usd: Total system cost (USD)
        rf_power_w: RF output power (W)

    Returns:
        Cost per Watt (USD/W)
    """
    if rf_power_w <= 0:
        return float("inf")
    return total_cost_usd / rf_power_w
options:
  show_root_heading: true

Output Metrics

Power Metrics

Metric Units Description
rf_power_w W Total RF power (all elements)
dc_power_w W DC power (RF / PA efficiency)
heat_dissipation_w Heat to remove (DC in minus average RF out)
heat_flux_w_per_cm2 Dissipated power per aperture area (average power)
radiated_power_density_peak_w_per_cm2 Radiated power per aperture area, peak
radiated_power_density_avg_w_per_cm2 Radiated power per aperture area, average
aperture_area_m2, cell_area_cm2 Physical aperture and unit-cell area
prime_power_w W Total prime power

Cost Metrics

Metric Units Description
recurring_cost_usd USD Element cost × count
nre_cost_usd USD Non-recurring engineering
integration_cost_usd USD System integration
cost_usd USD Total cost

Usage Examples

Power Calculation

from phased_array_systems.models.swapc import PowerModel

# Using PowerModel
model = PowerModel()
metrics = model.evaluate(arch, scenario, context={})
print(f"Prime Power: {metrics['prime_power_w']:.0f} W")
print(f"RF Power: {metrics['rf_power_w']:.0f} W")
print(f"DC Power: {metrics['dc_power_w']:.0f} W")

Cost Calculation

from phased_array_systems.models.swapc import CostModel

# Using CostModel
model = CostModel()
metrics = model.evaluate(arch, scenario, context={})
print(f"Total Cost: ${metrics['cost_usd']:,.0f}")
print(f"Recurring: ${metrics['recurring_cost_usd']:,.0f}")
print(f"NRE: ${metrics['nre_cost_usd']:,.0f}")

Cost Analysis Utilities

from phased_array_systems.models.swapc.cost import compute_cost_per_watt

# Cost efficiency metrics
cost_per_watt = compute_cost_per_watt(total_cost_usd=50000, rf_power_w=100)

print(f"Cost per Watt: ${cost_per_watt:.0f}/W")

Power Equations

RF Power

\[ P_{RF} = P_{elem} \times N \]

DC Power

\[ P_{DC} = \frac{P_{RF}}{\eta_{PA}} \]

Prime Power

Prime power includes additional overhead (typically DC power plus auxiliaries):

\[ P_{prime} = P_{DC} \times (1 + overhead) \]

Cost Equations

Recurring Cost

\[ C_{recurring} = C_{elem} \times N \]

Total Cost

\[ C_{total} = C_{recurring} + C_{NRE} + C_{integration} \]

Trade-offs

Power vs. Array Size

# Power scales linearly with element count
# For constant EIRP, larger arrays need less power per element

# 8x8 at 1W each: P = 64W RF
# 16x16 at 0.25W each: P = 64W RF, but 6dB more gain from aperture

Cost vs. Performance

# Cost scaling factors:
# - Element count: linear
# - Power per element: typically superlinear
# - Frequency: higher frequency = higher cost per element

See Also