示例#1
0
    def move(self, timestamp=None, **kwargs) -> None:
        """Propagate the platform position using the :attr:`transition_model`.

        Parameters
        ----------
        timestamp: :class:`datetime.datetime`, optional
            A timestamp signifying the end of the maneuver (the default is ``None``)

        Notes
        -----
        This methods updates the value of :attr:`position`.

        Any provided ``kwargs`` are forwarded to the :attr:`transition_model`.

        If :attr:`transition_model` or ``timestamp`` is ``None``, the method has
        no effect, but will return successfully.

        This method updates :attr:`transition_model`, :attr:`transition_index` and
        :attr:`current_interval`:
        If the timestamp provided gives a time delta greater than :attr:`current_interval` the
        :attr:`transition_model` is called for the rest of its corresponding duration, and the move
        method is called again on the next transition model (by incrementing
        :attr:`transition_index`) in :attr:`transition_models` with the residue time delta.
        If the time delta is less than :attr:`current_interval` the :attr:`transition_model` is
        called for that duration and :attr:`current_interval` is reduced accordingly.
        """
        if self.state.timestamp is None:
            self.state.timestamp = timestamp
            return
        try:
            time_interval = timestamp - self.state.timestamp
        except TypeError:
            # TypeError: (timestamp or prior.timestamp) is None
            return

        temp_state = self.state
        while time_interval != 0:
            if time_interval >= self.current_interval:
                temp_state = State(state_vector=self.transition_model.function(
                    state=temp_state,
                    noise=True,
                    time_interval=self.current_interval,
                    **kwargs),
                                   timestamp=timestamp)
                time_interval -= self.current_interval
                self.transition_index = (self.transition_index + 1) % len(
                    self.transition_models)
                self.current_interval = self.transition_times[
                    self.transition_index]

            else:
                temp_state = State(state_vector=self.transition_model.function(
                    state=temp_state,
                    noise=True,
                    time_interval=time_interval,
                    **kwargs),
                                   timestamp=timestamp)
                self.current_interval -= time_interval
                time_interval = 0
        self.states.append(temp_state)
示例#2
0
def test_multi_transition_movable_errors():
    # First check no error
    models = [ConstantVelocity(0), ConstantTurn(0, np.pi/2)]
    now = datetime.now()
    times = [timedelta(seconds=10), timedelta(seconds=10)]
    _ = MultiTransitionMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                               position_mapping=[0, 2, 4],
                               velocity_mapping=[1, 2, 5],
                               transition_models=models,
                               transition_times=times,
                               )

    with pytest.raises(AttributeError,
                       match='transition_models and transition_times must be same length'):
        _ = MultiTransitionMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                                   position_mapping=[0, 2, 4],
                                   velocity_mapping=[1, 2, 5],
                                   transition_models=[models[0]],
                                   transition_times=times,
                                   )

    with pytest.raises(AttributeError,
                       match='transition_models and transition_times must be same length'):
        _ = MultiTransitionMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                                   position_mapping=[0, 2, 4],
                                   velocity_mapping=[1, 2, 5],
                                   transition_models=models,
                                   transition_times=[now],
                                   )
def test_transitions_list(coords, turn_rate):

    x_coords = coords[0]
    y_coords = coords[1]

    x = x_coords[0]
    y = y_coords[0]
    vx = (x_coords[1] - x_coords[0]) / 10  # set sensible initial velocity
    vy = (y_coords[1] - y_coords[0]) / 10

    state_vector = StateVector([x, vx, y, vy])
    target = State(state_vector=state_vector, timestamp=start)

    transition_models, transition_times = create_smooth_transition_models(initial_state=target,
                                                                          x_coords=x_coords,
                                                                          y_coords=y_coords,
                                                                          times=times,
                                                                          turn_rate=turn_rate)

    for transition_model in transition_models:
        assert transition_model.ndim_state == 4

    for i in range(len(transition_models)):
        target.state_vector = transition_models[i].function(state=target,
                                                            time_interval=transition_times[i])
        target.timestamp += transition_times[i]
        if target.timestamp in times:
            index = times.index(target.timestamp)
            # expect target to be at next coordinates at each time-step
            assert np.isclose(target.state_vector[0], x_coords[index])
            assert np.isclose(target.state_vector[2], y_coords[index])
