Source code for stonesoup.sensor.base

# -*- coding: utf-8 -*-
import weakref
from abc import abstractmethod, ABC
from typing import Optional
from warnings import warn

from ..types.array import StateVector
from ..platform import Platform

from ..base import Base


[docs]class BaseSensor(Base, ABC): """Sensor base class .. warning:: This class is private and should not be used or subclassed directly. Instead use the :class:`~.Sensor` class which is needed to achieve the functionality described in this class's documentation. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._platform_system = None @property def platform(self) -> Optional[Platform]: """Return the platform system to which the sensor is attached. Resolves the ``weakref`` stored in the :attr:`platform_system` Property.""" if self.platform_system is None: return None else: return self.platform_system() @property def platform_system(self) -> Optional[weakref.ref]: """Return a ``weakref`` to the platform on which the sensor is mounted""" return self._platform_system @platform_system.setter def platform_system(self, value: weakref.ref): # this slightly odd construction is to allow overriding by the Sensor subclass self._set_platform_system(value) def _set_platform_system(self, value: weakref.ref): if self._platform_system is not None: warn('Sensor has been moved from one platform to another. This is unexpected ' 'behaviour') self._platform_system = value @abstractmethod def measure(self, **kwargs): raise NotImplementedError @property def position(self) -> Optional[StateVector]: """The sensor position on a 3D Cartesian plane, expressed as a 3x1 :class:`StateVector` of Cartesian coordinates in the order :math:`x,y,z`. .. note:: This property delegates the actual calculation of position to the platform on which the sensor is mounted. It is settable if, and only if, the sensor holds its own internal platform.""" if self.platform is None: return None return self.platform.get_sensor_position(self) @position.setter def position(self, value: StateVector): if self._has_internal_platform: self.platform.position = value else: raise AttributeError('Cannot set sensor position unless the sensor has its own ' 'default platform') @property def orientation(self) -> Optional[StateVector]: """A 3x1 StateVector of angles (rad), specifying the sensor orientation in terms of the counter-clockwise rotation around each Cartesian axis in the order :math:`x,y,z`. The rotation angles are positive if the rotation is in the counter-clockwise direction when viewed by an observer looking along the respective rotation axis, towards the origin. .. note:: This property delegates the actual calculation of orientation to the platform on which the sensor is mounted. It is settable if, and only if, the sensor holds its own internal platform.""" if self.platform is None: return None return self.platform.get_sensor_orientation(self) @orientation.setter def orientation(self, value: StateVector): if self._has_internal_platform: self.platform.orientation = value else: raise AttributeError('Cannot set sensor position unless the sensor has its own ' 'default platform') @property def _has_internal_platform(self) -> bool: return False @property def velocity(self) -> Optional[StateVector]: """The sensor velocity on a 3D Cartesian plane, expressed as a 3x1 :class:`StateVector` of Cartesian coordinates in the order :math:`x,y,z`. .. note:: This property delegates the actual calculation of velocity to the platform on which the sensor is mounted. It is settable if, and only if, the sensor holds its own internal platform which is a MovingPlatfom.""" return self.platform.velocity