Vector Patterns Module#

The vector patterns module connects the scalar array-factor engine with the polarization math: polarized element models produce complex (E_theta, E_phi) field components, which multiply the array factor to give full vector patterns, co/cross-polar decompositions, axial-ratio maps, and polarization-correct conformal array patterns.

A polarized element pattern is any callable f(theta, phi, **kwargs) -> (E_theta, E_phi) returning the complex field components in the spherical basis of its evaluation frame, with boresight along +z.

Pattern Container#

class phased_array.VectorPattern(theta, phi, E_theta, E_phi)[source]#

Bases: object

Full vector radiation pattern on a theta/phi grid.

theta#

Theta grid in radians, shape (n_theta, n_phi)

Type:

ndarray

phi#

Phi grid in radians, shape (n_theta, n_phi)

Type:

ndarray

E_theta#

Complex theta field component, shape (n_theta, n_phi)

Type:

ndarray

E_phi#

Complex phi field component, shape (n_theta, n_phi)

Type:

ndarray

property power: ndarray#

Total radiated power density |E_theta|^2 + |E_phi|^2.

power_dB(normalize=True)[source]#

Total power pattern in dB.

Parameters:

normalize (bool) – If True (default), normalize so the peak is 0 dB.

co_cross(reference_pol='ludwig3')[source]#

Co- and cross-polar field components.

Parameters:

reference_pol (str) – ‘ludwig3’ (x-polarized reference) or ‘ludwig3-y’ (y-polarized reference).

Returns:

E_co, E_cross – Complex co- and cross-polar components, same shape as E_theta.

Return type:

ndarray

axial_ratio_map()[source]#

Axial ratio at every grid point (1 = circular, inf = linear), computed from the Ludwig-3 co/cross components.

xpd_map(reference_pol='ludwig3')[source]#

Cross-polar discrimination map in dB: |E_co|^2 / |E_cross|^2.

Polarized Element Models#

phased_array.dipole_element(orientation='x')[source]#

Ideal short (Hertzian) dipole element pattern.

Parameters:

orientation (str) – Dipole axis: ‘x’, ‘y’, or ‘z’.

Returns:

element_func – f(theta, phi) -> (E_theta, E_phi), normalized so the peak field magnitude is 1.

Return type:

callable

Examples

>>> import numpy as np
>>> import phased_array as pa
>>> f = pa.dipole_element('x')
>>> E_theta, E_phi = f(np.array([0.0]), np.array([0.0]))
>>> np.isclose(abs(E_theta[0]), 1.0)  # boresight, co-pol
True
phased_array.ideal_patch_element(pol='x', cos_exp=1.0)[source]#

Ideal Ludwig-3 element: cos^n(theta) co-polar magnitude with zero cross-polarization by construction.

Parameters:
  • pol (str) – Co-polar direction, ‘x’ or ‘y’.

  • cos_exp (float) – Cosine exponent of the theta roll-off.

Returns:

element_func – f(theta, phi) -> (E_theta, E_phi). Zero behind the +z hemisphere.

Return type:

callable

phased_array.cos_q_polarized_element(q_theta=1.0, jones=None, max_gain_dBi=0.0)[source]#

cos^q(theta) element with an arbitrary polarization state.

Successor to the deprecated cos_exp_phi parameter of core.element_pattern: the scalar cos^q magnitude is mapped onto the Ludwig-3 basis of the given Jones vector.

Parameters:
  • q_theta (float) – Cosine exponent for the theta roll-off.

  • jones (ndarray, optional) – Jones vector [E_x, E_y] defining the polarization state (normalized internally). Default [1, 0] (x-linear).

  • max_gain_dBi (float) – Peak element gain in dBi (applied as a field scale factor).

Returns:

element_func – f(theta, phi) -> (E_theta, E_phi).

Return type:

callable

phased_array.crossed_dipole_element(phase_diff=-1.5707963267948966)[source]#

Crossed-dipole (turnstile) element for circular polarization.

An x-dipole and a y-dipole fed with a relative phase of phase_diff: -pi/2 gives RHCP at boresight, +pi/2 LHCP.

Returns:

element_func – f(theta, phi) -> (E_theta, E_phi), normalized so the boresight co-polar magnitude is 1.

Return type:

callable

class phased_array.GriddedElementPattern(theta_grid, phi_grid, E_theta, E_phi, method='linear')[source]#

Bases: object

Polarized element pattern interpolated from gridded data (e.g. a full-wave simulation or measurement export).

Satisfies the element protocol: instances are callables f(theta, phi) -> (E_theta, E_phi).

Parameters:
  • theta_grid (ndarray) – Monotonic 1D theta sample points in radians

  • phi_grid (ndarray) – Monotonic 1D phi sample points in radians

  • E_theta (ndarray) – Complex theta component, shape (len(theta_grid), len(phi_grid))

  • E_phi (ndarray) – Complex phi component, same shape

  • method (str) – Interpolation method for scipy.interpolate.RegularGridInterpolator

classmethod from_scalar(theta_grid, phi_grid, magnitude, jones=None, method='linear')[source]#

Build a polarized gridded pattern from a scalar magnitude grid and a Jones vector (default x-linear), mapping the magnitude onto the Ludwig-3 basis like cos_q_polarized_element.

Vector Pattern Computation#

