Application Examples

Two classical application examples are discussed below.


Code Verification

This package is well suited to verify the correctness of more involved numerical techniques to determine the scattering behavior of real-world objects. For example, the scattering from PEC objects can be determined by solving the electric field integral equation (EFIE) by the method of moments (MoM). To this end, the packages BEAST and CompScienceMeshes can be employed:

using BEAST, CompScienceMeshes

# --- parameters
f = 1e8             # frequency
c = 2.99792458e8    # speed of light
μ = 4π * 1e-7       # permeability
κ = 2π * f / c      # wavenumber

# --- obtain a triangulation of the sphere
spRadius = 1.0 # radius of sphere
Γ = meshsphere(spRadius, 0.25)

# --- define basis functions on the triangulation
RT = raviartthomas(Γ)

# --- excitation by plane wave
𝐸 = Maxwell3D.planewave(; direction=ẑ, polarization=x̂, wavenumber=κ)
𝑒 = n × 𝐸 × n

# --- integral operator
𝑇 = Maxwell3D.singlelayer(; wavenumber=κ)

# --- assemble matrix and RHS of the LSE
e = -assemble(𝑒, RT)
T = assemble(𝑇, RT, RT)

# --- solve the LSE
u = T \ e
942-element Vector{ComplexF64}:
   -0.04107977702743268 - 0.27608593643934365im
   -0.06928485337418612 - 0.27708976870410673im
    0.09785418511652132 + 0.21879174094409914im
   0.002678944452833076 + 0.015127886708172885im
    0.03530860769979943 - 0.4319712103722361im
   0.025758577496156242 - 0.4305876028305452im
 -0.0018068618933935751 - 0.032413425898132196im
    0.08414041448358665 - 0.41141589795213773im
   0.007442035358325664 + 0.04632137249409413im
    0.06488963152452873 + 0.20307900872734705im
                        ⋮
  -0.014169421871694968 - 0.034253545222115066im
   -0.03698742650724021 + 0.16001233390877898im
  -0.009500592345480906 + 0.10529002576023289im
   -0.04946749622038236 - 0.07935593382383231im
     0.1339575607968854 + 0.08279348231023383im
    0.05905764297862507 + 0.032486775926679im
    0.08027615813591862 - 0.17195665241152153im
   -0.06203225022644792 + 0.06686227253332541im
   -0.03179965597036785 - 0.07451277281293911im

Now that we know the expansion coefficients for the basis functions we can compute the scattered fields:

# --- define points where the fields are computed
using SphericalScattering # use this package to get points on a spherical grid
points_cartFF, points_sphFF = sphericalGridPoints()
points_cartNF, points_sphNF = sphericalGridPoints(r=5.0)

# --- compute the fields
EF_MoM = potential(MWSingleLayerField3D(𝑇), points_cartNF, u, RT)
HF_MoM = potential(BEAST.MWDoubleLayerField3D(wavenumber=κ), points_cartNF, u, RT) / (c * μ)
FF_MoM = -im * f / (2 * c) * potential(MWFarField3D(𝑇), points_cartFF, u, RT)
dots out of 10: ..........
dots out of 10: ..........
dots out of 10: ..........

The fields for the same scenario can be obtained (more accurately) by this package:

using SphericalScattering

sp = PECSphere(radius=spRadius)
ex = planeWave(frequency=f)

EF = scatteredfield(sp, ex, ElectricField(points_cartNF))
HF = scatteredfield(sp, ex, MagneticField(points_cartNF))
FF = scatteredfield(sp, ex, FarField(points_cartFF))

The agreement between the two solutions can be determined as a worst case relative error of all evaluated points:

using LinearAlgebra

# --- relative worst case errors in percent
diff_EF = round(maximum(norm.(EF - EF_MoM) ./ maximum(norm.(EF))) * 100, digits=2)
diff_HF = round(maximum(norm.(HF - HF_MoM) ./ maximum(norm.(HF))) * 100, digits=2)
diff_FF = round(maximum(norm.(FF - FF_MoM) ./ maximum(norm.(FF))) * 100, digits=2)

print("E-field error: $diff_EF %\n")
print("H-field error: $diff_HF %\n")
print("Far-field error: $diff_FF %\n")
E-field error: 1.29 %
H-field error: 1.28 %
Far-field error: 1.37 %
Tip

When testing this package, the packages BEAST and CompScienceMeshes are used to define several functional tests.


Radar Cross Section

The monostatic and the bistatic radar cross section (RCS) can be evaluated.

Monostatic RCS

The monostatic radar cross section as a function of the sphere radius can be computed as follows (compare also the plot in [1, pp. 352ff]):

using SphericalScattering
using PlotlyJS

f = 1e8
c = 2.99792458e8    # speed of light
λ = c / f

RCS = Float64[]
aTλ = Float64[]

