Skip to content

Requirements API

Requirements definition and verification classes.

Overview

from phased_array_systems.requirements import (
    Requirement,
    RequirementResult,
    RequirementSet,
    VerificationReport,
)

Classes

Requirement dataclass

Requirement(id: str, name: str, metric_key: str, op: ComparisonOp, value: float, units: str | None = None, severity: Severity = 'must')

A single requirement specification.

ATTRIBUTE DESCRIPTION
id

Unique identifier for the requirement (e.g., "REQ-001")

TYPE: str

name

Human-readable name

TYPE: str

metric_key

The key in the metrics dictionary to check

TYPE: str

op

Comparison operator

TYPE: ComparisonOp

value

Threshold value to compare against

TYPE: float

units

Optional units string for documentation

TYPE: str | None

severity

Importance level ("must", "should", "nice")

TYPE: Severity

check

check(actual_value: float) -> bool

Check if the actual value satisfies this requirement.

PARAMETER DESCRIPTION
actual_value

The measured/computed value to check

TYPE: float

RETURNS DESCRIPTION
bool

True if requirement is satisfied, False otherwise

Source code in src/phased_array_systems/requirements/core.py
def check(self, actual_value: float) -> bool:
    """Check if the actual value satisfies this requirement.

    Args:
        actual_value: The measured/computed value to check

    Returns:
        True if requirement is satisfied, False otherwise
    """
    if self.op == ">=":
        return actual_value >= self.value
    elif self.op == "<=":
        return actual_value <= self.value
    elif self.op == "==":
        return actual_value == self.value
    elif self.op == ">":
        return actual_value > self.value
    elif self.op == "<":
        return actual_value < self.value
    else:
        raise ValueError(f"Unknown operator: {self.op}")

compute_margin

compute_margin(actual_value: float) -> float

Compute the margin to the requirement threshold.

Positive margin means the requirement is satisfied with room to spare. Negative margin means the requirement is not met.

PARAMETER DESCRIPTION
actual_value

The measured/computed value

TYPE: float

RETURNS DESCRIPTION
float

Margin value (interpretation depends on operator)

Source code in src/phased_array_systems/requirements/core.py
def compute_margin(self, actual_value: float) -> float:
    """Compute the margin to the requirement threshold.

    Positive margin means the requirement is satisfied with room to spare.
    Negative margin means the requirement is not met.

    Args:
        actual_value: The measured/computed value

    Returns:
        Margin value (interpretation depends on operator)
    """
    if self.op in (">=", ">"):
        return actual_value - self.value
    elif self.op in ("<=", "<"):
        return self.value - actual_value
    else:  # ==
        return -abs(actual_value - self.value)

RequirementResult dataclass

RequirementResult(requirement: Requirement, actual_value: float | None, passes: bool, margin: float | None, error: str | None = None)

Result of checking a single requirement.

ATTRIBUTE DESCRIPTION
requirement

The requirement that was checked

TYPE: Requirement

actual_value

The actual value from metrics (None if metric missing)

TYPE: float | None

passes

Whether the requirement passed

TYPE: bool

margin

Margin to the threshold

TYPE: float | None

error

Error message if metric was missing or check failed

TYPE: str | None

RequirementSet dataclass

RequirementSet(requirements: list[Requirement] = list(), name: str | None = None)

A collection of requirements with verification capabilities.

ATTRIBUTE DESCRIPTION
requirements

List of requirements

TYPE: list[Requirement]

name

Optional name for the requirement set

TYPE: str | None

add

add(requirement: Requirement) -> None

Add a requirement to the set.

Source code in src/phased_array_systems/requirements/core.py
def add(self, requirement: Requirement) -> None:
    """Add a requirement to the set."""
    self.requirements.append(requirement)

verify

verify(metrics: MetricsDict) -> VerificationReport

Verify all requirements against provided metrics.

PARAMETER DESCRIPTION
metrics

Dictionary of metric_name -> value

TYPE: MetricsDict

RETURNS DESCRIPTION
VerificationReport

VerificationReport with pass/fail status and margins