phased_array.vector_total_pattern(theta, phi, x, y, weights, k, element_func, z=None, **element_kwargs)[source]#

Vector total pattern for identical, identically-oriented elements: (E_theta, E_phi) = AF * element field components.

Parameters:
  • theta (ndarray) – Observation angles in radians (any matching shapes)

  • phi (ndarray) – Observation angles in radians (any matching shapes)

  • x (ndarray) – Element positions in meters

  • y (ndarray) – Element positions in meters

  • weights (ndarray) – Complex element weights

  • k (float) – Wavenumber in rad/m

  • element_func (callable) – Polarized element pattern f(theta, phi, **kwargs) -> (E_theta, E_phi)

  • z (ndarray, optional) – Element z-positions

Returns:

E_theta, E_phi – Complex field components, same shape as theta.

Return type:

ndarray

Examples

>>> import numpy as np
>>> import phased_array as pa
>>> geom = pa.create_rectangular_array(4, 4, dx=0.5, dy=0.5)
>>> k = pa.wavelength_to_k(1.0)
>>> w = np.ones(16)
>>> f = pa.ideal_patch_element('x')
>>> E_theta, E_phi = pa.vector_total_pattern(
...     np.array([0.0]), np.array([0.0]), geom.x, geom.y, w, k, f
... )
>>> np.isclose(abs(E_theta[0]), 16.0)  # AF peak x unit co-pol field
True
phased_array.compute_full_vector_pattern(x, y, weights, k, element_func=None, n_theta=181, n_phi=361, theta_range=(0, 1.5707963267948966), phi_range=(0, 6.283185307179586), z=None, **element_kwargs)[source]#

Full vector pattern over a theta/phi grid.

Mirrors core.compute_full_pattern grid conventions but returns a VectorPattern with complex (E_theta, E_phi) instead of a scalar dB pattern.

Parameters:
  • element_func (callable, optional) – Polarized element pattern; default ideal_patch_element(‘x’).

  • core.compute_full_pattern) ((other parameters as in)

phased_array.compute_co_cross_pattern_cuts(x, y, weights, k, element_func, phi_cut_deg=0.0, theta_range_deg=(-90, 90), n_points=361, reference_pol='ludwig3', **element_kwargs)[source]#

Co- and cross-polar 1D pattern cuts through a phi plane.

Negative theta values are mapped to the phi + 180 deg half-plane. Both cuts are normalized to the co-polar peak.

Returns:

  • theta_deg (ndarray) – Cut angles in degrees

  • co_dB, cross_dB (ndarray) – Co- and cross-polar patterns in dB relative to the co-pol peak

Return type:

Tuple[ndarray, ndarray, ndarray]

phased_array.dual_pol_weights(weights_x, weights_y, jones_goal)[source]#

Scale two orthogonal feed weight sets to synthesize a target polarization state.

Parameters:
  • weights_x (ndarray) – Complex weights of the x- and y-polarized feeds

  • weights_y (ndarray) – Complex weights of the x- and y-polarized feeds

  • jones_goal (ndarray) – Target Jones vector [E_x, E_y] (normalized internally)

Returns:

weights_x_scaled, weights_y_scaled

Return type:

ndarray

Conformal Arrays#

phased_array.element_rotation_matrices(geometry)[source]#

Per-element rotation matrices from the global frame to each element’s local frame.

The local z-axis is the element normal. The local x-axis is the element tangent (tx, ty, tz) if the geometry provides one, otherwise normalize(z_hat x normal), falling back to the global x-axis when the normal is parallel to z_hat. The local y-axis completes the right-handed triad.

Returns:

R – Rows of R[i] are the local basis vectors in global coordinates, so v_local = R[i] @ v_global.

Return type:

ndarray, shape (n_elements, 3, 3)

phased_array.global_to_local_angles(R, theta, phi)[source]#

Observation angles in each element’s local frame.

Parameters:
  • R (ndarray, shape (3, 3) or (n_elements, 3, 3)) – Rotation matrices from element_rotation_matrices

  • theta (ndarray) – Global observation angles in radians (flattened internally)

  • phi (ndarray) – Global observation angles in radians (flattened internally)

Returns:

local_theta, local_phi – Local angles; shape (n_angles,) for a single matrix, else (n_elements, n_angles).

Return type:

ndarray

phased_array.vector_array_factor_conformal(theta, phi, geometry, weights, k, element_func=None, per_element_funcs=None, **element_kwargs)[source]#

Vector pattern for a conformal array with per-element orientation.

Each element’s polarized pattern is evaluated in its local frame (local z = element normal), the resulting field is rotated back to global Cartesian coordinates, and projected onto the global spherical basis at the observation angle before summation.

Parameters:
  • theta (ndarray) – Global observation angles in radians

  • phi (ndarray) – Global observation angles in radians

  • geometry (ArrayGeometry) – Geometry; normals default to +z when absent

  • weights (ndarray) – Complex element weights

  • k (float) – Wavenumber in rad/m

  • element_func (callable, optional) – Polarized element pattern used for every element; default ideal_patch_element(‘x’)

  • per_element_funcs (sequence of callables, optional) – Per-element patterns (e.g. embedded element patterns); overrides element_func

Returns:

E_theta, E_phi – Complex global field components, same shape as theta.

Return type:

ndarray