phased-array-systems 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. phased_array_systems/__about__.py +4 -0
  2. phased_array_systems/__init__.py +10 -0
  3. phased_array_systems/architecture/__init__.py +15 -0
  4. phased_array_systems/architecture/config.py +152 -0
  5. phased_array_systems/cli.py +25 -0
  6. phased_array_systems/constants.py +55 -0
  7. phased_array_systems/evaluate.py +136 -0
  8. phased_array_systems/io/__init__.py +13 -0
  9. phased_array_systems/io/config_loader.py +86 -0
  10. phased_array_systems/io/exporters.py +171 -0
  11. phased_array_systems/io/schema.py +145 -0
  12. phased_array_systems/models/__init__.py +5 -0
  13. phased_array_systems/models/antenna/__init__.py +15 -0
  14. phased_array_systems/models/antenna/adapter.py +190 -0
  15. phased_array_systems/models/antenna/metrics.py +166 -0
  16. phased_array_systems/models/base.py +30 -0
  17. phased_array_systems/models/comms/__init__.py +9 -0
  18. phased_array_systems/models/comms/link_budget.py +171 -0
  19. phased_array_systems/models/comms/propagation.py +84 -0
  20. phased_array_systems/models/swapc/__init__.py +9 -0
  21. phased_array_systems/models/swapc/cost.py +98 -0
  22. phased_array_systems/models/swapc/power.py +102 -0
  23. phased_array_systems/requirements/__init__.py +15 -0
  24. phased_array_systems/requirements/core.py +244 -0
  25. phased_array_systems/scenarios/__init__.py +11 -0
  26. phased_array_systems/scenarios/base.py +30 -0
  27. phased_array_systems/scenarios/comms.py +56 -0
  28. phased_array_systems/scenarios/radar.py +42 -0
  29. phased_array_systems/trades/__init__.py +16 -0
  30. phased_array_systems/trades/design_space.py +241 -0
  31. phased_array_systems/trades/doe.py +146 -0
  32. phased_array_systems/trades/pareto.py +266 -0
  33. phased_array_systems/trades/runner.py +245 -0
  34. phased_array_systems/types.py +54 -0
  35. phased_array_systems/utils/__init__.py +8 -0
  36. phased_array_systems/utils/hashing.py +70 -0
  37. phased_array_systems/viz/__init__.py +9 -0
  38. phased_array_systems/viz/plots.py +324 -0
  39. phased_array_systems-0.1.0.dist-info/METADATA +174 -0
  40. phased_array_systems-0.1.0.dist-info/RECORD +43 -0
  41. phased_array_systems-0.1.0.dist-info/WHEEL +4 -0
  42. phased_array_systems-0.1.0.dist-info/entry_points.txt +2 -0
  43. phased_array_systems-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,54 @@