# --- compute RCS
for rg in 0.01:0.01:3.0

    a = λ*rg

    monoRCS = rcs(PECSphere(radius=a), planeWave(frequency=f))

    push!(RCS, monoRCS / (π * a^2))
    push!(aTλ, rg)
end

# --- plot
layout = Layout(
    yaxis=attr(title_text="RCS / πa² in dB"),
    xaxis=attr(title_text="a / λ")
)

plot(scatter(; x=aTλ, y=10*log10.(RCS), mode="lines+markers"), layout)

Bistatic RCS

The bistatic radar cross section along a ϑ-cut can be computed as follows (compare also the plot in [1, pp. 351ff]):

using StaticArrays

# --- points
ϑ = [i*π/500 for i in 0:500]
φ = 0
points_cart = [SphericalScattering.sph2cart(SVector(1.0, ϑi, φ)) for ϑi in ϑ]

# --- compute RCS
biRCS = rcs(PECSphere(radius=λ), planeWave(frequency=1e8), points_cart) / λ^2

# --- plot
layout = Layout(
    yaxis=attr(title_text="RCS / λ² in dB"),
    xaxis=attr(title_text="ϑ in degree")
)

plot(scatter(; x=ϑ*180/π, y=10*log10.(biRCS), mode="lines+markers"), layout)

Visualization of Fields

This package provides several means to directly visualize quantities of the scattering setup.

Note

In order to make the plotting functionality available the package PlotlyJS has to be loaded. (It is a weak dependency.)

Plotting Far-Field Patterns

As an example consider a Hertzian dipole that excites a PEC sphere:

using SphericalScattering
using LinearAlgebra, StaticArrays

# --- excite PEC sphere by Hertzian dipole
orient = normalize(SVector(0.0,1.0,1.0))
ex = HertzianDipole(frequency=1e8, orientation=orient, position=2*orient)

sp = PECSphere(radius = 1.0)

# --- evaluate fields at spherical grid points
points_cart, points_sph = sphericalGridPoints()

FF = scatteredfield(sp, ex, FarField(points_cart))

The 3D pattern can then be evaluated as

using PlotlyJS
plotff(FF, points_sph, scale="linear", normalize=true, type="abs")

Alternatively, the field of the dipole itself or the total field can be plotted:

FF = field(sp, ex, FarField(points_cart)) # total field

# --- plot only the φ-component in logarithmic scale
plotff(FF, points_sph, scale="log", normalize=true, type="phi")

Plotting Far-Field Cuts

Sphercial cuts can be conveniently obtained by:

using SphericalScattering
using LinearAlgebra, StaticArrays

# --- excite PEC sphere by magnetic ring current
orient = normalize(SVector(0.0,1.0,1.0))
ex = magneticRingCurrent(frequency=1e8, orientation=orient, center=2*orient, radius=0.2)

sp = PECSphere(radius = 1.0)

# --- evaluate fields at φ = 5° cut
points_cart, points_sph = phiCutPoints(5) # analogously, thetaCutPoints can be used

FF = scatteredfield(sp, ex, FarField(points_cart))

The cut can then be plotted as:

using PlotlyJS
plotffcut(norm.(FF), points_sph, normalize=true, scale="log", format="polar")

Plotting Near-Field Cuts

The near-field of an electric ring current can, e.g., be visualized in the xz-plane as:

using SphericalScattering
using LinearAlgebra, StaticArrays

f = 1e8             # frequency
c = 2.99792458e8    # speed of light
λ = c / f           # wavelength

ex = electricRingCurrent(frequency=1e8, center=SVector(0.,0,0), radius=3*λ)

# --- define points in the xz plane
res = λ/15

points_cart = [SVector(x, 0.0, z) for z in -5λ:res:5λ, x in -5λ:res:5λ]
points_sph = SphericalScattering.cart2sph.(points_cart)

# --- evaluate the fields
E = field(ex, ElectricField(points_cart))

To plot the fields a heatmap can be employed:

using PlotlyJS

# --- convert data to spherical coordinates
Esph = SphericalScattering.convertCartesian2Spherical.(E, points_sph)
Eφ = [Esph[i][3] for (i, j) in enumerate(Esph)] # extract φ-component

# --- truncate large values (for plot)
data = abs.(Eφ)
data[data .> 250] .= 250

# --- plot heatmap
layout = Layout(
    yaxis=attr(title_text="y/λ"),
    xaxis=attr(title_text="x/λ")
)

plot(heatmap(x=-5:1/15:5,y=-5:1/15:5,z=data, colorscale="Jet"), layout)

Or instead of the magnitude a snapshot can be plotted

data = real.(Eφ)
data[data .> 250] .= 250

# --- plot heatmap
layout = Layout(
    yaxis=attr(title_text="y/λ"),
    xaxis=attr(title_text="x/λ")
)

plot(heatmap(x=-5:1/15:5,y=-5:1/15:5,z=data, colorscale="Jet"), layout)