Skip to content

Architecture API

System configuration classes for defining phased array architectures.

Overview

from phased_array_systems.architecture import (
    Architecture,
    ArrayConfig,
    RFChainConfig,
    CostConfig,
)

Classes

ArrayConfig

Bases: BaseModel

Configuration for the antenna array geometry.

ATTRIBUTE DESCRIPTION
geometry

Array geometry type

TYPE: Literal['rectangular', 'circular', 'triangular']

nx

Number of elements in x-direction

TYPE: int

ny

Number of elements in y-direction

TYPE: int

dx_lambda

Element spacing in x-direction (wavelengths)

TYPE: float

dy_lambda

Element spacing in y-direction (wavelengths)

TYPE: float

scan_limit_deg

Maximum scan angle from boresight (degrees)

TYPE: float

max_subarray_nx

Maximum elements per sub-array in x (must be power of 2)

TYPE: int

max_subarray_ny

Maximum elements per sub-array in y (must be power of 2)

TYPE: int

enforce_subarray_constraint

Whether to enforce power-of-two sub-array constraint

TYPE: bool

n_elements property

n_elements: int

Total number of elements in the array.

subarray_nx property

subarray_nx: int

Actual elements per sub-array in x-direction.

subarray_ny property

subarray_ny: int

Actual elements per sub-array in y-direction.

n_subarrays_x property

n_subarrays_x: int

Number of sub-arrays in x-direction.

n_subarrays_y property

n_subarrays_y: int

Number of sub-arrays in y-direction.

n_subarrays property

n_subarrays: int

Total number of sub-arrays.

elements_per_subarray property

elements_per_subarray: int

Number of elements per sub-array.

validate_power_of_two classmethod

validate_power_of_two(v: int) -> int

Validate that max sub-array dimensions are powers of two.

Source code in src/phased_array_systems/architecture/config.py
@field_validator("max_subarray_nx", "max_subarray_ny")
@classmethod
def validate_power_of_two(cls, v: int) -> int:
    """Validate that max sub-array dimensions are powers of two."""
    if not is_power_of_two(v):
        raise ValueError(
            f"max_subarray value {v} must be a power of 2 "
            f"(valid values: {VALID_POWERS_OF_TWO})"
        )
    return v

validate_subarray_constraints

validate_subarray_constraints() -> ArrayConfig

Validate that array dimensions result in power-of-two sub-arrays.

Source code in src/phased_array_systems/architecture/config.py
@model_validator(mode="after")
def validate_subarray_constraints(self) -> "ArrayConfig":
    """Validate that array dimensions result in power-of-two sub-arrays."""
    if not self.enforce_subarray_constraint:
        return self

    if self.geometry != "rectangular":
        # Sub-array constraints only apply to rectangular arrays for now
        return self

    # Check x-direction
    if self.nx > self.max_subarray_nx:
        # Must be divisible by max_subarray_nx
        if self.nx % self.max_subarray_nx != 0:
            raise ValueError(
                f"nx={self.nx} must be divisible by max_subarray_nx={self.max_subarray_nx} "
                f"for arrays larger than max sub-array size. "
                f"Set enforce_subarray_constraint=False to disable."
            )
    else:
        # Small array: nx itself must be power of two
        if not is_power_of_two(self.nx):
            raise ValueError(
                f"nx={self.nx} must be a power of 2 (2, 4, 8, 16, ...) when "
                f"enforce_subarray_constraint=True. Valid values: {VALID_POWERS_OF_TWO}"
            )

    # Check y-direction
    if self.ny > self.max_subarray_ny:
        # Must be divisible by max_subarray_ny
        if self.ny % self.max_subarray_ny != 0:
            raise ValueError(
                f"ny={self.ny} must be divisible by max_subarray_ny={self.max_subarray_ny} "
                f"for arrays larger than max sub-array size. "
                f"Set enforce_subarray_constraint=False to disable."
            )
    else:
        # Small array: ny itself must be power of two
        if not is_power_of_two(self.ny):
            raise ValueError(
                f"ny={self.ny} must be a power of 2 (2, 4, 8, 16, ...) when "
                f"enforce_subarray_constraint=True. Valid values: {VALID_POWERS_OF_TWO}"
            )

    return self

RFChainConfig

Bases: BaseModel

Configuration for the RF chain.

ATTRIBUTE DESCRIPTION
tx_power_w_per_elem

Transmit power per element (Watts)

TYPE: float

pa_efficiency

Power amplifier efficiency (0-1)

TYPE: float

noise_figure_db

Receiver noise figure (dB)

TYPE: float

n_tx_beams

Number of simultaneous transmit beams

TYPE: int

feed_loss_db

Feed network loss (dB)

TYPE: float

