Skip to content

Far-Field Radiation Sensor

The far-field radiation sensor recovers fields in the far-field zone. You use it to study radiation and scattering patterns. It uses a near-to-far-field transformation. This transformation computes the electromagnetic field in the far-field region from its near-field values.

mufem calculates the far-field electric field with an approximation of the Stratton-Chu formula. This approximation is valid in the limit \(kr \gg 1\), where \(k\) is the wave number and \(r\) is the observation distance. The spherical angles \((\theta,\phi)\) give the observation direction \(\vec{r}_0\). With this approximation, the far-field electric field \(\vec{E}_p(\vec{r}_0)\) in the observation direction \(\vec{r}_0\) is

\[ r \vec{E}_p(\vec{r}_0) = \frac{-j k}{4 \pi} \vec{r}_0 \times \int_S \left[ \hat{n} \times \vec{E} - Z\, \vec{r}_0 \times \left(\hat{n} \times \vec{H}\right) \right] e^{jk\vec{r}_0 \cdot \vec{r}\,'} dS'. \]

Here \(S\) is an arbitrary surface enclosing the simulated object with an outward normal \(\hat{n}\). The vectors \(\vec{E}\) (V/m) and \(\vec{H}\) (A/m) represent the electric and magnetic fields at the surface \(S\), while \(Z = \sqrt{\mu/\varepsilon}\) is the wave impedance (Ohm) of the material at the surface. The vector \(\vec{r}\,'\) (m) is a point on the surface \(S\), and the integration encompasses all such points. The sign of the exponent agrees with the time convention \(e^{j\omega t}\) of mufem, with an outgoing wave \(e^{-jkr}\). The observation direction is expressed as \(\vec{r}_0=(\sin\theta\cos\phi, \sin\theta\sin\phi, \cos\theta)\) with the polar angle \(\theta\in[0,\pi]\) and the azimuthal angle \(\phi\in[0,2\pi]\).

Note that we get \(r \vec{E}_p\) rather than \(\vec{E}_p\) because the electric field decays as \(\exp(-jkr)/r\). Multiply by \(r\) so the field quantity stays finite. The solution is also defined up to a global phase factor.

From \(r \vec{E}_p\), you can get the magnetic field if the waves propagate in free space:

\[ r \vec{H}_p = \frac{\vec{r}_0 \times r\vec{E}_p}{Z_0}, \]

where \(Z_0\) is the impedance of free space.

From the far-field electric field \(\vec{E}_\text{far}\), the E-field radiation pattern \(\vec{E}_\text{pattern}(\theta,\phi)\) is defined as

\[ \vec{E}_\text{far}(\theta,\phi,r) = \vec{E}_\text{pattern}(\theta,\phi) \frac{e^{-j\vec{k}\cdot\vec{r}}}{r}. \]

From this equation, we have \(\vec{E}_\text{pattern}(\theta,\phi)=|r\vec{E}_p|\). The E-field radiation pattern has units of voltage.

The power \(U\) radiated per unit solid angle, also known as radiation intensity, is given by

\[ U(\theta,\phi) = \frac{1}{2Z_0} \left|\vec{E}_\text{pattern}(\theta,\phi)\right|^2. \]

To create a FarFieldRadiationSensor object, give a sensor name and the range parameters: start angle, stop angle, and step size, all in degrees. These parameters define the values for the polar angle \(\theta\) and the azimuthal angle \(\phi\). For a single angle, set the start and stop values to the same angle and the step to 0.0. The sensor uses the boundaries of all AbsorbingBoundaryCondition objects of the model as the integration surface \(S\). If the model has no AbsorbingBoundaryCondition, the sensor gives an error. The example below shows how to create and use a FarFieldRadiationSensor after the solve:

import numpy as np
from mufem.electromagnetics.timeharmonicmaxwell import FarFieldRadiationSensor

sensor = FarFieldRadiationSensor(
      "My Far-Field Radiation Sensor",
      polar_start=0.0,
      polar_stop=180.0,
      polar_step=6.0,
      azimuthal_start=0.0,
      azimuthal_stop=360.0,
      azimuthal_step=6.0,
)

thetas = np.array(sensor.get_polar_angles())  # [rad]
phis = np.array(sensor.get_azimuthal_angles())  # [rad]
e_pattern = np.array(sensor.get_radiation_pattern())  # shape (polar, azimuthal)

The sensor has these methods:

Methods of the far-field radiation sensor
Method Description
get_polar_angles() The polar angles $\theta$ in radians.
get_azimuthal_angles() The azimuthal angles $\phi$ in radians.
get_electric_field() The complex far-field electric field $r\vec{E}_p$ (V). The values are a complex128 array of shape (polar, azimuthal, 3).
get_radiation_pattern() The E-field radiation pattern $|\vec{E}_\text{pattern}|$ (V). The values are a float64 array of shape (polar, azimuthal).
get_radiation_intensity() The radiation intensity $U$ (W/sr). The values are a float64 array of shape (polar, azimuthal).
evaluate() Calculates the far field again from the current solution.

The methods get_electric_field(), get_radiation_pattern(), and get_radiation_intensity() return an AngularGrid object. It has the methods get_polar_angles(), get_azimuthal_angles() (both in radians), and get_values(), which returns the values as a NumPy array. You can also convert it directly with numpy.array(grid). The first index of the array is the polar angle and the second index is the azimuthal angle.

The sensor calculates the far field when you first get a result. It keeps the result for the model frequency. If you change the frequency, the sensor calculates the far field again. If you solve again at the same frequency (for example, with a different material or excitation), call evaluate() to update the result.

Warning

In a parallel (MPI) run, all processes must call the methods get_electric_field(), get_radiation_pattern(), get_radiation_intensity(), and evaluate() at the same time. Do not call them only on the main process. If you do, the run hangs without an error message. Get the result on all processes and print it on one process:

pattern = sensor.get_radiation_pattern()  # all processes
if is_main_process:
    print(np.array(pattern))

Typical industrial applications are the design of antennas, for example horn and dipole antennas. Another application is the calculation of the scattering pattern of an object, for example for radar.