Core Concepts#

This page explains the fundamental concepts used throughout the library.

Coordinate Systems#

Spherical Coordinates (Theta/Phi)#

The library uses a standard spherical coordinate system:

  • Theta (θ): Angle from the z-axis (zenith), 0° to 180°

  • Phi (φ): Azimuth angle in the x-y plane, 0° to 360°

  • Broadside: θ = 0° (normal to array face)

\[\begin{split}x = r \sin\theta \cos\phi \\ y = r \sin\theta \sin\phi \\ z = r \cos\theta\end{split}\]

Direction Cosines (UV-Space)#

UV-space uses direction cosines, which are more convenient for array analysis:

\[\begin{split}u = \sin\theta \cos\phi \\ v = \sin\theta \sin\phi \\ w = \cos\theta\end{split}\]

The visible region is defined by \(u^2 + v^2 \leq 1\). Points outside this circle correspond to evanescent waves.

Convert between coordinate systems:

u, v = pa.theta_phi_to_uv(theta, phi)
theta, phi = pa.uv_to_theta_phi(u, v)

Array Factor#

The array factor describes the interference pattern of an array of isotropic point sources:

\[AF(\theta, \phi) = \sum_{n=1}^{N} w_n \exp\left(jk(x_n u + y_n v)\right)\]

Where:

  • \(w_n\) = complex weight (amplitude and phase) for element n

  • \(k = 2\pi/\lambda\) = wavenumber

  • \(x_n, y_n\) = element positions in wavelengths

The array_factor_vectorized() function computes this efficiently using NumPy broadcasting.

Pattern Multiplication#

The total radiation pattern of an array equals the product of:

  1. Element pattern: Directivity of a single element

  2. Array factor: Interference pattern from element spacing and phasing

\[E_{total}(\theta, \phi) = E_{element}(\theta, \phi) \times AF(\theta, \phi)\]
# Compute element pattern (cosine model)
element = pa.element_pattern(theta, exponent=1.3)

# Compute array factor
af = pa.array_factor_vectorized(k, geom.x, geom.y, weights, theta, phi)

# Total pattern
total = element * af

Steering Vector#

To point the main beam toward direction \((\theta_0, \phi_0)\), apply phase shifts that cancel the path differences:

\[w_n = \exp\left(-jk(x_n u_0 + y_n v_0)\right)\]

Where \(u_0 = \sin\theta_0 \cos\phi_0\) and \(v_0 = \sin\theta_0 \sin\phi_0\).

weights = pa.steering_vector(k, x, y, theta0_deg=30, phi0_deg=45)

Element Spacing and Grating Lobes#

Grating lobes are unwanted secondary main beams that appear when element spacing exceeds half a wavelength. To avoid grating lobes when scanning to angle \(\theta_{max}\):

\[d < \frac{\lambda}{1 + \sin\theta_{max}}\]

For λ/2 spacing (d=0.5), the array can scan to ±90° without grating lobes. For larger spacing, the maximum scan angle is limited.

Maximum Scan Angle vs. Spacing#

Spacing (d/λ)

Max Scan Angle

0.50

90°

0.55

65°

0.60

56°

0.70

46°

Amplitude Tapering#

Uniform amplitude weighting produces the narrowest beamwidth but has high sidelobes (~-13 dB for a rectangular array). Amplitude tapering reduces sidelobes at the cost of:

  1. Increased beamwidth

  2. Reduced aperture efficiency (directivity loss)

Common tapers include:

  • Taylor: Specified sidelobe level with controlled rolloff

  • Chebyshev: Equiripple sidelobes, narrowest beamwidth for given SLL

  • Hamming/Hanning: Simple, good for general use

# Taylor taper for -30 dB sidelobes
taper = pa.taylor_taper_2d(16, 16, sidelobe_dB=-30)

# Apply to steering weights
weights = weights * taper

Units and Normalization#

Positions#

Element positions are in wavelengths by default. This makes patterns frequency-independent. For physical units:

# If positions are in meters
wavelength = 0.03  # 10 GHz
x_wavelengths = x_meters / wavelength

Wavenumber#

The wavenumber relates frequency to spatial phase:

\[k = \frac{2\pi}{\lambda} = \frac{2\pi f}{c}\]
k = pa.wavelength_to_k(1.0)  # For normalized wavelength=1
k = pa.frequency_to_k(10e9)  # For 10 GHz

Pattern Normalization#

Patterns are typically shown in dB, normalized to the peak:

pattern_dB = pa.linear_to_db(np.abs(af))
pattern_dB = pa.normalize_pattern(pattern_dB)  # Peak at 0 dB

ArrayGeometry Class#

The ArrayGeometry dataclass stores array element positions and optional metadata:

from dataclasses import dataclass

@dataclass
class ArrayGeometry:
    x: np.ndarray      # X positions (wavelengths)
    y: np.ndarray      # Y positions (wavelengths)
    z: np.ndarray      # Z positions (wavelengths)
    nx: np.ndarray     # Normal vector x components (optional)
    ny: np.ndarray     # Normal vector y components (optional)
    nz: np.ndarray     # Normal vector z components (optional)
    n_elements: int    # Number of elements

Element normals are used for conformal arrays where elements point in different directions.