示例#4
0
def test_fixed_movable_velocity_mapping_error():
    # test no error for MovingMovable
    _ = MovingMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                      position_mapping=[0, 2, 4],
                      velocity_mapping=[1, 2, 5],
                      transition_model=None,
                      )
    with pytest.raises(ValueError, match='Velocity mapping should not be set for a FixedMovable'):
        _ = FixedMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                         position_mapping=[0, 2, 4],
                         velocity_mapping=[1, 2, 5],
                         )
示例#5
0
def test_multi_transition_movable_move():
    input_state_vector = StateVector([0, 1, 2.2, 78.6])
    pre_state = State(input_state_vector, timestamp=None)
    models = [CombinedLinearGaussianTransitionModel((ConstantVelocity(0), ConstantVelocity(0))),
              ConstantTurn([0, 0], turn_rate=np.pi / 2)]
    times = [timedelta(seconds=10), timedelta(seconds=10)]

    movable = MultiTransitionMovable(states=pre_state,
                                     position_mapping=[0, 2],
                                     velocity_mapping=[1, 3],
                                     transition_models=models,
                                     transition_times=times,
                                     )

    assert movable.state.state_vector is input_state_vector
    assert movable.state.timestamp is None

    now = datetime.now()
    movable.move(now)
    assert movable.state.state_vector is input_state_vector
    assert movable.state.timestamp is now

    movable.move(None)
    assert movable.state.state_vector is input_state_vector
    assert movable.state.timestamp is now

    movable.move(now + timedelta(seconds=10))
    assert movable.state.state_vector is not input_state_vector
    assert movable.state.timestamp is not now
示例#6
0
def test_empty_state_error():
    # first, check no error
    _ = MovingMovable(states=State(StateVector([0, 0, 0, 0, 0, 0])),
                      position_mapping=[0, 2, 4],
                      velocity_mapping=[1, 2, 5],
                      transition_model=None,
                      )
    with pytest.raises(ValueError, match='States must not be empty'):
        _ = MovingMovable(position_mapping=[0, 2, 4],
                          velocity_mapping=[1, 2, 5],
                          transition_model=None,
                          )
    with pytest.raises(ValueError, match='States must not be empty'):
        _ = MovingMovable(states=[],
                          position_mapping=[0, 2, 4],
                          velocity_mapping=[1, 2, 5],
                          transition_model=None,
                          )
示例#7
0
    def __init__(self, *args, **kwargs):
        position = kwargs.pop('position', None)
        orientation = kwargs.pop('orientation', None)
        self.__has_internal_controller = False

        super().__init__(*args, **kwargs)
        if position is not None or orientation is not None:
            if position is None:
                # assuming 3d for a default platform
                position = StateVector([0, 0, 0])
            if orientation is None:
                orientation = StateVector([0, 0, 0])
            controller = FixedMovable(states=State(state_vector=position),
                                      position_mapping=list(
                                          range(len(position))),
                                      orientation=orientation)
            self._property_movement_controller = controller
            self.__has_internal_controller = True
            self._set_mounting_rotation_defaults()
