你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-08 07:24:19 +08:00
Added a pre-commit config file and reformatted all the files accordingly by using it.
这个提交包含在:
@@ -18,8 +18,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# 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')
|
||||
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
|
||||
|
||||
@@ -27,7 +30,7 @@ outputfile = args.outputfile
|
||||
# User configurable parameters
|
||||
|
||||
# Pattern type (E or H)
|
||||
type = 'H'
|
||||
type = "H"
|
||||
|
||||
# Antenna (true if using full antenna model; false for a theoretical Hertzian dipole
|
||||
antenna = True
|
||||
@@ -55,35 +58,47 @@ traceno = np.s_[:] # All traces
|
||||
# Critical angle and velocity
|
||||
if epsr:
|
||||
mr = 1
|
||||
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0']
|
||||
v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr)
|
||||
thetac = np.round(np.arcsin(v1 / config.sim_config.em_consts['c']) * (180 / np.pi))
|
||||
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts["z0"]
|
||||
v1 = config.sim_config.em_consts["c"] / np.sqrt(epsr)
|
||||
thetac = np.round(np.arcsin(v1 / config.sim_config.em_consts["c"]) * (180 / np.pi))
|
||||
wavelength = v1 / f
|
||||
|
||||
# Print some useful information
|
||||
logger.info('Centre frequency: {} GHz'.format(f / 1e9))
|
||||
logger.info("Centre frequency: {} GHz".format(f / 1e9))
|
||||
if epsr:
|
||||
logger.info('Critical angle for Er {} is {} degrees'.format(epsr, thetac))
|
||||
logger.info('Wavelength: {:.3f} m'.format(wavelength))
|
||||
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))
|
||||
logger.info("Critical angle for Er {} is {} degrees".format(epsr, thetac))
|
||||
logger.info("Wavelength: {:.3f} m".format(wavelength))
|
||||
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')
|
||||
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']
|
||||
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
|
||||
time = time / 1e-9
|
||||
fs = 1 / dt # Sampling frequency
|
||||
|
||||
# Initialise arrays to store fields
|
||||
@@ -105,15 +120,15 @@ 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'][:]
|
||||
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'][:]
|
||||
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
|
||||
@@ -141,14 +156,23 @@ for radius in range(0, len(radii)):
|
||||
# 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)
|
||||
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
|
||||
@@ -161,22 +185,22 @@ for radius in range(0, len(radii)):
|
||||
|
||||
# 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
|
||||
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / z1
|
||||
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / z1
|
||||
else:
|
||||
Ethetasum[index] = np.sum(Etheta[:, index]**2) / config.sim_config.em_consts['z0']
|
||||
Hthetasum[index] = np.sum(Htheta[:, index]**2) / config.sim_config.em_consts['z0']
|
||||
Ethetasum[index] = np.sum(Etheta[:, index] ** 2) / config.sim_config.em_consts["z0"]
|
||||
Hthetasum[index] = np.sum(Htheta[:, index] ** 2) / config.sim_config.em_consts["z0"]
|
||||
|
||||
index += 1
|
||||
|
||||
if type == 'H':
|
||||
if type == "H":
|
||||
# Flip H-plane patterns as rx points are written CCW but always plotted CW
|
||||
patternsave[radius, :] = Hthetasum[::-1]
|
||||
elif type == 'E':
|
||||
elif type == "E":
|
||||
patternsave[radius, :] = Ethetasum
|
||||
|
||||
rxstart += len(theta)
|
||||
|
||||
# Save pattern to numpy file
|
||||
np.save(os.path.splitext(outputfile)[0], patternsave)
|
||||
logger.info('Written Numpy file: {}.npy'.format(os.path.splitext(outputfile)[0]))
|
||||
logger.info("Written Numpy file: {}.npy".format(os.path.splitext(outputfile)[0]))
|
||||
|
@@ -17,8 +17,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Parse command line arguments
|
||||
parser = argparse.ArgumentParser(description='Plot field patterns from a simulation with receivers positioned in circles around an antenna. This module should be used after the field pattern data has been processed and stored using the initial_save.py module.', usage='cd gprMax; python -m user_libs.AntennaPatterns.plot_fields numpyfile')
|
||||
parser.add_argument('numpyfile', help='name of numpy file including path')
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Plot field patterns from a simulation with receivers positioned in circles around an antenna. This module should be used after the field pattern data has been processed and stored using the initial_save.py module.",
|
||||
usage="cd gprMax; python -m user_libs.AntennaPatterns.plot_fields numpyfile",
|
||||
)
|
||||
parser.add_argument("numpyfile", help="name of numpy file including path")
|
||||
# parser.add_argument('hertzian', help='name of numpy file including path')
|
||||
args = parser.parse_args()
|
||||
patterns = np.load(args.numpyfile)
|
||||
@@ -28,7 +31,7 @@ patterns = np.load(args.numpyfile)
|
||||
# User configurable parameters
|
||||
|
||||
# Pattern type (E or H)
|
||||
type = 'H'
|
||||
type = "H"
|
||||
|
||||
# Relative permittivity of half-space for homogeneous materials (set to None for inhomogeneous)
|
||||
epsr = 5
|
||||
@@ -52,33 +55,45 @@ step = 12
|
||||
# Critical angle and velocity
|
||||
if epsr:
|
||||
mr = 1
|
||||
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts['z0']
|
||||
v1 = config.sim_config.em_consts['c'] / np.sqrt(epsr)
|
||||
thetac = np.round(np.rad2deg(np.arcsin(v1 / config.sim_config.em_consts['c'])))
|
||||
z1 = np.sqrt(mr / epsr) * config.sim_config.em_consts["z0"]
|
||||
v1 = config.sim_config.em_consts["c"] / np.sqrt(epsr)
|
||||
thetac = np.round(np.rad2deg(np.arcsin(v1 / config.sim_config.em_consts["c"])))
|
||||
wavelength = v1 / f
|
||||
|
||||
# Print some useful information
|
||||
logger.info('Centre frequency: {} GHz'.format(f / 1e9))
|
||||
logger.info("Centre frequency: {} GHz".format(f / 1e9))
|
||||
if epsr:
|
||||
logger.info('Critical angle for Er {} is {} degrees'.format(epsr, thetac))
|
||||
logger.info('Wavelength: {:.3f} m'.format(wavelength))
|
||||
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))
|
||||
logger.info("Critical angle for Er {} is {} degrees".format(epsr, thetac))
|
||||
logger.info("Wavelength: {:.3f} m".format(wavelength))
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
# Setup figure
|
||||
fig = plt.figure(num=args.numpyfile, figsize=(8, 8), facecolor='w', edgecolor='w')
|
||||
fig = plt.figure(num=args.numpyfile, figsize=(8, 8), facecolor="w", edgecolor="w")
|
||||
ax = plt.subplot(111, polar=True)
|
||||
cmap = plt.cm.get_cmap('rainbow')
|
||||
ax.set_prop_cycle('color', [cmap(i) for i in np.linspace(0, 1, len(radii))])
|
||||
cmap = plt.cm.get_cmap("rainbow")
|
||||
ax.set_prop_cycle("color", [cmap(i) for i in np.linspace(0, 1, len(radii))])
|
||||
|
||||
# Critical angle window and air/subsurface interface lines
|
||||
if epsr:
|
||||
ax.plot([0, np.deg2rad(180 - thetac)], [min, 0], color='0.7', lw=2)
|
||||
ax.plot([0, np.deg2rad(180 + thetac)], [min, 0], color='0.7', lw=2)
|
||||
ax.plot([np.deg2rad(270), np.deg2rad(90)], [0, 0], color='0.7', lw=2)
|
||||
ax.annotate('Air', xy=(np.deg2rad(270), 0), xytext=(8, 8), textcoords='offset points')
|
||||
ax.annotate('Ground', xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords='offset points')
|
||||
ax.plot([0, np.deg2rad(180 - thetac)], [min, 0], color="0.7", lw=2)
|
||||
ax.plot([0, np.deg2rad(180 + thetac)], [min, 0], color="0.7", lw=2)
|
||||
ax.plot([np.deg2rad(270), np.deg2rad(90)], [0, 0], color="0.7", lw=2)
|
||||
ax.annotate("Air", xy=(np.deg2rad(270), 0), xytext=(8, 8), textcoords="offset points")
|
||||
ax.annotate("Ground", xy=(np.deg2rad(270), 0), xytext=(8, -15), textcoords="offset points")
|
||||
|
||||
# Plot patterns
|
||||
for patt in range(0, len(radii)):
|
||||
@@ -86,12 +101,12 @@ for patt in range(0, len(radii)):
|
||||
pattplot = pattplot / np.max(np.max(patterns)) # Normalise, based on set of patterns
|
||||
|
||||
# Calculate power (ignore warning from taking a log of any zero values)
|
||||
with np.errstate(divide='ignore'):
|
||||
with np.errstate(divide="ignore"):
|
||||
power = 10 * np.log10(pattplot)
|
||||
# Replace any NaNs or Infs from zero division
|
||||
power[np.invert(np.isfinite(power))] = 0
|
||||
|
||||
ax.plot(theta, power, label='{:.2f}m'.format(radii[patt]), marker='.', ms=6, lw=1.5)
|
||||
ax.plot(theta, power, label="{:.2f}m".format(radii[patt]), marker=".", ms=6, lw=1.5)
|
||||
|
||||
# Add Hertzian dipole plot
|
||||
# hertzplot1 = np.append(hertzian[0, :], hertzian[0, 0]) # Append start value to close circle
|
||||
@@ -102,8 +117,8 @@ for patt in range(0, len(radii)):
|
||||
# ax.plot(theta, 10 * np.log10(hertzplot2), label='Inf. dipole, 0.58m', color='black', ls='--', lw=3)
|
||||
|
||||
# Theta axis options
|
||||
ax.set_theta_zero_location('N')
|
||||
ax.set_theta_direction('clockwise')
|
||||
ax.set_theta_zero_location("N")
|
||||
ax.set_theta_direction("clockwise")
|
||||
ax.set_thetagrids(np.arange(0, 360, 30))
|
||||
|
||||
# Radial axis options
|
||||
@@ -111,19 +126,21 @@ ax.set_rmax(0)
|
||||
ax.set_rlabel_position(45)
|
||||
ax.set_yticks(np.arange(min, step, step))
|
||||
yticks = ax.get_yticks().tolist()
|
||||
yticks[-1] = '0 dB'
|
||||
yticks[-1] = "0 dB"
|
||||
ax.set_yticklabels(yticks)
|
||||
|
||||
# Grid and legend
|
||||
ax.grid(True)
|
||||
handles, existlabels = ax.get_legend_handles_labels()
|
||||
leg = ax.legend([handles[0], handles[-1]], [existlabels[0], existlabels[-1]], ncol=2, loc=(0.27, -0.12), frameon=False) # Plot just first and last legend entries
|
||||
leg = ax.legend(
|
||||
[handles[0], handles[-1]], [existlabels[0], existlabels[-1]], ncol=2, loc=(0.27, -0.12), frameon=False
|
||||
) # Plot just first and last legend entries
|
||||
# leg = ax.legend([handles[0], handles[-3], handles[-2], handles[-1]], [existlabels[0], existlabels[-3], existlabels[-2], existlabels[-1]], ncol=4, loc=(-0.13,-0.12), frameon=False)
|
||||
[legobj.set_linewidth(2) for legobj in leg.legendHandles]
|
||||
|
||||
# Save a pdf of the plot
|
||||
savename = os.path.splitext(args.numpyfile)[0] + '.pdf'
|
||||
fig.savefig(savename, dpi=None, format='pdf', bbox_inches='tight', pad_inches=0.1)
|
||||
savename = os.path.splitext(args.numpyfile)[0] + ".pdf"
|
||||
fig.savefig(savename, dpi=None, format="pdf", bbox_inches="tight", pad_inches=0.1)
|
||||
# savename = os.path.splitext(args.numpyfile)[0] + '.png'
|
||||
# fig.savefig(savename, dpi=150, format='png', bbox_inches='tight', pad_inches=0.1)
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户