2022-03-11 16:40:02 +01:00
|
|
|
import numpy as np
|
|
|
|
from functools import partial
|
|
|
|
|
2022-03-24 12:16:14 +01:00
|
|
|
def distance(x1, x2):
|
|
|
|
"""
|
|
|
|
Calculate the Euclidean distance between two locations x1 and x2
|
|
|
|
"""
|
2022-03-24 15:10:06 +01:00
|
|
|
return np.sqrt( np.sum( (x1 - x2)**2, axis=-1) )
|
2022-03-24 12:16:14 +01:00
|
|
|
|
2022-03-24 13:05:51 +01:00
|
|
|
def plot_geometry(ax, emitters=[], antennae=[], unit='m'):
|
|
|
|
"""
|
|
|
|
Show the geometry of emitters and antennae in a square plot.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
ax - matplotlib.Axes
|
|
|
|
The axis object to plot the geometry on.
|
|
|
|
emitters - list of Locations
|
|
|
|
The Emitter objects to plot.
|
|
|
|
antennae - list of Locations
|
|
|
|
The Receiver objects to plot.
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
ax - matplotlib.Axes
|
|
|
|
The axis object containing the plotted geometry.
|
|
|
|
annots - dict of list of matplotlib.text.Annotation
|
|
|
|
The dictionary is split up into a list of annotations
|
|
|
|
belonging to the emitters, and one for the antennae.
|
|
|
|
"""
|
|
|
|
|
|
|
|
ax.grid()
|
|
|
|
ax.set_title("Geometry of Emitter(s) and Antennae")
|
|
|
|
ax.set_ylabel("y ({})".format(unit))
|
|
|
|
ax.set_xlabel("x ({})".format(unit))
|
|
|
|
ax.margins(0.3)
|
|
|
|
ax.set_aspect('equal', 'datalim') # make it a square plot
|
|
|
|
|
|
|
|
annots = {}
|
|
|
|
for k, locs in {"E": emitters, "A": antennae}.items():
|
|
|
|
if k == "E":
|
|
|
|
marker='*'
|
|
|
|
prefix = k
|
|
|
|
elif k == "A":
|
|
|
|
marker="o"
|
|
|
|
prefix = k
|
|
|
|
|
|
|
|
# create the list of annotations
|
|
|
|
if k not in annots:
|
|
|
|
annots[k] = []
|
|
|
|
|
|
|
|
# plot marker and create annotation
|
|
|
|
for j, loc in enumerate(locs):
|
|
|
|
label = "{}{}".format(prefix, j)
|
|
|
|
ax.plot(*loc.x, marker=marker, label=label)
|
|
|
|
annots[k].append(ax.annotate(label, loc.x))
|
|
|
|
|
|
|
|
return ax, annots
|
|
|
|
|
2022-03-11 16:40:02 +01:00
|
|
|
class Location:
|
|
|
|
"""
|
|
|
|
A location is a point designated by a spatial coordinate x.
|
|
|
|
|
|
|
|
Locations are wrappers around a Numpy N-dimensional array.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, x):
|
|
|
|
self.x = np.asarray(x)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "Location({})".format(repr(self.x))
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
return self.x[key]
|
|
|
|
|
|
|
|
def __setitem__(self, key, val):
|
|
|
|
self.x[key] = val
|
|
|
|
|
2022-03-24 12:16:14 +01:00
|
|
|
def distance(self, other):
|
|
|
|
if isinstance(other, Location):
|
|
|
|
other = other.x
|
|
|
|
|
|
|
|
return distance(self.x, other)
|
|
|
|
|
2022-03-11 16:40:02 +01:00
|
|
|
# math
|
|
|
|
def __add__(self, other):
|
|
|
|
if isinstance(other, Location):
|
|
|
|
other = other.x
|
|
|
|
|
|
|
|
return self.__class__(self.x + other)
|
|
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
if isinstance(other, Location):
|
|
|
|
other = other.x
|
|
|
|
|
|
|
|
return self.__class__(self.x - other)
|
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
return self.__class__(self.x * other)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
if isinstance(other, Location):
|
|
|
|
other = other.x
|
|
|
|
|
|
|
|
return np.all(self.x == other)
|
|
|
|
|
|
|
|
# math alias functions
|
|
|
|
__radd__ = __add__
|
|
|
|
__rsub__ = __sub__
|
|
|
|
__rmul__ = __mul__
|