Skip to main content

Spatial antenna analysis with xarray.

Project description

📡 xant

xant is a Python library for spatial antenna analysis. Define antenna patterns analytically or from measured data, position them in 3D space, combine them into phased arrays, and evaluate gain, beamwidth, and directivity — all coordinate-frame-aware and unit-safe via pint and xarray.

Built on top of hics, xarray, and scipy.

Installation

uv add xant

Or with pip:

pip install xant

Features

  • Lazy antenna math — add, subtract, multiply, and divide patterns using Python operators; the expression tree is only evaluated when data is requested
  • Arbitrary coordinate frames — request pattern data in phitheta, azel, elaz, uv, uvw, llh, ecef, or h3; xant handles all rotation and interpolation automatically
  • Spatial positioning — place any antenna or array in 3D space using hics hierarchical coordinate systems; relative rotations are resolved automatically
  • Phased arrays — build rectangular, triangular, or arbitrary lattice arrays; steer dispersively by phase center; apply amplitude tapers; visualize element layout
  • Hierarchical arrays — compose arrays of arrays for subarray-based architectures
  • Spatial RF link analysis — compute received power between two spatially positioned antennas with automatic antenna pointing, polarization projection, and horizon angle resolution
  • Transmit power density mapping — project EIRP onto a lat/lon/alt grid and plot coverage maps over satellite imagery via cartopy
  • Propagation models — free-space path loss (FSPL) and terrain-aware ITM (Irregular Terrain Model) with polarization-resolved H/V loss, optional clutter models (ITU-R P.1812, ITU-R P.2108), and configurable reliability/confidence percentiles
  • Analytical models — isotropic, dipole, cosine, cardioid, aperture, and more built-in element patterns
  • Data patterns — load and interpolate measured or simulated antenna data from .xant (NetCDF/HDF5) files using spline interpolation
  • Polarization support — various polarizations support in different coordinate systems; apolar patterns for total power
  • Array concatenation — stack antennas along arbitrary named dimensions for channel or port analysis
  • Antenna metrics — beamwidth, directivity (D0), and total radiated power (TRP)
  • Unit safety — all quantities carry pint units; degrees, radians, Hz, and meter conversions are handled automatically

Quick Start

Define and query an antenna

import numpy as np
from xrench.units import ureg
from xant.antenna.common import Dipole

freq  = np.array([2.4e9]) * ureg.Hz
theta = np.linspace(0, 180, 181) * ureg.degree
phi   = np.arange(-180, 180, 5) * ureg.degree

dip  = Dipole(l=0.5 * ureg.m, frequency=freq)
data = dip.request_data(theta=theta, phi=phi, coordinate_frame="phitheta")
# Returns xr.DataArray with dims: (polarization, frequency, phi, theta)

Position an antenna in space

from hics import HCS
from scipy.spatial.transform import Rotation

# Tilt 30° around Y, offset 1 m above origin
cs  = HCS((0, 0, 1) * ureg.m, rotation=Rotation.from_euler("Y", 30, degrees=True))
ant = Dipole(l=0.5 * ureg.m, frequency=freq, hcs=cs)

Antenna math

Operators are lazy — the expression tree is evaluated only when request_data() is called.

from xant.antenna.common import Isotropic

iso      = Isotropic(frequency=freq)
combined = iso + dip       # coherent sum
scaled   = dip * 0.5       # amplitude scale
ratio    = dip / iso       # pattern ratio

Phased array

from xant.antenna.phasedarray import AntennaArray, steer_phase_centers
from hics import GLOBAL_CS

freq = np.array([3e9]) * ureg.Hz
lam  = (ureg.speed_of_light / freq).to("m")

element = Isotropic(frequency=freq)
array   = AntennaArray.rectangular(
    element, nx=8, dx=0.5*lam, ny=8, dy=0.5*lam, cs_reference=GLOBAL_CS
)

# Steer to theta=30°, phi=0°
steer_phase_centers(array, frequency=freq[0], theta=30*ureg.degree, phi=0*ureg.degree)

data = array.total.request_data(theta=theta, phi=phi, coordinate_frame="phitheta")

Hierarchical subarray