示例#8
0
    def move(self, timestamp=None, **kwargs) -> None:
        """Propagate the platform position using the :attr:`transition_model`.

        Parameters
        ----------
        timestamp: :class:`datetime.datetime`, optional
            A timestamp signifying when the end of the maneuver \
            (the default is ``None``)

        Notes
        -----
        This methods updates the value of :attr:`position`.

        Any provided ``kwargs`` are forwarded to the :attr:`transition_model`.

        If `timestamp`` is ``None``, the method has no effect, but will return successfully.

        """

        if self.state.timestamp is None:
            self.state.timestamp = timestamp
            return

        # Compute time_interval
        try:
            time_interval = timestamp - self.state.timestamp
        except TypeError:
            # TypeError: (timestamp or prior.timestamp) is None
            return

        if self.transition_model is None:
            raise AttributeError(
                'Platform without a transition model cannot be moved')

        self.states.append(
            State(state_vector=self.transition_model.function(
                state=self.state,
                noise=True,
                timestamp=timestamp,
                time_interval=time_interval,
                **kwargs),
                  timestamp=timestamp))
def test_coordinate_length():

    x_coords = np.zeros(3)
    y_coords = np.zeros(2)
    times = [start + timedelta(seconds=10*i) for i in range(3)]

    x = x_coords[0]
    y = y_coords[0]
    vx = (x_coords[1] - x_coords[0]) / 10  # set sensible initial velocity
    vy = (y_coords[1] - y_coords[0]) / 10

    turn_rate = 5

    state_vector = StateVector([x, vx, y, vy])
    target = State(state_vector=state_vector, timestamp=start)

    with pytest.raises(ValueError):
        #  x and y lists not equal in length (x longer)
        create_smooth_transition_models(initial_state=target,
                                        x_coords=x_coords,
                                        y_coords=y_coords,
                                        times=times,
                                        turn_rate=turn_rate)
    with pytest.raises(ValueError):
        #  x and y lists not equal in length (y longer)
        create_smooth_transition_models(initial_state=target,
                                        x_coords=y_coords,
                                        y_coords=x_coords,
                                        times=times,
                                        turn_rate=turn_rate)
    times = [start + timedelta(seconds=10*i) for i in range(4)]
    with pytest.raises(ValueError):
        #  times not equal to coordinates lists
        create_smooth_transition_models(initial_state=target,
                                        x_coords=x_coords,
                                        y_coords=x_coords,
                                        times=times,
                                        turn_rate=turn_rate)
示例#10
0
from matplotlib import pyplot as plt

start = datetime.now()

X = Y = np.array([0, -10, -20])
Y = np.array([0, 10, 0])
times = [start, start + timedelta(seconds=10), start + timedelta(seconds=30)]

# %%
# Plotting the three target destinations (in blue) and the target initial bearing in green:
from stonesoup.types.array import StateVector
from stonesoup.types.state import State

ux = 1  # initial x-speed
uy = 1  # initial y-speed
platform_state = State(StateVector((X[0], ux, Y[0], uy)), timestamp=start)

fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.axis('equal')
ax.scatter(X, Y, color='lightskyblue', s=100, edgecolors='black')
ax.plot((X[0], X[0] + 2 * ux), (Y[0], Y[0] + 2 * uy),
        color='lightgreen',
        linewidth=2)

# %%
# :meth:`~simulator.transition.get_smooth_transition_models` requires the initial state of the
# platform, x and y coordinates, times to be at each respective coordinate and the platform
# turn-rate.
from stonesoup.models.transition.linear import (
    CombinedLinearGaussianTransitionModel, ConstantVelocity)
from stonesoup.platform.base import MovingPlatform
from stonesoup.types.state import State

time_step = datetime.timedelta(seconds=0.1)
time_init = datetime.datetime.now()

transition_model = CombinedLinearGaussianTransitionModel(
    [ConstantVelocity(1.),
     ConstantVelocity(1.),
     ConstantVelocity(1.)])

red = MovingPlatform(position_mapping=[0, 2, 4],
                     velocity_mapping=[0, 2, 4],
                     states=State([50., 0., -50., 10., 0., 0.],
                                  timestamp=time_init),
                     transition_model=transition_model)
# %%
# Move target