Source code in src/phased_array_systems/requirements/core.py
def verify(self, metrics: MetricsDict) -> VerificationReport:
    """Verify all requirements against provided metrics.

    Args:
        metrics: Dictionary of metric_name -> value

    Returns:
        VerificationReport with pass/fail status and margins
    """
    results: list[RequirementResult] = []
    failed_ids: list[str] = []
    must_pass = 0
    must_total = 0
    should_pass = 0
    should_total = 0

    for req in self.requirements:
        # Track totals by severity
        if req.severity == "must":
            must_total += 1
        elif req.severity == "should":
            should_total += 1

        # Check if metric exists
        if req.metric_key not in metrics:
            result = RequirementResult(
                requirement=req,
                actual_value=None,
                passes=False,
                margin=None,
                error=f"Metric '{req.metric_key}' not found in results",
            )
            failed_ids.append(req.id)
        else:
            actual = metrics[req.metric_key]
            if actual is None or not isinstance(actual, (int, float)):
                result = RequirementResult(
                    requirement=req,
                    actual_value=None,
                    passes=False,
                    margin=None,
                    error=f"Metric '{req.metric_key}' has invalid value: {actual}",
                )
                failed_ids.append(req.id)
            else:
                actual_float = float(actual)
                passes = req.check(actual_float)
                margin = req.compute_margin(actual_float)
                result = RequirementResult(
                    requirement=req,
                    actual_value=actual_float,
                    passes=passes,
                    margin=margin,
                )
                if not passes:
                    failed_ids.append(req.id)
                else:
                    if req.severity == "must":
                        must_pass += 1
                    elif req.severity == "should":
                        should_pass += 1

        results.append(result)

    # Overall pass requires all "must" requirements to pass
    all_must_pass = must_pass == must_total

    return VerificationReport(
        passes=all_must_pass,
        results=results,
        failed_ids=failed_ids,
        must_pass_count=must_pass,
        must_total_count=must_total,
        should_pass_count=should_pass,
        should_total_count=should_total,
    )

get_by_id

get_by_id(req_id: str) -> Requirement | None

Get a requirement by its ID.

Source code in src/phased_array_systems/requirements/core.py
def get_by_id(self, req_id: str) -> Requirement | None:
    """Get a requirement by its ID."""
    for req in self.requirements:
        if req.id == req_id:
            return req
    return None

VerificationReport dataclass

VerificationReport(passes: bool, results: list[RequirementResult], failed_ids: list[str], must_pass_count: int = 0, must_total_count: int = 0, should_pass_count: int = 0, should_total_count: int = 0)

Complete verification report for a set of requirements.

ATTRIBUTE DESCRIPTION
passes

True if ALL 'must' requirements pass

TYPE: bool

results

List of individual requirement results

TYPE: list[RequirementResult]

failed_ids

List of requirement IDs that failed

TYPE: list[str]

must_pass_count

Number of must requirements that passed

TYPE: int

must_total_count

Total number of must requirements

TYPE: int

should_pass_count

Number of should requirements that passed

TYPE: int

should_total_count

Total number of should requirements

TYPE: int

to_dict

to_dict() -> dict

Convert report to dictionary for serialization.

Source code in src/phased_array_systems/requirements/core.py
def to_dict(self) -> dict:
    """Convert report to dictionary for serialization."""
    return {
        "passes": self.passes,
        "failed_ids": self.failed_ids,
        "must_pass_count": self.must_pass_count,
        "must_total_count": self.must_total_count,
        "should_pass_count": self.should_pass_count,
        "should_total_count": self.should_total_count,
        "results": [
            {
                "id": r.requirement.id,
                "name": r.requirement.name,
                "metric_key": r.requirement.metric_key,
                "threshold": r.requirement.value,
                "operator": r.requirement.op,
                "actual_value": r.actual_value,
                "passes": r.passes,
                "margin": r.margin,
                "severity": r.requirement.severity,
                "error": r.error,
            }
            for r in self.results
        ],
    }

Usage Examples

Defining Requirements

from phased_array_systems.requirements import Requirement, RequirementSet

# Create individual requirements
req1 = Requirement(
    id="REQ-001",
    name="Minimum EIRP",
    metric_key="eirp_dbw",
    op=">=",
    value=40.0,
    units="dBW",
    severity="must",
)

req2 = Requirement(
    id="REQ-002",
    name="Positive Link Margin",
    metric_key="link_margin_db",
    op=">=",
    value=0.0,
    severity="must",
)

# Create requirement set
requirements = RequirementSet(
    requirements=[req1, req2],
    name="Communications Requirements",
)

Verifying Requirements

from phased_array_systems.evaluate import evaluate_case

metrics = evaluate_case(arch, scenario)
report = requirements.verify(metrics)

# Check overall status
print(f"Overall: {'PASS' if report.passes else 'FAIL'}")
print(f"Must: {report.must_pass_count}/{report.must_total_count}")

# Check individual requirements
for result in report.results:
    status = "PASS" if result.passes else "FAIL"
    print(f"{result.requirement.id}: {status} (margin: {result.margin:.1f})")

Checking Individual Requirements

req = Requirement("TEST", "Test", "value", ">=", 10.0)

# Check if value passes
print(req.check(15.0))  # True
print(req.check(5.0))   # False

# Compute margin
print(req.compute_margin(15.0))  # 5.0
print(req.compute_margin(5.0))   # -5.0

Serializing Reports

report = requirements.verify(metrics)
report_dict = report.to_dict()

# Contains structured verification data
import json
print(json.dumps(report_dict, indent=2))

Type Aliases

from phased_array_systems.types import ComparisonOp, Severity

# ComparisonOp = Literal[">=", "<=", ">", "<", "=="]
# Severity = Literal["must", "should", "nice"]

See Also