subarray = AntennaArray.rectangular(
    element, nx=2, dx=0.5*lam, ny=2, dy=0.5*lam, cs_reference=GLOBAL_CS
)
top = AntennaArray(subarray, [HCS((i * 2 * lam[0].magnitude, 0, 0) * ureg.m) for i in range(4)])

Spatial RF link

Calculate received power between two geospatially positioned antennas. xant automatically resolves the pointing angles from each antenna's coordinate system toward the other, projects polarization, and applies the selected propagation model.

from hics import HCS
from xant.propagation.rflink import calculate_spatial_link

# Position TX and RX using geodetic coordinates
tx_cs = HCS.from_crs((40.015 * ureg.degree, -105.27 * ureg.degree, 30 * ureg.m), hagl=True)
rx_cs = HCS.from_crs((40.020 * ureg.degree, -105.24 * ureg.degree,  10 * ureg.m), hagl=True)

tx = Isotropic(frequency=freq, hcs=tx_cs)
rx = Isotropic(frequency=freq, hcs=rx_cs)

rx_power, prop_loss, incident_pol, txcs, rxcs = calculate_spatial_link(
    tx, power=1 * ureg.watt, rx=rx, propagation="fspl"
)
print(rx_power)  # received power in dBm

Terrain-aware propagation with ITM

rx_power, prop_loss, incident_pol, txcs, rxcs = calculate_spatial_link(
    tx,
    power=1 * ureg.watt,
    rx=rx,
    propagation="itm_rflink",
    gnd="good",           # ground conductivity: "poor", "average", "good", "fresh_water"
    time=[50],            # reliability percentile
    situation=[50],       # confidence percentile
)

Transmit power density map

Project EIRP across a lat/lon grid and visualize coverage over a map.

from xant.propagation.rflink import transmit_power_density, plot_transmit_pd

lats = np.linspace(40.00, 40.04, 50) * ureg.degree
lons = np.linspace(-105.30, -105.20, 50) * ureg.degree
hs   = [0] * ureg.m

pd_map = transmit_power_density(
    tx, power=1 * ureg.watt,
    lats=lats, lons=lons, hs=hs,
    propagation="fspl",
)

plot_transmit_pd(pd_map)

Link horizon visualization

Visualize the link geometry, terrain profile, Fresnel zones, and antenna gain patterns in a single cross-section plot.

from xant.propagation.rflink import view_link_horizon

ax = view_link_horizon(tx, rx, rx_power, incident_pol, prop_loss,gsize=.02)

Load and export measured patterns

import xant

ant  = xant.Antenna("measured_pattern.xant")
ant.export("my_antenna.xant")

Metrics

bw  = ant.beamwidth(dim="phi", coordinate_frame="phitheta")
d0  = ant.d0()
trp = ant.trp()

API Reference

Antenna

The base pattern container. Wraps either an xr.DataArray of measured data or an AntennaFunction for analytical/lazy patterns.

Parameter Description
data Path to .xant file, xr.DataArray, or AntennaFunction
hcs HCS coordinate system defining position and orientation

Key methods: .request_data(), .move(), .export(), .copy(), .beamwidth(), .d0(), .trp()

Operators: +, -, *, /, **, unary -, .sum(dim)

request_data()

ant.request_data(
    coordinate_frame="phitheta",   # output coordinate frame
    hcs=None,                      # viewpoint coordinate system
    theta=...,                     # spatial coordinate kwargs (Quantity or DataArray)
    phi=...,
)

Returns an xr.DataArray with dims (polarization, frequency, ...). All coordinate frame transforms and spatial rotations are applied automatically.

AntennaArray

A phased array of Antenna or nested AntennaArray elements.

Constructor Description
AntennaArray(element, coordinate_systems) Arbitrary element positions
AntennaArray.rectangular(element, nx, dx, ny, dy, cs_reference) Rectangular lattice
AntennaArray.triangular(element, nx, ny, dx, cs_reference) Triangular lattice
Property Description
.total Sum of translated element patterns weighted by excitation
.af Array factor (translated phase × excitation)
.elements Per-element patterns with translation applied
.excitation Complex excitation weights (taper × steering_vector)
.positions(reference) Element positions relative to a reference HCS

Visualization: .show() (3D), .showxy() (2D top-down with optional phase/magnitude/subarray coloring)

Steering and Tapering

from xant.antenna.phasedarray import steer_phase_centers, apply_taper