for s in range(1, 100):
    red.move(time_init + s * time_step)

# %%
# Measure target states
# ^^^^^^^^^^^^^^^^^^^^^
# The states are measured with and without noise to show the real position with the measured one.

measurements = []
noiseless_measurements = []
for state in red.states:
示例#12
0
# .. math::
#           F_{k} = \begin{bmatrix}
#            1 & \triangle k & 0 & 0 & 0 & 0\\
#            0 & 1 & 0 & 0 & 0 & 0\\
#            0 & 0 & 1 & \triangle k & 0 & 0\\
#            0 & 0 & 0 & 1 & 0 & 0\\
#            0 & 0 & 0 & 0 & 1 & \triangle k \\
#            0 & 0 & 0 & 0 & 0 & 1\\
#              \end{bmatrix}

# First import the Moving platform
from stonesoup.platform.base import MovingPlatform

# Define the initial platform position, in this case the origin
initial_loc = StateVector([[0], [0], [0], [50], [8000], [0]])
initial_state = State(initial_loc, start_time)

# Define transition model and position for 3D platform
transition_model = CombinedLinearGaussianTransitionModel(
    [ConstantVelocity(0.), ConstantVelocity(0.), ConstantVelocity(0.)])

# create our fixed platform
sensor_platform = MovingPlatform(states=initial_state,
                                 position_mapping=(0, 2, 4),
                                 velocity_mapping=(1, 3, 5),
                                 transition_model=transition_model)

# %%
# With our platform generated we now need to build a set of sensors which will be mounted onto the platform. In this
# case we will exploit a :class:`~.RadarElevationBearingRangeRate` and a :class:`~.PassiveElevationBearing` sensor
# (e.g. an optical sensor, which has no capability to directly measure range).
#                          x\\ \dot{x}\\ y\\ \dot{y}\\ z\\ \dot{z} \end{bmatrix}
#                      = \begin{bmatrix}
#                          0\\ 0\\ 0\\ 0\\ 0\\ 0 \end{bmatrix}
#
# Because the platform is static we only need to define :math:`(x, y, z)`, any internal interaction with the platform
# which requires knowledge of platform velocity :math:`(\dot{x}, \dot{y}, \dot{z})` will be returned :math:`(0, 0, 0)`.

# First import the fixed platform
from stonesoup.platform.base import FixedPlatform

# Define the initial platform position, in this case the origin
platform_state_vector = StateVector([[0], [0], [0]])
position_mapping = (0, 1, 2)

# Create the initial state (position, time), notice it is set to the simulation start time defined earlier
platform_state = State(platform_state_vector, start_time)

# create our fixed platform
platform = FixedPlatform(states=platform_state,
                         position_mapping=position_mapping)

# %%
# We have now created a platform within Stone Soup and located it at the origin of our state space. As previously stated
# the platform will have a velocity :math:`(\dot{x}, \dot{y}, \dot{z})` of :math:`(0, 0, 0)` which we can check:
platform.velocity

# %%
# We can also query the platform orientation:
platform.orientation

# %%
示例#14
0
# Create specific transition model for example moving platform
transition_models = [transition_modelStraight, transition_modelLeft]
transition_times = [
    datetime.timedelta(seconds=160),
    datetime.timedelta(seconds=20)
]

# List sensors in stationary platforms (sensor orientations are overwritten)
stationarySensors = [
    RadarRotatingBearingRange(
        ndim_state=6,
        position_mapping=(0, 2),
        noise_covar=np.diag([np.radians(1)**2,
                             7**2]),  # The sensor noise covariance matrix
        dwell_center=State(StateVector([[-np.pi]])),
        rpm=12.5,
        max_range=100000,
        fov_angle=np.radians(360)),
    RadarRotatingBearingRange(ndim_state=6,
                              position_mapping=(0, 2),
                              noise_covar=np.diag([np.radians(1)**2, 7**2]),
                              dwell_center=State(StateVector([[-np.pi]])),
                              rpm=12.5,
                              max_range=100000,
                              fov_angle=np.radians(360)),
]