1
+ """Type aliases and protocols for the phased-array-systems package."""
2
+
3
+ from typing import Any, Literal, Protocol, runtime_checkable
4
+
5
+ # Type aliases for metric dictionaries
6
+ MetricsDict = dict[str, float | str | None]
7
+
8
+ # Comparison operators for requirements
9
+ ComparisonOp = Literal[">=", "<=", "==", ">", "<"]
10
+
11
+ # Severity levels for requirements
12
+ Severity = Literal["must", "should", "nice"]
13
+
14
+ # Geometry types supported by phased-array-modeling
15
+ GeometryType = Literal["rectangular", "circular", "triangular"]
16
+
17
+ # Path loss model types
18
+ PathLossModel = Literal["fspl"]
19
+
20
+ # DOE sampling methods
21
+ SamplingMethod = Literal["grid", "random", "lhs"]
22
+
23
+ # Optimization directions
24
+ OptimizeDirection = Literal["minimize", "maximize"]
25
+
26
+
27
+ @runtime_checkable
28
+ class Scenario(Protocol):
29
+ """Protocol for scenario objects (comms, radar, etc.)."""
30
+
31
+ freq_hz: float
32
+
33
+
34
+ @runtime_checkable
35
+ class ModelBlock(Protocol):
36
+ """Protocol for model blocks that evaluate architecture/scenario combinations.
37
+
38
+ All model blocks must implement evaluate() and return a flat metrics dictionary.
39
+ """
40
+
41
+ name: str
42
+
43
+ def evaluate(self, arch: Any, scenario: Scenario, context: dict[str, Any]) -> MetricsDict:
44
+ """Evaluate the model and return metrics.
45
+
46
+ Args:
47
+ arch: Architecture configuration object
48
+ scenario: Scenario configuration object
49
+ context: Additional context (e.g., results from other models)
50
+
51
+ Returns:
52
+ Dictionary of metric_name -> value pairs
53
+ """
54
+ ...
@@ -0,0 +1,8 @@
1
+ """Utility functions for phased-array-systems."""
2
+
3
+ from phased_array_systems.utils.hashing import compute_case_id, compute_config_hash
4
+
5
+ __all__ = [
6
+ "compute_case_id",
7
+ "compute_config_hash",
8
+ ]
@@ -0,0 +1,70 @@
1
+ """Hashing utilities for stable case identification."""
2
+
3
+ import hashlib
4
+ import json
5
+ from typing import Any
6
+
7
+
8
+ def compute_config_hash(config: dict[str, Any], length: int = 8) -> str:
9
+ """Compute a stable hash for a configuration dictionary.
10
+
11
+ Uses JSON serialization with sorted keys to ensure consistent
12
+ ordering, then SHA-256 hashing.
13
+
14
+ Args:
15
+ config: Configuration dictionary
16
+ length: Number of hex characters to return
17
+
18
+ Returns:
19
+ Hexadecimal hash string
20
+ """
21
+ # Serialize with sorted keys for consistency
22
+ json_str = json.dumps(config, sort_keys=True, default=str)
23
+ hash_bytes = hashlib.sha256(json_str.encode()).hexdigest()
24
+ return hash_bytes[:length]
25
+
26
+
27
+ def compute_case_id(
28
+ case_index: int,
29
+ config: dict[str, Any] | None = None,
30
+ prefix: str = "case",
31
+ ) -> str:
32
+ """Compute a unique case identifier.
33
+
34
+ Args:
35
+ case_index: Sequential case number
36
+ config: Optional configuration to include in hash
37
+ prefix: Prefix for the case ID
38
+
39
+ Returns:
40
+ Case ID string like "case_00001" or "case_00001_a1b2c3d4"
41
+ """
42
+ base_id = f"{prefix}_{case_index:05d}"
43
+
44
+ if config is not None:
45
+ config_hash = compute_config_hash(config)
46
+ return f"{base_id}_{config_hash}"
47
+
48
+ return base_id
49
+
50
+
51
+ def dict_to_hashable(d: dict[str, Any]) -> tuple:
52
+ """Convert a dictionary to a hashable tuple representation.
53
+
54
+ Useful for using dictionaries as dictionary keys or in sets.
55
+
56
+ Args:
57
+ d: Dictionary to convert
58
+
59
+ Returns:
60
+ Tuple of (key, value) pairs, sorted by key
61
+ """
62
+ items = []
63
+ for k in sorted(d.keys()):
64
+ v = d[k]
65
+ if isinstance(v, dict):
66
+ v = dict_to_hashable(v)
67
+ elif isinstance(v, list):
68
+ v = tuple(v)
69
+ items.append((k, v))
70
+ return tuple(items)
@@ -0,0 +1,9 @@
1
+ """Visualization utilities for trade study results."""
2
+
3
+ from phased_array_systems.viz.plots import pareto_plot, scatter_matrix, trade_space_plot
4
+
5
+ __all__ = [
6
+ "pareto_plot",
7
+ "scatter_matrix",
8
+ "trade_space_plot",
9
+ ]
@@ -0,0 +1,324 @@
1
+ """Plotting functions for trade study visualization."""
2
+
3
+ from typing import Literal
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ import pandas as pd
8
+
9
+
10
+ def pareto_plot(
11
+ results: pd.DataFrame,
12
+ x: str,
13
+ y: str,
14
+ pareto_front: pd.DataFrame | None = None,
15
+ feasible_mask: pd.Series | None = None,
16
+ color_by: str | None = None,
17
+ size_by: str | None = None,
18
+ ax: plt.Axes | None = None,
19
+ title: str | None = None,
20
+ x_label: str | None = None,
21
+ y_label: str | None = None,
22
+ show_pareto_line: bool = True,
23
+ figsize: tuple[float, float] = (8, 6),
24
+ ) -> plt.Figure:
25
+ """Create a Pareto plot showing trade-offs between two objectives.
26
+
27
+ Args:
28
+ results: DataFrame with all evaluation results
29
+ x: Column name for x-axis
30
+ y: Column name for y-axis
31
+ pareto_front: Optional DataFrame with Pareto-optimal points to highlight
32
+ feasible_mask: Optional boolean Series marking feasible designs
33
+ color_by: Optional column name to color points by
34
+ size_by: Optional column name to size points by
35
+ ax: Optional existing Axes to plot on
36
+ title: Plot title
37
+ x_label: X-axis label (defaults to column name)
38
+ y_label: Y-axis label (defaults to column name)
39
+ show_pareto_line: If True, draw line connecting Pareto points
40
+ figsize: Figure size (width, height)
41
+
42
+ Returns:
43
+ matplotlib Figure object
44
+ """
45
+ if ax is None:
46
+ fig, ax = plt.subplots(figsize=figsize)
47
+ else:
48
+ fig = ax.figure
49
+
50
+ # Determine point sizes
51
+ if size_by is not None and size_by in results.columns:
52
+ sizes = results[size_by]
53
+ sizes = (sizes - sizes.min()) / (sizes.max() - sizes.min() + 1e-10) * 100 + 20
54
+ else:
55
+ sizes = 50
56
+
57
+ # Determine colors
58
+ if color_by is not None and color_by in results.columns:
59
+ colors = results[color_by]
60
+ cmap = plt.cm.viridis
61
+ else:
62
+ colors = "steelblue"
63
+ cmap = None
64
+
65
+ # Plot infeasible points (if mask provided)
66
+ if feasible_mask is not None:
67
+ infeasible = results[~feasible_mask]
68
+ if len(infeasible) > 0:
69
+ ax.scatter(
70
+ infeasible[x],
71
+ infeasible[y],
72
+ c="lightgray",
73
+ s=30,
74
+ alpha=0.5,
75
+ marker="x",
76
+ label="Infeasible",
77
+ )
78
+
79
+ # Plot all feasible points
80
+ plot_data = results[feasible_mask] if feasible_mask is not None else results
81
+
82
+ scatter = ax.scatter(
83
+ plot_data[x],
84
+ plot_data[y],
85
+ c=colors if color_by is None else plot_data[color_by],
86
+ s=sizes if isinstance(sizes, int) else plot_data[size_by] if size_by else 50,
87
+ alpha=0.7,
88
+ cmap=cmap,
89
+ label="Feasible" if feasible_mask is not None else None,
90
+ )
91
+
92
+ # Add colorbar if coloring by a metric
93
+ if color_by is not None and cmap is not None:
94
+ cbar = plt.colorbar(scatter, ax=ax)
95
+ cbar.set_label(color_by)
96
+
97
+ # Highlight Pareto front
98
+ if pareto_front is not None and len(pareto_front) > 0:
99
+ ax.scatter(
100
+ pareto_front[x],
101
+ pareto_front[y],
102
+ facecolors="none",
103
+ edgecolors="red",
104
+ s=100,
105
+ linewidths=2,
106
+ label="Pareto Optimal",
107
+ zorder=5,
108
+ )
109
+
110
+ # Draw Pareto line
111
+ if show_pareto_line and len(pareto_front) > 1:
112
+ sorted_pareto = pareto_front.sort_values(x)
113
+ ax.plot(
114
+ sorted_pareto[x],
115
+ sorted_pareto[y],
116
+ "r--",
117
+ alpha=0.5,
118
+ linewidth=1.5,
119
+ zorder=4,
120
+ )
121
+
122
+ # Labels and title
123
+ ax.set_xlabel(x_label or x)
124
+ ax.set_ylabel(y_label or y)
125
+ ax.set_title(title or f"Pareto Trade-off: {x} vs {y}")
126
+
127
+ # Legend
128
+ handles, labels = ax.get_legend_handles_labels()
129
+ if handles:
130
+ ax.legend(loc="best")
131
+
132
+ ax.grid(True, alpha=0.3)
133
+ fig.tight_layout()
134
+
135
+ return fig
136
+
137
+
138
+ def scatter_matrix(
139
+ results: pd.DataFrame,
140
+ columns: list[str],
141
+ color_by: str | None = None,
142
+ diagonal: Literal["hist", "kde"] = "hist",
143
+ figsize: tuple[float, float] | None = None,
144
+ title: str | None = None,
145
+ ) -> plt.Figure:
146
+ """Create a scatter matrix showing pairwise relationships.
147
+
148
+ Args:
149
+ results: DataFrame with evaluation results
150
+ columns: List of column names to include
151
+ color_by: Optional column name to color points by
152
+ diagonal: What to show on diagonal ("hist" or "kde")
153
+ figsize: Figure size (auto-calculated if None)
154
+ title: Overall figure title
155
+
156
+ Returns:
157
+ matplotlib Figure object
158
+ """
159
+ n = len(columns)
160
+ if figsize is None:
161
+ figsize = (n * 2.5, n * 2.5)
162
+
163
+ fig, axes = plt.subplots(n, n, figsize=figsize)
164
+
165
+ # Determine colors
166
+ if color_by is not None and color_by in results.columns:
167
+ colors = results[color_by].values
168
+ cmap = plt.cm.viridis
169
+ norm = plt.Normalize(colors.min(), colors.max())
170
+ point_colors = cmap(norm(colors))
171
+ else:
172
+ point_colors = "steelblue"
173
+
174
+ for i, col_i in enumerate(columns):
175
+ for j, col_j in enumerate(columns):
176
+ ax = axes[i, j]
177
+
178
+ if i == j:
179
+ # Diagonal: histogram or KDE
180
+ if diagonal == "hist":
181
+ ax.hist(results[col_i], bins=20, alpha=0.7, color="steelblue")
182
+ else: # kde
183
+ from scipy import stats
184
+
185
+ data = results[col_i].dropna()
186
+ if len(data) > 1:
187
+ kde = stats.gaussian_kde(data)
188
+ x_range = np.linspace(data.min(), data.max(), 100)
189
+ ax.fill_between(x_range, kde(x_range), alpha=0.5)
190
+ ax.plot(x_range, kde(x_range), color="steelblue")
191
+ else:
192
+ # Off-diagonal: scatter plot
193
+ ax.scatter(
194
+ results[col_j],
195
+ results[col_i],
196
+ c=point_colors,
197
+ s=10,
198
+ alpha=0.5,
199
+ )
200
+
201
+ # Labels on edges only
202
+ if i == n - 1:
203
+ ax.set_xlabel(col_j, fontsize=8)
204
+ else:
205
+ ax.set_xticklabels([])
206
+
207
+ if j == 0:
208
+ ax.set_ylabel(col_i, fontsize=8)
209
+ else:
210
+ ax.set_yticklabels([])
211
+
212
+ ax.tick_params(labelsize=6)
213
+
214
+ if title:
215
+ fig.suptitle(title, fontsize=12)
216
+
217
+ fig.tight_layout()
218
+ if title:
219
+ fig.subplots_adjust(top=0.95)
220
+
221
+ return fig
222
+
223
+
224
+ def trade_space_plot(
225
+ results: pd.DataFrame,
226
+ x: str,
227
+ y: str,
228
+ z: str,
229
+ feasible_mask: pd.Series | None = None,
230
+ pareto_front: pd.DataFrame | None = None,
231
+ ax: plt.Axes | None = None,
232
+ figsize: tuple[float, float] = (10, 8),
233
+ title: str | None = None,
234
+ ) -> plt.Figure:
235
+ """Create a 3D trade space visualization.
236
+
237
+ Args:
238
+ results: DataFrame with evaluation results
239
+ x: Column name for x-axis
240
+ y: Column name for y-axis
241
+ z: Column name for z-axis (color)
242
+ feasible_mask: Optional boolean mask for feasible designs
243
+ pareto_front: Optional DataFrame with Pareto-optimal points
244
+ ax: Optional existing 3D Axes
245
+ figsize: Figure size
246
+ title: Plot title
247
+
248
+ Returns:
249
+ matplotlib Figure object
250
+ """
251
+ if ax is None:
252
+ fig = plt.figure(figsize=figsize)
253
+ ax = fig.add_subplot(111, projection="3d")
254
+ else:
255
+ fig = ax.figure
256
+
257
+ # Plot points
258
+ if feasible_mask is not None:
259
+ # Infeasible
260
+ inf_data = results[~feasible_mask]
261
+ ax.scatter(
262
+ inf_data[x],
263
+ inf_data[y],
264
+ inf_data[z],
265
+ c="lightgray",
266
+ alpha=0.3,
267
+ s=20,
268
+ marker="x",
269
+ )
270
+ plot_data = results[feasible_mask]
271
+ else:
272
+ plot_data = results
273
+
274
+ scatter = ax.scatter(
275
+ plot_data[x],
276
+ plot_data[y],
277
+ plot_data[z],
278
+ c=plot_data[z],
279
+ cmap="viridis",
280
+ alpha=0.7,
281
+ s=40,
282
+ )
283
+
284
+ # Highlight Pareto front
285
+ if pareto_front is not None and len(pareto_front) > 0:
286
+ ax.scatter(
287
+ pareto_front[x],
288
+ pareto_front[y],
289
+ pareto_front[z],
290
+ c="red",
291
+ s=100,
292
+ marker="*",
293
+ label="Pareto Optimal",
294
+ zorder=5,
295
+ )
296
+ ax.legend()
297
+
298
+ ax.set_xlabel(x)
299
+ ax.set_ylabel(y)
300
+ ax.set_zlabel(z)
301
+
302
+ fig.colorbar(scatter, ax=ax, label=z, shrink=0.5)
303
+
304
+ if title:
305
+ ax.set_title(title)
306
+
307
+ return fig
308
+
309
+
310
+ def save_figure(
311
+ fig: plt.Figure,
312
+ path: str,
313
+ dpi: int = 150,
314
+ transparent: bool = False,
315
+ ) -> None:
316
+ """Save a figure to file.
317
+
318
+ Args:
319
+ fig: matplotlib Figure to save
320
+ path: Output path (extension determines format)
321
+ dpi: Resolution for raster formats
322
+ transparent: Whether to use transparent background
323
+ """
324
+ fig.savefig(path, dpi=dpi, transparent=transparent, bbox_inches="tight")
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.4
2
+ Name: phased-array-systems
3
+ Version: 0.1.0
4
+ Summary: Phased array antenna system design, optimization, and performance visualization
5
+ Project-URL: Homepage, https://github.com/jman4162/phased-array-systems
6
+ Project-URL: Documentation, https://github.com/jman4162/phased-array-systems#readme
7
+ Project-URL: Repository, https://github.com/jman4162/phased-array-systems
8
+ Project-URL: Issues, https://github.com/jman4162/phased-array-systems/issues
9
+ Author: phased-array-systems contributors
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: RF,antenna,communications,optimization,phased array,radar,system design,trade study
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering
23
+ Classifier: Topic :: Scientific/Engineering :: Physics
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: matplotlib>=3.7.0
26
+ Requires-Dist: numpy>=1.24.0
27
+ Requires-Dist: pandas>=2.0.0
28
+ Requires-Dist: phased-array-modeling>=1.2.0
29
+ Requires-Dist: pydantic>=2.0
30
+ Requires-Dist: pyyaml>=6.0
31
+ Requires-Dist: scipy>=1.10.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.0; extra == 'dev'
34
+ Requires-Dist: pandas-stubs>=2.0; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
36
+ Requires-Dist: pytest>=7.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
38
+ Provides-Extra: plotting
39
+ Requires-Dist: kaleido>=0.2; extra == 'plotting'
40
+ Requires-Dist: plotly>=5.0; extra == 'plotting'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # phased-array-systems
44
+
45
+ [![CI](https://github.com/jman4162/phased-array-systems/actions/workflows/ci.yml/badge.svg)](https://github.com/jman4162/phased-array-systems/actions/workflows/ci.yml)
46
+ [![PyPI version](https://badge.fury.io/py/phased-array-systems.svg)](https://badge.fury.io/py/phased-array-systems)
47
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
49
+
50
+ Phased array antenna system design, optimization, and performance visualization for wireless communications and radar applications.
51
+
52
+ ## Features
53
+
54
+ - **Requirements as first-class objects**: Every run produces pass/fail + margins with traceability
55
+ - **Trade-space exploration**: DOE + Pareto optimization over single-point designs
56
+ - **Flat metrics dictionary**: All models return consistent `dict[str, float]` for interchange
57
+ - **Config-driven reproducibility**: Stable case IDs, seed control, version stamping
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install phased-array-systems
63
+
64
+ # Development dependencies
65
+ pip install phased-array-systems[dev]
66
+
67
+ # Visualization extras
68
+ pip install phased-array-systems[plotting]
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ### Single Case Evaluation
74
+
75
+ ```python
76
+ from phased_array_systems.architecture import Architecture, ArrayConfig, RFChainConfig
77
+ from phased_array_systems.scenarios import CommsLinkScenario
78
+ from phased_array_systems.evaluate import evaluate_case
79
+
80
+ # Define architecture
81
+ arch = Architecture(
82
+ array=ArrayConfig(nx=8, ny=8, dx_lambda=0.5, dy_lambda=0.5),
83
+ rf=RFChainConfig(tx_power_w_per_elem=1.0, pa_efficiency=0.3),
84
+ )
85
+
86
+ # Define scenario
87
+ scenario = CommsLinkScenario(
88
+ freq_hz=10e9,
89
+ bandwidth_hz=10e6,
90
+ range_m=100e3,
91
+ required_snr_db=10.0,
92
+ )
93
+
94
+ # Evaluate
95
+ metrics = evaluate_case(arch, scenario)
96
+ print(f"EIRP: {metrics['eirp_dbw']:.1f} dBW")
97
+ print(f"Link Margin: {metrics['link_margin_db']:.1f} dB")
98
+ ```
99
+
100
+ ### DOE Trade Study
101
+
102
+ ```python
103
+ from phased_array_systems.trades import DesignSpace, generate_doe, BatchRunner, extract_pareto
104
+
105
+ # Define design space
106
+ space = (
107
+ DesignSpace()
108
+ .add_variable("array.nx", "int", low=4, high=16)
109
+ .add_variable("array.ny", "int", low=4, high=16)
110
+ .add_variable("rf.tx_power_w_per_elem", "float", low=0.5, high=3.0)
111
+ )
112
+
113
+ # Generate DOE
114
+ doe = generate_doe(space, method="lhs", n_samples=100, seed=42)
115
+
116
+ # Run batch evaluation
117
+ runner = BatchRunner(scenario)
118
+ results = runner.run(doe)
119
+
120
+ # Extract Pareto frontier
121
+ pareto = extract_pareto(results, [
122
+ ("cost_usd", "minimize"),
123
+ ("eirp_dbw", "maximize"),
124
+ ])
125
+ ```
126
+
127
+ ## Examples
128
+
129
+ See the `examples/` directory:
130
+ - `01_comms_single_case.py` - Single case evaluation
131
+ - `02_comms_doe_trade.py` - Full DOE trade study workflow
132
+
133
+ ### Tutorial Notebook
134
+
135
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/jman4162/phased-array-systems/blob/main/notebooks/tutorial_phased_array_trade_study.ipynb)
136
+
137
+ Try the interactive tutorial in Google Colab!
138
+
139
+ ## Package Structure
140
+
141
+ ```
142
+ phased_array_systems/
143
+ ├── architecture/ # Array, RF chain, cost configurations
144
+ ├── scenarios/ # CommsLinkScenario, RadarDetectionScenario
145
+ ├── requirements/ # Requirement definitions and verification
146
+ ├── models/
147
+ │ ├── antenna/ # Phased array adapter and metrics
148
+ │ ├── comms/ # Link budget, propagation models
149
+ │ └── swapc/ # Power and cost models
150
+ ├── trades/ # DOE, batch runner, Pareto analysis
151
+ ├── viz/ # Plotting utilities
152
+ └── io/ # Config loading, results export
153
+ ```
154
+
155
+ ## Development
156
+
157
+ ```bash
158
+ # Clone the repository
159
+ git clone https://github.com/jman4162/phased-array-systems.git
160
+ cd phased-array-systems
161
+
162
+ # Install in development mode
163
+ pip install -e ".[dev]"
164
+
165
+ # Run tests
166
+ pytest tests/ -v
167
+
168
+ # Run linting
169
+ ruff check .
170
+ ```
171
+
172
+ ## License
173
+
174
+ MIT License - see [LICENSE](LICENSE) for details.
@@ -0,0 +1,43 @@
1
+ phased_array_systems/__about__.py,sha256=Qe_T9JvLe3C-9zBcXDIoQjsjy25E-ox3VlYm2AK2GTg,125
2
+ phased_array_systems/__init__.py,sha256=47SV42pztafqI3b0kVwjfQxdp8eKoEuda69PD9oXgVM,362
3
+ phased_array_systems/cli.py,sha256=x_D3sGeOeo9RpDLkOBTX8bhfpmATieUAgii_uS8MISw,642
4
+ phased_array_systems/constants.py,sha256=-WjHG4CJXmckxJsG2ymVGrqbTtWFKvAdARe3S03Ybjw,1310
5
+ phased_array_systems/evaluate.py,sha256=EgQXtM9zztAr9QHM6wcschA055eH6rY3i9xft10s-7c,4825
6
+ phased_array_systems/types.py,sha256=_K-9wvl2UO5jzjZgvHWw3MC-Aiz2WDfdgLV6IT6llK0,1521
7
+ phased_array_systems/architecture/__init__.py,sha256=ksS18SuMWiWxO4ov8fx13LYV4sn2-R9c67IrTyfpLoM,265
8
+ phased_array_systems/architecture/config.py,sha256=oc8bOKrGuJsUp5ZKLVCIE2KZQ3-P70q26naVy2J1u5s,5274
9
+ phased_array_systems/io/__init__.py,sha256=j8h7-fYUKTiFknqHTxdUIJJQaaXHmyKf76f_pyH4fZQ,387
10
+ phased_array_systems/io/config_loader.py,sha256=eEeEO5nqUewXrjs5ZlQDCeo_E5eIVjCQer0C4Pvpot0,2470
11
+ phased_array_systems/io/exporters.py,sha256=m6f4ZhT6cQaJLE3v1zMVbatKQRlOUViaAnYzAZTE3rY,4441
12
+ phased_array_systems/io/schema.py,sha256=43_O9U_w8ALjAYL64XajHV_zwq-TeRqP7zL8WFveYaI,4858
13
+ phased_array_systems/models/__init__.py,sha256=kjl_doYE2uyGRnjxrJzC0Pp_UcdjZY_GeY9GHWh9iOs,123
14
+ phased_array_systems/models/base.py,sha256=AP6C70tU8jXKxMCiuvB4oy5Vw2KFX_CTfK5oiYjrGo0,937
15
+ phased_array_systems/models/antenna/__init__.py,sha256=N1SEfVY1IuT0kEuq5H-1wk4hZwWRJeVp1TKnJlgy4Uk,394
16
+ phased_array_systems/models/antenna/adapter.py,sha256=jkoGnQ0d5DMASK9iRodosaGa6gM-bF3syhJKSFyTynQ,6670
17
+ phased_array_systems/models/antenna/metrics.py,sha256=cw2DCZ_vGpT9vNcurdSSxVB9zV9524fNM5nxrsWiwro,4875
18
+ phased_array_systems/models/comms/__init__.py,sha256=7aPkt-zKpe6yECynehGwAoP14I62n-M5w1lkMGgaiRM,243
19
+ phased_array_systems/models/comms/link_budget.py,sha256=dGKO7VA5C8RI5lffzqDs6H7l7fujfNe5HM5mgeTUfHc,6017
20
+ phased_array_systems/models/comms/propagation.py,sha256=mXsmgCAZ3h3FZIk0L9NykQga_fCHXVXBFSm2oRq_Xks,2364
21
+ phased_array_systems/models/swapc/__init__.py,sha256=0UCAWinqnMVW6c_num8qYTVHF3EYsJHGoOh44xKjd-I,228
22
+ phased_array_systems/models/swapc/cost.py,sha256=5c_vHDZXjmANoBbB2sTYotzNPgirIoGFKSBlfsqbPtA,2898
23
+ phased_array_systems/models/swapc/power.py,sha256=f7ECkfnM8MvlW4po-TboeWU6kyqrcmix_2IWTJsK7LY,3187
24
+ phased_array_systems/requirements/__init__.py,sha256=4eNoTS1ySN0toEYLAo1ttpe3u6Bu8YXFOUP0k4GTwUc,302
25
+ phased_array_systems/requirements/core.py,sha256=E3Bp474UXLyMhYLrlmERa0jaP3hl8iskgCvAJmVhJ70,8095
26
+ phased_array_systems/scenarios/__init__.py,sha256=4LAbI_zz3oQt36-WSxkHFSV1rRtTy13aG1s8YgodTvc,361
27
+ phased_array_systems/scenarios/base.py,sha256=Mlq-hMob1an4TviLQfFekRsQfCyOsNFJwCavKjrDaxs,818
28
+ phased_array_systems/scenarios/comms.py,sha256=d-IubHyWZC5iFZLUJdkwoDkMWAnptQn0bvkvN1KDBj4,2216
29
+ phased_array_systems/scenarios/radar.py,sha256=1DHMT8Mjrtg_hLUWuvh0iHQJomJT1Ct4Az9EWa_jF5I,1576
30
+ phased_array_systems/trades/__init__.py,sha256=3YIx1FvSwJWq9ai7zpFA7Ss2AiwcUJMAbZxuOCqxhjY,514
31
+ phased_array_systems/trades/design_space.py,sha256=mVH5FcBTjQmhr5IqucLlcCaLIZYcqvSKElowY8YvARw,8524
32
+ phased_array_systems/trades/doe.py,sha256=bEj946EcC8NqP0QQ6zxAw0rqEhAIMmDd3M3biNCm9Ow,4836
33
+ phased_array_systems/trades/pareto.py,sha256=4kyXP30SlEACbWyXk1mVBccGsG6mFXcQfPjYigsrxZk,8588
34
+ phased_array_systems/trades/runner.py,sha256=_4Wac8QS7alZAjijz5kIaWiRY54zGvXIVqP0av4gfAo,8225
35
+ phased_array_systems/utils/__init__.py,sha256=gGnUsnK_3Yv_7mG86dNIlV0PdQzR8lYuCvBab7P-hlE,200
36
+ phased_array_systems/utils/hashing.py,sha256=vNuMvM9Mh_qtvfIpiGvyKor2FjWMVAeGqNWjrCpjysI,1836
37
+ phased_array_systems/viz/__init__.py,sha256=ofsSeB8GVu_YbpSNJiu8UdoIxfO2GeIbChIp8hhRBhc,225
38
+ phased_array_systems/viz/plots.py,sha256=bAcBVMlLCv7Mj5bT8m6k6mGQmEhqsLGB-R6X8qs-U84,9128
39
+ phased_array_systems-0.1.0.dist-info/METADATA,sha256=z2RgzLRfESqAN8CZGIUWqLHmI-8t0DCiPxnhYVO9-9c,5826
40
+ phased_array_systems-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
41
+ phased_array_systems-0.1.0.dist-info/entry_points.txt,sha256=C5I-JkVj-j99qHvWW3PoXWjnzam62a0N5W4haHHxXxM,56
42
+ phased_array_systems-0.1.0.dist-info/licenses/LICENSE,sha256=tTGISmKHj6ZUsuU7scIo5pEognjuz4a7IB3maC4DfBw,1067
43
+ phased_array_systems-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pasys = phased_array_systems.cli:main