import numpy as np
from matplotlib import pyplot as plt
from astrohack.antenna.base_panel import BasePanel, markersize
from astrohack.antenna.panel_fitting import PanelPoint
[docs]
class RingPanel(BasePanel):
# This class describes and treats panels that are arranged in
# rings on the Antenna surface
def __init__(
self,
model,
angle,
ipanel,
label,
inrad,
ourad,
margin=0.20,
screw_scheme=None,
screw_offset=None,
plot_screw_size=0.20,
):
"""
Initializes a panel that is a section of a ring in a circular antenna
Fitting method kinds are:
AIPS fitting kinds:
mean: The panel is corrected by the mean of its samples
rigid: The panel samples are fitted to a rigid surface
Corotated Paraboloids (the two bending axes are parallel and perpendicular to the radius of the antenna crossing
the middle of the panel):
corotated_scipy: Paraboloid is fitted using scipy.optimize, robust but slow
corotated_lst_sq: Paraboloid is fitted using the linear algebra least squares method, fast but unreliable
corotated_robust: Tries corotated_lst_sq, if it diverges falls back to corotated_scipy
Experimental fitting kinds:
xy_paraboloid: fitted using scipy.optimize, bending axes are parallel to the x and y axes
rotated_paraboloid: fitted using scipy.optimize, bending axes can be rotated by an arbitrary angle
full_paraboloid_lst_sq: Full 9 parameter paraboloid fitted using least_squares method, heavily overfits
Args:
model: What kind of surface fitting method to be used
angle: Azimuthal span of the panel
ipanel: Panel number clockwise from top
label: Panel label
inrad: Radius at panel inner side
ourad: Radius at panel outer side
margin: Fraction from panel edge inwards that won't be used for fitting
screw_scheme: tuple containing the description of screw positions
"""
[docs]
self.theta1 = ipanel * angle
[docs]
self.theta2 = (ipanel + 1) * angle
dradius = ourad - inrad
[docs]
self.margin_theta1 = self.theta1 + margin * angle
[docs]
self.margin_theta2 = self.theta2 - margin * angle
[docs]
self.margin_inrad = inrad + margin * dradius
[docs]
self.margin_ourad = ourad - margin * dradius
[docs]
self.first = ipanel == 0
zeta = (ipanel + 0.5) * angle
rt = (self.inrad + self.ourad) / 2
[docs]
self.center = PanelPoint(-rt * np.sin(zeta), rt * np.cos(zeta))
screws = self._init_screws(screw_scheme, screw_offset)
plot_screw_pos = self._init_screws(screw_scheme, 2 * plot_screw_size)
fi = self.theta2 - self.theta1
x1 = self.inrad * np.sin(fi / 2.0)
x2 = self.ourad * np.sin(fi / 2.0)
y2 = self.ourad * np.cos(fi / 2.0)
# Now we are ready to initialize the base object
super().__init__(
model,
screws,
plot_screw_pos,
plot_screw_size,
label,
center=self.center,
zeta=zeta,
ref_points=[x1, x2, y2],
)
def _init_screws(self, scheme, offset):
"""
Initialize screws according to the scheme
Args:
scheme: Tuple of strings containing the positioning of the screws
offset: How far from the edge of the panel are corner screws (meters)
Returns:
numpy array with the positions of the screws
"""
if scheme is None:
scheme = ["il", "ir", "ol", "or"]
if offset is None:
offset = 1e-2 # 1 cm
nscrews = len(scheme)
screws = np.ndarray([nscrews], dtype=np.object_)
for iscrew in range(nscrews):
if scheme[iscrew] == "c":
screws[iscrew] = self.center
else:
if scheme[iscrew][0] == "i":
radius = self.inrad + offset
else:
radius = self.ourad - offset
deltatheta = offset / radius
if scheme[iscrew][1] == "l":
theta = self.theta1 + deltatheta
else:
theta = self.theta2 - deltatheta
screws[iscrew] = PanelPoint(
-radius * np.sin(theta), radius * np.cos(theta)
)
return screws
[docs]
def is_inside(self, rad, phi):
"""
Check if a point is inside a panel using polar coordinates
Args:
rad: radius of the point
phi: angle of the point in polar coordinates
Returns:
issample: True if point is inside the fitting part of the panel
inpanel: True if point is inside the panel
"""
# Simple test of polar coordinates to check that a point is
# inside this panel
angle = self.theta1 <= phi <= self.theta2
radius = self.inrad <= rad <= self.ourad
inpanel = angle and radius
angle = self.margin_theta1 <= phi <= self.margin_theta2
radius = self.margin_inrad <= rad <= self.margin_ourad
issample = angle and radius
return issample, inpanel
[docs]
def print_misc(self):
"""
Print miscelaneous information about the panel to the terminal
"""
print("########################################")
print("{0:20s}={1:8s}".format("ipanel", self.label))
print("{0:20s}={1:8s}".format("model", " " + self.model_name))
print("{0:20s}={1:8.5f}".format("inrad", self.inrad))
print("{0:20s}={1:8.5f}".format("ourad", self.ourad))
print("{0:20s}={1:8.5f}".format("theta1", self.theta1))
print("{0:20s}={1:8.5f}".format("theta2", self.theta2))
print("{0:20s}={1:8.5f}".format("zeta", self.zeta))
print()
[docs]
def plot(self, ax, screws=False, label=False, _=False, samples=False):
"""
Plot panel outline to ax
Args:
ax: matplotlib axes instance
screws: Display screws in plot
label: Add panel labels to plot
_: does nothing (interface compatibility)
samples: plot samples and margins
"""
x1 = self.inrad * np.sin(self.theta1)
y1 = self.inrad * np.cos(self.theta1)
x2 = self.ourad * np.sin(self.theta1)
y2 = self.ourad * np.cos(self.theta1)
ax.plot(
[x1, x2],
[y1, y2],
ls="-",
color=self.linecolor,
marker=None,
lw=self.linewidth,
)
if self.first:
# Draw ring outline with first panel
inrad = plt.Circle(
(0, 0), self.inrad, color=self.linecolor, fill=False, lw=self.linewidth
)
ourad = plt.Circle(
(0, 0), self.ourad, color=self.linecolor, fill=False, lw=self.linewidth
)
ax.add_patch(inrad)
ax.add_patch(ourad)
if label:
self.plot_label(ax)
if screws:
self.plot_screws(ax)
if samples and len(self.samples) > 0:
for sample in self.samples:
ax.scatter(sample.xc, sample.yc, color="black", s=markersize)
for marg in self.margins:
ax.scatter(marg.xc, marg.yc, color="red", s=markersize)