你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-04 11:36:52 +08:00
213 行
8.0 KiB
Python
213 行
8.0 KiB
Python
# Copyright (C) 2016, Craig Warren
|
|
#
|
|
# This module is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
# To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
|
|
#
|
|
# Please use the attribution at http://dx.doi.org/10.1016/j.sigpro.2016.04.010
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
|
|
import h5py
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
|
|
from scipy.constants import c
|
|
from scipy.constants import epsilon_0 as e0
|
|
from scipy.constants import mu_0 as m0
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Impedance of free space (Ohms)
|
|
z0 = np.sqrt(m0 / e0)
|
|
|
|
# Parse command line arguments
|
|
parser = argparse.ArgumentParser(
|
|
description="Calculate and store (in a Numpy file) field patterns from a simulation with receivers positioned in circles around an antenna.",
|
|
usage="cd gprMax; python -m user_libs.AntennaPatterns.initial_save outputfile",
|
|
)
|
|
parser.add_argument("outputfile", help="name of gprMax output file including path")
|
|
args = parser.parse_args()
|
|
outputfile = args.outputfile
|
|
|
|
########################################
|
|
# User configurable parameters
|
|
|
|
# Pattern type (E or H)
|
|
type = "H"
|
|
|
|
# Antenna (true if using full antenna model; false for a theoretical Hertzian dipole
|
|
antenna = True
|
|
|
|
# Relative permittivity of half-space for homogeneous materials (set to None for inhomogeneous)
|
|
epsr = 5
|
|
|
|
# Observation radii and angles
|
|
radii = np.linspace(0.1, 0.3, 20)
|
|
theta = np.linspace(3, 357, 60) * (180 / np.pi)
|
|
|
|
# Scaling of time-domain field pattern values by material impedance
|
|
impscaling = False
|
|
|
|
# Centre frequency of modelled antenna
|
|
f = 1.5e9 # GSSI 1.5GHz antenna model
|
|
|
|
# Largest dimension of antenna transmitting element
|
|
D = 0.060 # GSSI 1.5GHz antenna model
|
|
|
|
# Traces to plot for sanity checking
|
|
traceno = np.s_[:] # All traces
|
|
########################################
|
|
|
|
# Critical angle and velocity
|
|
if epsr:
|
|
mr = 1
|
|
z1 = np.sqrt(mr / epsr) * z0
|
|
v1 = c / np.sqrt(epsr)
|
|
thetac = np.round(np.arcsin(v1 / c * (180 / np.pi)))
|
|
wavelength = v1 / f
|
|
|
|
# Print some useful information
|
|
logger.info(f"Centre frequency: {f / 1000000000.0} GHz")
|
|
if epsr:
|
|
logger.info(f"Critical angle for Er {epsr} is {thetac} degrees")
|
|
logger.info(f"Wavelength: {wavelength:.3f} m")
|
|
logger.info(
|
|
"Observation distance(s) from {:.3f} m ({:.1f} wavelengths) to {:.3f} m ({:.1f} wavelengths)".format(
|
|
radii[0], radii[0] / wavelength, radii[-1], radii[-1] / wavelength
|
|
)
|
|
)
|
|
logger.info(
|
|
"Theoretical boundary between reactive & radiating near-field (0.62*sqrt((D^3/wavelength): {:.3f} m".format(
|
|
0.62 * np.sqrt((D**3) / wavelength)
|
|
)
|
|
)
|
|
logger.info(
|
|
"Theoretical boundary between radiating near-field & far-field (2*D^2/wavelength): {:.3f} m".format(
|
|
(2 * D**2) / wavelength
|
|
)
|
|
)
|
|
|
|
# Load text file with coordinates of pattern origin
|
|
origin = np.loadtxt(os.path.splitext(outputfile)[0] + "_rxsorigin.txt")
|
|
|
|
# Load output file and read some header information
|
|
f = h5py.File(outputfile, "r")
|
|
iterations = f.attrs["Iterations"]
|
|
dt = f.attrs["dt"]
|
|
nrx = f.attrs["nrx"]
|
|
if antenna:
|
|
nrx = nrx - 1 # Ignore first receiver point with full antenna model
|
|
start = 2
|
|
else:
|
|
start = 1
|
|
time = np.arange(0, dt * iterations, dt)
|
|
time = time / 1e-9
|
|
fs = 1 / dt # Sampling frequency
|
|
|
|
# Initialise arrays to store fields
|
|
coords = np.zeros((nrx, 3), dtype=np.float32)
|
|
Ex = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Ey = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Ez = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Hx = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Hy = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Hz = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Er = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Etheta = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Ephi = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Hr = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Htheta = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Hphi = np.zeros((iterations, nrx), dtype=np.float32)
|
|
Ethetasum = np.zeros(len(theta), dtype=np.float32)
|
|
Hthetasum = np.zeros(len(theta), dtype=np.float32)
|
|
patternsave = np.zeros((len(radii), len(theta)), dtype=np.float32)
|
|
|
|
for rx in range(0, nrx):
|
|
path = "/rxs/rx" + str(rx + start) + "/"
|
|
position = f[path].attrs["Position"][:]
|
|
coords[rx, :] = position - origin
|
|
Ex[:, rx] = f[path + "Ex"][:]
|
|
Ey[:, rx] = f[path + "Ey"][:]
|
|
Ez[:, rx] = f[path + "Ez"][:]
|
|
Hx[:, rx] = f[path + "Hx"][:]
|
|
Hy[:, rx] = f[path + "Hy"][:]
|
|
Hz[:, rx] = f[path + "Hz"][:]
|
|
f.close()
|
|
|
|
# Plot traces for sanity checking
|
|
# fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6)) = plt.subplots(num=outputfile, nrows=3, ncols=2, sharex=False, sharey='col', subplot_kw=dict(xlabel='Time [ns]'), figsize=(20, 10), facecolor='w', edgecolor='w')
|
|
# ax1.plot(time, Ex[:, traceno],'r', lw=2)
|
|
# ax1.set_ylabel('$E_x$, field strength [V/m]')
|
|
# ax3.plot(time, Ey[:, traceno],'r', lw=2)
|
|
# ax3.set_ylabel('$E_y$, field strength [V/m]')
|
|
# ax5.plot(time, Ez[:, traceno],'r', lw=2)
|
|
# ax5.set_ylabel('$E_z$, field strength [V/m]')
|
|
# ax2.plot(time, Hx[:, traceno],'b', lw=2)
|
|
# ax2.set_ylabel('$H_x$, field strength [A/m]')
|
|
# ax4.plot(time, Hy[:, traceno],'b', lw=2)
|
|
# ax4.set_ylabel('$H_y$, field strength [A/m]')
|
|
# ax6.plot(time, Hz[:, traceno],'b', lw=2)
|
|
# ax6.set_ylabel('$H_z$, field strength [A/m]')
|
|
# Turn on grid
|
|
# [ax.grid() for ax in fig.axes]
|
|
# plt.show()
|
|
|
|
# Calculate fields for patterns
|
|
rxstart = 0 # Index for rx points
|
|
for radius in range(0, len(radii)):
|
|
index = 0
|
|
# Observation points
|
|
for pt in range(rxstart, rxstart + len(theta)):
|
|
# Cartesian to spherical coordinate transform coefficients from (Kraus,1991,Electromagnetics,p.34)
|
|
r1 = coords[pt, 0] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
r2 = coords[pt, 1] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
r3 = coords[pt, 2] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
theta1 = (coords[pt, 0] * coords[pt, 2]) / (
|
|
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
|
|
* np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
)
|
|
theta2 = (coords[pt, 1] * coords[pt, 2]) / (
|
|
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
|
|
* np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
)
|
|
theta3 = -(
|
|
np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
|
|
/ np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2 + coords[pt, 2] ** 2)
|
|
)
|
|
phi1 = -(coords[pt, 1] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2))
|
|
phi2 = coords[pt, 0] / np.sqrt(coords[pt, 0] ** 2 + coords[pt, 1] ** 2)
|
|
phi3 = 0
|
|
|
|
# Fields in spherical coordinates
|
|
Er[:, index] = Ex[:, pt] * r1 + Ey[:, pt] * r2 + Ez[:, pt] * r3
|
|
Etheta[:, index] = Ex[:, pt] * theta1 + Ey[:, pt] * theta2 + Ez[:, pt] * theta3
|
|
Ephi[:, index] = Ex[:, pt] * phi1 + Ey[:, pt] * phi2 + Ez[:, pt] * phi3
|
|
Hr[:, index] = Hx[:, pt] * r1 + Hy[:, pt] * r2 + Hz[:, pt] * r3
|
|
Htheta[:, index] = Hx[:, pt] * theta1 + Hy[:, pt] * theta2 + Hz[:, pt] * theta3
|
|
Hphi[:, index] = Hx[:, pt] * phi1 + Hy[:, pt] * phi2 + Hz[:, pt] * phi3
|
|
|
|
# Calculate metric for time-domain field pattern values
|
|
if impscaling and coords[pt, 2] < 0:
|
|
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / z1
|
|
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / z1
|
|
else:
|
|
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / z0
|
|
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / z0
|
|
|
|
index += 1
|
|
|
|
if type == "H":
|
|
# Flip H-plane patterns as rx points are written CCW but always plotted CW
|
|
patternsave[radius, :] = Hthetasum[::-1]
|
|
elif type == "E":
|
|
patternsave[radius, :] = Ethetasum
|
|
|
|
rxstart += len(theta)
|
|
|
|
# Save pattern to numpy file
|
|
np.save(os.path.splitext(outputfile)[0], patternsave)
|
|
logger.info(f"Written Numpy file: {os.path.splitext(outputfile)[0]}.npy")
|