system_loss_db

Additional system losses (dB)

TYPE: float

CostConfig

Bases: BaseModel

Configuration for cost modeling.

ATTRIBUTE DESCRIPTION
cost_per_elem_usd

Recurring cost per element (USD)

TYPE: float

nre_usd

Non-recurring engineering cost (USD)

TYPE: float

integration_cost_usd

System integration cost (USD)

TYPE: float

Architecture

Bases: BaseModel

Complete system architecture configuration.

This is the top-level configuration object that contains all subsystem configurations.

ATTRIBUTE DESCRIPTION
array

Antenna array configuration

TYPE: ArrayConfig

rf

RF chain configuration

TYPE: RFChainConfig

cost

Cost model configuration

TYPE: CostConfig

name

Optional name for this architecture

TYPE: str | None

n_elements property

n_elements: int

Total number of elements (convenience property).

model_dump_flat

model_dump_flat() -> dict

Return a flattened dictionary of all configuration values.

Useful for DOE case generation where we need flat parameter names.

Source code in src/phased_array_systems/architecture/config.py
def model_dump_flat(self) -> dict:
    """Return a flattened dictionary of all configuration values.

    Useful for DOE case generation where we need flat parameter names.
    """
    flat = {}
    for prefix, config in [
        ("array", self.array),
        ("rf", self.rf),
        ("cost", self.cost),
    ]:
        for key, value in config.model_dump().items():
            flat[f"{prefix}.{key}"] = value
    if self.name:
        flat["name"] = self.name
    return flat

from_flat classmethod

from_flat(flat_dict: dict) -> Architecture

Create an Architecture from a flattened dictionary.

PARAMETER DESCRIPTION
flat_dict

Dictionary with keys like "array.nx", "rf.tx_power_w_per_elem"

TYPE: dict

RETURNS DESCRIPTION
Architecture

Architecture instance

Source code in src/phased_array_systems/architecture/config.py
@classmethod
def from_flat(cls, flat_dict: dict) -> "Architecture":
    """Create an Architecture from a flattened dictionary.

    Args:
        flat_dict: Dictionary with keys like "array.nx", "rf.tx_power_w_per_elem"

    Returns:
        Architecture instance
    """
    array_dict = {}
    rf_dict = {}
    cost_dict = {}
    name = None

    for key, value in flat_dict.items():
        if key == "name":
            name = value
        elif key.startswith("array."):
            array_dict[key.replace("array.", "")] = value
        elif key.startswith("rf."):
            rf_dict[key.replace("rf.", "")] = value
        elif key.startswith("cost."):
            cost_dict[key.replace("cost.", "")] = value

    return cls(
        array=ArrayConfig(**array_dict),
        rf=RFChainConfig(**rf_dict),
        cost=CostConfig(**cost_dict) if cost_dict else CostConfig(),
        name=name,
    )

Helper Functions

is_power_of_two

is_power_of_two(n: int) -> bool

Check if n is a power of two (and >= 2).

Source code in src/phased_array_systems/architecture/config.py
def is_power_of_two(n: int) -> bool:
    """Check if n is a power of two (and >= 2)."""
    return n >= 2 and (n & (n - 1)) == 0

Constants

# Valid sub-array dimensions (powers of 2)
VALID_POWERS_OF_TWO = [2, 4, 8, 16, 32, 64, 128, 256, 512]

Usage Examples

Basic Architecture

from phased_array_systems.architecture import (
    Architecture, ArrayConfig, RFChainConfig, CostConfig
)

arch = Architecture(
    array=ArrayConfig(nx=8, ny=8, dx_lambda=0.5, dy_lambda=0.5),
    rf=RFChainConfig(tx_power_w_per_elem=1.0, pa_efficiency=0.3),
    cost=CostConfig(cost_per_elem_usd=100.0),
    name="Baseline Design",
)

print(f"Elements: {arch.n_elements}")
print(f"Sub-arrays: {arch.array.n_subarrays}")

Flattening for DOE

# Convert to flat dictionary
flat = arch.model_dump_flat()
# {'array.nx': 8, 'array.ny': 8, 'array.dx_lambda': 0.5, ...}

# Reconstruct from flat dictionary
arch2 = Architecture.from_flat(flat)

Validation Examples

# This raises ValidationError - nx must be >= 1
ArrayConfig(nx=0, ny=8)

# This raises ValidationError - efficiency must be 0-1
RFChainConfig(tx_power_w_per_elem=1.0, pa_efficiency=1.5)

# This raises ValidationError - not power of 2
ArrayConfig(nx=6, ny=6, enforce_subarray_constraint=True)

# This works - constraint disabled
ArrayConfig(nx=6, ny=6, enforce_subarray_constraint=False)

See Also