steer_phase_centers(array, frequency=freq[0], theta=30*ureg.degree, phi=0*ureg.degree)
apply_taper(array, window=np.kaiser(N, beta=6), dim="x")

Propagation (xant.propagation)

Function Description
calculate_spatial_link(tx, power, rx, propagation) Received power, path loss, and pointing angles between two Antenna objects
transmit_power_density(tx, power, lats, lons, hs, propagation) EIRP projected onto a lat/lon/alt grid in dBm
plot_transmit_pd(data) Coverage map over satellite imagery; supports animation along a time dimension
plot_link(data) Scatter plot of received power on a map projection
view_link_horizon(tx, rx, res, incident_pol, prop_loss) Terrain cross-section with antenna patterns, LOS, and Fresnel zones overlaid
Propagator Description
fspl Free-space path loss
itm_rflink ITM terrain propagation, H/V polarization-resolved, configurable reliability/confidence percentiles and ground type
mask_los Mask path loss beyond the radio horizon

ITM ground types: "poor", "average", "good", "fresh_water"

ITM clutter methods: ClutterMethods.NONE, ClutterMethods.ITURP1812, ClutterMethods.ITURP2108

Built-in Antenna Models (xant.antenna.common)

Class Description
Isotropic Uniform gain in all directions
Dipole Half-wave dipole with theta/phi polarization
Cardioid Cardioid pattern
Cosine Cosine^n element pattern
Hemispherical Upper-hemisphere only
ElementWeight Slope-vs-theta weighting function
RectangularAperture Uniform rectangular aperture (Balanis Ch. 12)
TE10Aperture TE₁₀-mode waveguide aperture
CircularAperture Uniform circular aperture (Balanis Ch. 12)
DipoleAboveGround Dipole over a ground plane via image theory

Coordinate Frames

Frame Dims Notes
phitheta phi, theta Standard spherical
azel azimuth, elevation Azimuth over elevation
elaz elevation, azimuth Elevation over azimuth
uv u, v Sin-space projection
uvw u, v, w Direction cosines
llh lat, lon, h Geodetic — requires HCS
ecef x, y, z Earth-centered — requires HCS
h3 i, j, h H3 hexagonal grid — requires HCS

Concatenation

from xant.antenna.core import concat

multi = concat([ant1, ant2, ant3], coord={"channel": [0, 1, 2]})
data  = multi.request_data(channel=[0, 2], theta=theta, phi=phi, coordinate_frame="phitheta")

Grating Lobe Diagram

from xant.antenna.phasedarray import plot_grating_lobe_diagram

plot_grating_lobe_diagram(
    dx=0.5, dy=0.5,
    steering_angles=(0*ureg.degree, 30*ureg.degree),
    lattice_type="rectangular",
    max_scan=60*ureg.degree,
)

Dependencies

  • hics — hierarchical coordinate systems and geospatial utilities
  • xrench — xarray + pint integration utilities
  • xarray — labeled N-D arrays
  • pint — unit-aware quantities
  • numpy, scipy, matplotlib
  • cartopy, shapely (propagation and mapping)

License

MIT

Author

Created by Rob Scheeler

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xant-0.1.1.tar.gz (162.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xant-0.1.1-py3-none-any.whl (165.1 kB view details)

Uploaded Python 3

File details

Details for the file xant-0.1.1.tar.gz.

File metadata

  • Download URL: xant-0.1.1.tar.gz
  • Upload date:
  • Size: 162.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.6.12

File hashes

Hashes for xant-0.1.1.tar.gz
Algorithm Hash digest
SHA256 eeb63a943a6c34a3441855907378a791668abf00842215554582d0944a184c39
MD5 a416b1731269b6a4c89bc8875667be3c
BLAKE2b-256 73aad4af0da1f0df73ba5adee75db815cf2acfb59ca24be42500c94928dfc184

See more details on using hashes here.

File details

Details for the file xant-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: xant-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 165.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.6.12

File hashes

Hashes for xant-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ef56b9e03046e1840fdc50788005db9df778c4e3ea53f2408850121262a383f4
MD5 68b9547a7b62d76aedb2628def3a757f
BLAKE2b-256 5f30ebc67c9916ef8a73975e0ae74ff7a69309bce5532d5f1b18da9a8a1a9b04

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page