import datetime
from abc import abstractmethod
from collections.abc import Sequence
from ...base import Property, Base
[docs]
class BeamTransitionModel(Base):
"""Base class for Beam Transition Model"""
centre: Sequence = Property(doc="Centre of the beam pattern")
[docs]
@abstractmethod
def move_beam(self, timestamp, **kwargs):
"""Gives position of beam at given time"""
raise NotImplementedError
[docs]
class StationaryBeam(BeamTransitionModel):
"""Stationary beam that points in the direction of centre"""
[docs]
def move_beam(self, *args, **kwargs):
""" generates a beam position based on the centre
Parameters
----------
Returns
-------
azimuth : `float`
azimuth from the perspective of the radar at given timestamp
elevation : `float`
elevation from the perspective of the radar at given timestamp
"""
return self.centre
[docs]
class BeamSweep(BeamTransitionModel):
"""This describes a beam moving in a raster pattern"""
init_time: datetime.datetime = Property(default=None, doc="The time the frame is started")
angle_per_s: float = Property(doc="The speed that the beam scans at")
frame: tuple[float, float] = Property(doc="Dimensions of search frame as [azimuth,elevation]")
separation: float = Property(doc="Separation of lines in elevation")
centre: tuple[float, float] = Property(
default=(0, 0),
doc="Centre of the search frame in [azimuth,elevation]. Defaults to (0, 0)")
@property
def length_frame(self):
return self.frame[0] * (self.frame[1] / self.separation + 1)
@property
def frame_time(self):
return self.length_frame / self.angle_per_s
[docs]
def move_beam(self, timestamp, **kwargs):
"""Returns the position of the beam at given timestamp
Parameters
----------
timestamp : `datetime.datetime`
current timestep
Returns
-------
azimuth : `float`
azimuth from the perspective of the radar at given timestamp
elevation : `float`
elevation from the perspective of the radar at given timestamp
"""
if self.init_time is None:
self.init_time = timestamp
time_diff = timestamp - self.init_time
# distance into a frame
total_angle = (time_diff.total_seconds() * self.angle_per_s) % \
self.length_frame
# the row the beam should be in
row = int(total_angle / (self.frame[0]))
# how far the beam is into the the current row
col = total_angle - row*self.frame[0]
# start from left or right?
if row % 2 == 0:
az = col
else:
az = self.frame[0] - col
# azimuth position
az = az - self.frame[0]/2 + self.centre[0]
# elevation position
el = self.frame[1]/2 + self.centre[1] - row*self.separation
return az, el