Geometry Module#
The geometry module provides classes and functions for creating various array geometries, from simple rectangular grids to complex conformal and sparse arrays.
Classes#
- class phased_array.ArrayGeometry(x, y, z=None, nx=None, ny=None, nz=None, element_indices=None, tx=None, ty=None, tz=None)[source]#
Bases:
objectContainer for phased array element positions and orientations.
- x#
Element x-positions in meters
- Type:
ndarray
- y#
Element y-positions in meters
- Type:
ndarray
- z#
Element z-positions in meters (for 3D/conformal arrays)
- Type:
ndarray, optional
- nx#
Element normal x-components (unit vectors)
- Type:
ndarray, optional
- ny#
Element normal y-components
- Type:
ndarray, optional
- nz#
Element normal z-components
- Type:
ndarray, optional
- element_indices#
Original indices before any thinning (for tracking)
- Type:
ndarray, optional
- tx#
Element tangent x-components (local x-axis / polarization reference for conformal vector patterns)
- Type:
ndarray, optional
- ty#
Element tangent y-components
- Type:
ndarray, optional
- tz#
Element tangent z-components
- Type:
ndarray, optional
- class phased_array.SubarrayArchitecture(geometry, subarray_assignments, n_subarrays, subarray_centers=None, overlapped=False, subarray_elements=None, overlap_weights=None)[source]#
Bases:
objectDefines subarray partitioning of a phased array.
Supports both non-overlapped and overlapped subarray architectures. In overlapped architectures, elements can belong to multiple subarrays with potentially different weights.
- geometry#
Full array geometry
- Type:
- subarray_assignments#
Subarray index for each element (shape: n_elements,) None for overlapped subarrays
- Type:
ndarray, optional
- subarray_centers#
Center positions of each subarray (n_subarrays, 2 or 3)
- Type:
ndarray, optional
- subarray_elements#
For overlapped: list of element indices for each subarray
- Type:
listofndarray, optional
- overlap_weights#
For overlapped: amplitude weights for shared elements in each subarray
- Type:
listofndarray, optional
- get_element_subarrays(element_idx)[source]#
Get indices of all subarrays that contain a given element.
For non-overlapped architectures, returns single subarray index. For overlapped, may return multiple indices.
- Parameters:
element_idx (
int) – Index of the element- Returns:
subarray_indices – Array of subarray indices containing this element
- Return type:
ndarray
Planar Arrays#
- phased_array.create_rectangular_array(Nx, Ny, dx, dy, wavelength=1.0, center=True)[source]#
Create a rectangular planar array.
- Parameters:
- Returns:
geometry – Array geometry with element positions
- Return type:
Examples
Create a 16x16 array with half-wavelength spacing:
>>> import phased_array as pa >>> geom = pa.create_rectangular_array(16, 16, dx=0.5, dy=0.5) >>> geom.n_elements 256 >>> geom.x.shape (256,)
Create a 10x10 array at 10 GHz (3 cm wavelength):
>>> geom = pa.create_rectangular_array(10, 10, dx=0.5, dy=0.5, wavelength=0.03) >>> geom.n_elements 100
Access element positions:
>>> geom = pa.create_rectangular_array(4, 4, dx=0.5, dy=0.5) >>> geom.is_planar True
- phased_array.create_triangular_array(Nx, Ny, dx, dy=None, wavelength=1.0, center=True)[source]#
Create an offset triangular (hexagonal) array.
Rows are offset by half the x-spacing for optimal packing.
- Parameters:
- Returns:
geometry
- Return type:
Examples
Create a triangular grid array (hexagonal packing):
>>> import phased_array as pa >>> geom = pa.create_triangular_array(10, 10, dx=0.5) >>> geom.n_elements # Slightly fewer than 10x10 due to offset rows 95 >>> geom.is_planar True
Triangular grids provide ~13% better packing efficiency:
>>> rect = pa.create_rectangular_array(10, 10, dx=0.5, dy=0.5) >>> tri = pa.create_triangular_array(10, 10, dx=0.5) >>> rect.n_elements > tri.n_elements # Rect has more for same Nx, Ny True
- phased_array.create_elliptical_array(a, b, dx, dy=None, grid_type='rectangular', wavelength=1.0)[source]#
Create an array within an elliptical boundary.
- Parameters:
a (
float) – Ellipse semi-axis in x (in wavelengths)b (
float) – Ellipse semi-axis in y (in wavelengths)dx (
float) – Element spacing in x (in wavelengths)dy (
float, optional) – Element spacing in y (default: same as dx)grid_type (
str) – ‘rectangular’ or ‘triangular’wavelength (
float) – Wavelength in meters
- Returns:
geometry
- Return type:
Circular and Ring Arrays#
- phased_array.create_circular_array(n_elements, radius, wavelength=1.0, start_angle=0.0)[source]#
Create a circular (ring) array in the xy-plane.
- Parameters:
- Returns:
geometry
- Return type:
Conformal Arrays#
- phased_array.create_cylindrical_array(n_azimuth, n_vertical, radius, height, wavelength=1.0)[source]#
Create a cylindrical conformal array.
Elements are distributed on a cylinder surface with normals pointing radially outward.
- phased_array.create_spherical_array(n_theta, n_phi, radius, theta_min=0.0, theta_max=1.5707963267948966, wavelength=1.0)[source]#
Create a spherical conformal array.
- Parameters:
n_theta (
int) – Number of elements in theta (elevation)n_phi (
int) – Number of elements in phi (azimuth)radius (
float) – Sphere radius in wavelengthstheta_min (
float) – Minimum theta in radians (0 = north pole)theta_max (
float) – Maximum theta in radianswavelength (
float) – Wavelength in meters
- Returns:
geometry
- Return type:
- phased_array.array_factor_conformal(theta, phi, geometry, weights, k, element_pattern_func=None, **element_kwargs)[source]#
Compute array factor for conformal arrays with element orientation.
Each element’s contribution is weighted by its projected pattern in the observation direction.
- Parameters:
theta (
ndarray) – Observation theta angles in radiansphi (
ndarray) – Observation phi angles in radiansgeometry (
ArrayGeometry) – Array geometry with element normalsweights (
ndarray) – Complex element weightsk (
float) – Wavenumberelement_pattern_func (
callable, optional) – Element pattern function**element_kwargs – Arguments for element pattern function
- Returns:
AF – Array factor (same shape as theta)
- Return type:
ndarray
Sparse/Thinned Arrays#
- phased_array.thin_array_random(geometry, thinning_factor, seed=None)[source]#
Randomly thin an array by removing elements.
- Parameters:
geometry (
ArrayGeometry) – Original array geometrythinning_factor (
float) – Fraction of elements to keep (0 to 1)seed (
int, optional) – Random seed for reproducibility
- Returns:
geometry – Thinned array geometry
- Return type:
- phased_array.thin_array_density_tapered(geometry, density_func, seed=None)[source]#
Thin array with position-dependent density (statistical thinning).
- Parameters:
geometry (
ArrayGeometry) – Original array geometrydensity_func (
callable) – Function(x, y) -> probability of keeping each element (0 to 1)seed (
int, optional) – Random seed
- Returns:
geometry – Thinned geometry
- Return type:
- phased_array.thin_array_genetic_algorithm(geometry, n_target, objective_func, population_size=50, n_generations=100, mutation_rate=0.1, seed=None)[source]#
Optimize element selection using a genetic algorithm.
- Parameters:
geometry (
ArrayGeometry) – Original full array geometryn_target (
int) – Target number of elements to keepobjective_func (
callable) – Function(ArrayGeometry) -> float to minimizepopulation_size (
int) – GA population sizen_generations (
int) – Number of generationsmutation_rate (
float) – Probability of mutation per geneseed (
int, optional) – Random seed
- Returns:
geometry – Optimized thinned geometry
- Return type:
Subarrays#
- phased_array.create_rectangular_subarrays(Nx_total, Ny_total, Nx_sub, Ny_sub, dx, dy, wavelength=1.0)[source]#
Create rectangular subarrays from a rectangular array.
- Parameters:
- Returns:
architecture
- Return type:
- phased_array.compute_subarray_weights(architecture, k, theta0_deg, phi0_deg, intra_subarray_weights=None)[source]#
Compute element weights for subarray-level beamforming.
Phase is quantized to subarray centers (one phase shifter per subarray).
- Parameters:
architecture (
SubarrayArchitecture) – Subarray architecturek (
float) – Wavenumbertheta0_deg (
float) – Steering direction in degreesphi0_deg (
float) – Steering direction in degreesintra_subarray_weights (
ndarray, optional) – Amplitude taper applied within each subarray
- Returns:
weights – Complex weights for all elements
- Return type:
ndarray
Overlapped Subarrays#
Overlapped subarray architectures share elements between adjacent subarrays, improving pattern characteristics and reducing grating lobes while maintaining independent subarray beam control.
- phased_array.create_overlapped_subarrays(Nx_total, Ny_total, Nx_sub, Ny_sub, overlap_x, overlap_y, dx, dy, wavelength=1.0, taper_overlap=True)[source]#
Create overlapped subarrays from a rectangular array.
Overlapped subarrays share elements between adjacent subarrays, which can improve pattern characteristics and reduce grating lobes while maintaining independent subarray beam control.
- Parameters:
Nx_total (
int) – Total elements in xNy_total (
int) – Total elements in yNx_sub (
int) – Elements per subarray in xNy_sub (
int) – Elements per subarray in yoverlap_x (
int) – Number of overlapping elements in x between adjacent subarraysoverlap_y (
int) – Number of overlapping elements in y between adjacent subarraysdx (
float) – Element spacing in wavelengthsdy (
float) – Element spacing in wavelengthswavelength (
float) – Wavelength in meterstaper_overlap (
bool) – If True, apply amplitude taper to overlapping elements
- Returns:
architecture – Overlapped subarray architecture
- Return type:
Examples
Create 50% overlapped 4x4 subarrays:
>>> import phased_array as pa >>> arch = pa.create_overlapped_subarrays( ... Nx_total=16, Ny_total=16, ... Nx_sub=4, Ny_sub=4, ... overlap_x=2, overlap_y=2, ... dx=0.5, dy=0.5 ... ) >>> arch.overlapped True >>> arch.n_subarrays > 0 True
Notes
- Subarray stride (non-overlapping portion):
stride_x = Nx_sub - overlap_x stride_y = Ny_sub - overlap_y
Elements in the overlap region receive contributions from multiple subarrays, typically with tapered weights.
- phased_array.overlapped_subarray_weights(architecture, k, theta0_deg, phi0_deg, subarray_weights=None)[source]#
Compute element weights for overlapped subarray beamforming.
- Parameters:
architecture (
SubarrayArchitecture) – Overlapped subarray architecturek (
float) – Wavenumbertheta0_deg (
float) – Steering direction in degreesphi0_deg (
float) – Steering direction in degreessubarray_weights (
ndarray, optional) – Complex weights for each subarray (n_subarrays,). If None, uses uniform amplitude with steering phase.
- Returns:
weights – Complex weights for all elements
- Return type:
ndarray
Examples
>>> import numpy as np >>> import phased_array as pa >>> arch = pa.create_overlapped_subarrays( ... Nx_total=16, Ny_total=16, ... Nx_sub=4, Ny_sub=4, ... overlap_x=2, overlap_y=2, ... dx=0.5, dy=0.5 ... ) >>> k = pa.wavelength_to_k(1.0) >>> weights = pa.overlapped_subarray_weights(arch, k, 15, 0) >>> weights.shape (256,)
Notes
For overlapped architectures, each element’s weight is the sum of contributions from all subarrays it belongs to, weighted by the overlap weight for that subarray.
- phased_array.compute_overlapped_pattern(architecture, k, theta0_deg, phi0_deg, theta_range=(0, 1.5707963267948966), n_points=361, phi_cut_deg=0.0)[source]#
Compute radiation pattern for overlapped subarray architecture.
- Parameters:
architecture (
SubarrayArchitecture) – Overlapped subarray architecturek (
float) – Wavenumbertheta0_deg (
float) – Steering direction in degreesphi0_deg (
float) – Steering direction in degreestheta_range (
tuple) – (min, max) theta range in radiansn_points (
int) – Number of pattern pointsphi_cut_deg (
float) – Phi angle for the pattern cut
- Returns:
theta_deg (
ndarray) – Theta angles in degreespattern_dB (
ndarray) – Normalized pattern in dB
- Return type:
Examples
>>> import numpy as np >>> import phased_array as pa >>> arch = pa.create_overlapped_subarrays( ... Nx_total=16, Ny_total=16, ... Nx_sub=4, Ny_sub=4, ... overlap_x=2, overlap_y=2, ... dx=0.5, dy=0.5 ... ) >>> k = pa.wavelength_to_k(1.0) >>> theta_deg, pattern_dB = pa.compute_overlapped_pattern( ... arch, k, theta0_deg=0, phi0_deg=0 ... ) >>> len(theta_deg) == 361 True