# List sensors in moving platform (sensor orientations are overwritten)
movingPlatformSensors = [
    RadarRotatingBearingRange(ndim_state=6,
示例#15
0
def test_alphabeta(measurement_model, prediction, measurement, alpha, beta):

    # Time delta
    timediff = timedelta(seconds=2)

    # Calculate evaluation variables - converts
    # to measurement from prediction space
    eval_measurement_prediction = StateMeasurementPrediction(
        measurement_model.matrix() @ prediction.state_vector)

    eval_posterior_position = prediction.state_vector[[0, 2]] + \
        alpha * (measurement.state_vector - eval_measurement_prediction.state_vector)
    eval_posterior_velocity = prediction.state_vector[[1, 3]] + \
        beta/timediff.total_seconds() * (measurement.state_vector -
                                         eval_measurement_prediction.state_vector)

    eval_state_vect = np.concatenate(
        (eval_posterior_position, eval_posterior_velocity))
    eval_posterior = State(eval_state_vect[[0, 2, 1, 3]])

    # Initialise an Alpha-Beta updater
    updater = AlphaBetaUpdater(measurement_model=measurement_model,
                               alpha=alpha,
                               beta=beta)

    # Get and assert measurement prediction
    measurement_prediction = updater.predict_measurement(prediction)

    assert (np.allclose(measurement_prediction.state_vector,
                        eval_measurement_prediction.state_vector,
                        0,
                        atol=1.e-14))

    # Perform and assert state update (without measurement prediction)
    posterior = updater.update(SingleHypothesis(prediction=prediction,
                                                measurement=measurement),
                               time_interval=timediff)

    assert (np.allclose(posterior.state_vector,
                        eval_posterior.state_vector,
                        0,
                        atol=1.e-14))
    assert (np.array_equal(posterior.hypothesis.prediction, prediction))
    assert (np.array_equal(posterior.hypothesis.measurement, measurement))
    assert (posterior.timestamp == prediction.timestamp)

    # Check that the vmap parameter can be set
    # Check a measurement prediction can be added
    updater.vmap = np.array([1, 3])
    posterior = updater.update(SingleHypothesis(
        prediction=prediction,
        measurement=measurement,
        measurement_prediction=measurement_prediction),
                               time_interval=timediff)
    assert (np.allclose(posterior.state_vector,
                        eval_posterior.state_vector,
                        0,
                        atol=1.e-14))

    # Finally check that no model in the updater raises correct error
    updater.measurement_model = None
    with pytest.raises(ValueError):
        updater._check_measurement_model(None)
示例#16
0
# ------------------------------------
# The sensor converts the Cartesian coordinates into range, bearing and elevation.
# The sensor is then mounted onto a platform (stationary in this case)

from stonesoup.platform.base import FixedPlatform
from stonesoup.sensor.radar.radar import RadarElevationBearingRange
from stonesoup.simulator.platform import PlatformDetectionSimulator
from stonesoup.types.state import State

sensor = RadarElevationBearingRange(
    [0, 2, 4],
    meas_covar,
    6,
)
platform = FixedPlatform(
    State([0, 0, 0, 0, 0, 0]),  # Sensor at reference point, zero velocity
    [0, 2, 4],
    sensors=[sensor])

# Create the detector and initialize it.
detector = PlatformDetectionSimulator(ground_truth_reader, [platform])

# %%
# Setup Initiator class for the Tracker
# ---------------------------------------
# This is just an heuristic initiation:
# Assume most of the deviation is caused by the Bearing measurement error.
# This is then converted into x, y components using the target bearing. For the
# deviation in z,
# we simply use :math:`R\times\sigma_{elev}` (ignore any bearing and range
# deviation components). Velocity covariances are simply based on the expected