dstl / Stone-Soup

A software project to provide the target tracking community with a framework for the development and testing of tracking algorithms.
https://stonesoup.rtfd.io
MIT License
414 stars 140 forks source link

Strange error in converting to PDA in tutorial 10 #577

Closed adielstatman closed 2 years ago

adielstatman commented 2 years ago

Hi. Besides putting MultiTargetMixtureTracker instead of MultiTargetTracker I coded:

from stonesoup.hypothesiser.probability import PDAHypothesiser from stonesoup.dataassociator.probability import JPDA hypothesiser =PDAHypothesiser(predictor, updater, clutter_spatial_density=0.5) data_associator = JPDA(hypothesiser)

instead of:

from stonesoup.hypothesiser.distance import DistanceHypothesiser from stonesoup.dataassociator.neighbour import GNNWith2DAssignment from stonesoup.measures import Mahalanobis hypothesiser = DistanceHypothesiser(predictor, updater, measure=Mahalanobis(), missed_distance=3) data_associator = GNNWith2DAssignment(hypothesiser)

than I get the following error:

File "/home/adiel/anaconda3/lib/python3.8/site-packages/stonesoup/updater/kalman.py", line 227, in update
  predicted_state = hypothesis.prediction

AttributeError: 'MultipleHypothesis' object has no attribute 'prediction'

What is wrong? what else should be modified? Thanks!

oharrald-Dstl commented 2 years ago

It looks like MultipleHypothesis are being passed directly to the updater's update method, rather than the individual hypotheses of each MultipleHypothesis. This suggests to me that a MultiTargetTracker is still being used instead of the MultiTargetMixtureTracker. Does your tracker get redefined to a MultiTargetTracker at some point?

adielstatman commented 2 years ago

It seems not.. This is my complete code which outputs the above error (very few is changed relative the original tutorial 10. Only the definitions hypothesiser, tracker and the dataassociator):

import numpy as np import datetime

from stonesoup.types.array import StateVector, CovarianceMatrix from stonesoup.types.state import GaussianState initial_state_mean = StateVector([[0], [0], [0], [0]]) initial_state_covariance = CovarianceMatrix(np.diag([4, 0.5, 4, 0.5])) timestep_size = datetime.timedelta(seconds=5) number_of_steps = 20 birth_rate = 0.3 death_probability = 0.05 initial_state = GaussianState(initial_state_mean, initial_state_covariance)

from stonesoup.models.transition.linear import ( CombinedLinearGaussianTransitionModel, ConstantVelocity) transition_model = CombinedLinearGaussianTransitionModel( [ConstantVelocity(0.05), ConstantVelocity(0.05)])

from stonesoup.simulator.simple import MultiTargetGroundTruthSimulator groundtruth_sim = MultiTargetGroundTruthSimulator( transition_model=transition_model, initial_state=initial_state, timestep=timestep_size, number_steps=number_of_steps, birth_rate=birth_rate, death_probability=death_probability )

from stonesoup.simulator.simple import SimpleDetectionSimulator from stonesoup.models.measurement.linear import LinearGaussian

measurement_model_covariance = np.diag([0.25, 0.25]) measurement_model = LinearGaussian(4, [0, 2], measurement_model_covariance)

probability_detection = 0.9

clutter_area = np.array([[-1, 1], [-1, 1]])*30 clutter_rate = 1

detection_sim = SimpleDetectionSimulator( groundtruth=groundtruth_sim, measurement_model=measurement_model, detection_probability=probability_detection, meas_range=clutter_area, clutter_rate=clutter_rate )

from stonesoup.predictor.kalman import KalmanPredictor predictor = KalmanPredictor(transition_model)

from stonesoup.updater.kalman import KalmanUpdater updater = KalmanUpdater(measurement_model)

from stonesoup.hypothesiser.probability import PDAHypothesiser from stonesoup.dataassociator.probability import JPDA

from stonesoup.measures import Mahalanobis

hypothesiser =PDAHypothesiser(predictor, updater, clutter_spatial_density=0.5) data_associator = JPDA(hypothesiser)

from stonesoup.deleter.error import CovarianceBasedDeleter covariance_limit_for_delete = 2 deleter = CovarianceBasedDeleter(covar_trace_thresh=covariance_limit_for_delete)

s_prior_state = GaussianState([[0], [0], [0], [0]], np.diag([0, 0.5, 0, 0.5])) min_detections = 3

from stonesoup.initiator.simple import MultiMeasurementInitiator initiator = MultiMeasurementInitiator( prior_state=s_prior_state, measurement_model=measurement_model, deleter=deleter, data_associator=data_associator, updater=updater, min_points=min_detections )

from stonesoup.tracker.simple import MultiTargetMixtureTracker as MTT

tracker = MTT( initiator=initiator, deleter=deleter, detector=detection_sim, data_associator=data_associator, updater=updater, )

groundtruth = set() detections = set() tracks = set() from stonesoup.metricgenerator.plotter import TwoDPlotter for time, ctracks in tracker: groundtruth.update(groundtruth_sim.groundtruth_paths) detections.update(detection_sim.detections) tracks.update(ctracks) plotter = TwoDPlotter(track_indices=[0, 2], gtruth_indices=[0, 2], detection_indices=[0, 2]) fig = plotter.plot_tracks_truth_detections(tracks, groundtruth, detections).value ax = fig.axes[0] ax.setxlim([-30, 30]) = ax.set_ylim([-30, 30])

sdhiscocks commented 2 years ago

from stonesoup.initiator.simple import MultiMeasurementInitiator initiator = MultiMeasurementInitiator( prior_state=s_prior_state, measurement_model=measurement_model, deleter=deleter, data_associator=data_associator, updater=updater, min_points=min_detections )

Issue is here. The multi model initiator doesn't work with mixture. Below should hopefully work (replacing data associator with hard assignment one):

from stonesoup.initiator.simple import MultiMeasurementInitiator
from stonesoup.dataassociator.neighbour import NearestNeighbour
initiator = MultiMeasurementInitiator(
prior_state=s_prior_state,
measurement_model=measurement_model,
deleter=deleter,
data_associator=NearestNeighbour(hypothesiser),
updater=updater,
min_points=min_detections
)
adielstatman commented 2 years ago

Hi. Now it is run, but no tracking is appeared. Exist only the ground truths and the measurements. Adiel.

sdhiscocks commented 2 years ago
clutter_area = np.array([[-1, 1], [-1, 1]])*30
clutter_rate = 1
hypothesiser =PDAHypothesiser(predictor, updater, clutter_spatial_density=0.5)

Looks like the clutter_spatial_density is too high. The clutter your generating is 1/(60*60) so a rate of 2e-4 would be about right.

Way I think of it, is if the clutter spatial density is higher than actual clutter present, then higher chance that measurements seen are clutter, and such missed detection more probable. The uncertainty is probably therefore increasing more and deleter is removing the track too soon.

adielstatman commented 2 years ago

It does not work for me. Putting

clutter_rate = 1

and

clutter_spatial_density=2e-4 (or any value less than 0.04)

yields:

File "/home/adiel/anaconda3/lib/python3.8/site-packages/stonesoup/tracker/simple.py", line 162, in tracks_gen for hypothesis in multihypothesis:

TypeError: 'SingleProbabilityHypothesis' object is not iterable

putting clutter_spatial_density=0.05 still does not gives tracks. If there is a chance you can try to run my code, I will be grateful!

sdhiscocks commented 2 years ago

Did you also include the multi model initiator change in my previous comment?

I've tested here, and it is working.

adielstatman commented 2 years ago

Yes. I guess it should be changed also in the tracker. However, it gives the same (no tracks) also when putting JPDA (from stonesoup.dataassociator.probability import JPDA) in the tracker. This is my complete code:

import numpy as np import datetime

from stonesoup.types.array import StateVector, CovarianceMatrix from stonesoup.types.state import GaussianState initial_state_mean = StateVector([[0], [0], [0], [0]]) initial_state_covariance = CovarianceMatrix(np.diag([4, 0.5, 4, 0.5])) timestep_size = datetime.timedelta(seconds=5) number_of_steps = 20 birth_rate = 0.3 death_probability = 0.05 initial_state = GaussianState(initial_state_mean, initial_state_covariance)

from stonesoup.models.transition.linear import ( CombinedLinearGaussianTransitionModel, ConstantVelocity) transition_model = CombinedLinearGaussianTransitionModel( [ConstantVelocity(0.05), ConstantVelocity(0.05)])

from stonesoup.simulator.simple import MultiTargetGroundTruthSimulator groundtruth_sim = MultiTargetGroundTruthSimulator( transition_model=transition_model, initial_state=initial_state, timestep=timestep_size, number_steps=number_of_steps, birth_rate=birth_rate, death_probability=death_probability )

from stonesoup.simulator.simple import SimpleDetectionSimulator from stonesoup.models.measurement.linear import LinearGaussian

measurement_model_covariance = np.diag([0.25, 0.25]) measurement_model = LinearGaussian(4, [0, 2], measurement_model_covariance)

probability_detection = 0.9

clutter_area = np.array([[-1, 1], [-1, 1]])*30 clutter_rate = 1

detection_sim = SimpleDetectionSimulator( groundtruth=groundtruth_sim, measurement_model=measurement_model, detection_probability=probability_detection, meas_range=clutter_area, clutter_rate=clutter_rate )

from stonesoup.predictor.kalman import KalmanPredictor predictor = KalmanPredictor(transition_model)

from stonesoup.updater.kalman import KalmanUpdater updater = KalmanUpdater(measurement_model)

from stonesoup.hypothesiser.probability import PDAHypothesiser

from stonesoup.dataassociator.probability import JPDA

from stonesoup.measures import Mahalanobis

from stonesoup.dataassociator.neighbour import NearestNeighbour

hypothesiser =PDAHypothesiser(predictor, updater, clutter_spatial_density=0.05)

from stonesoup.deleter.error import CovarianceBasedDeleter covariance_limit_for_delete = 2 deleter = CovarianceBasedDeleter(covar_trace_thresh=covariance_limit_for_delete)

s_prior_state = GaussianState([[0], [0], [0], [0]], np.diag([0, 0.5, 0, 0.5])) min_detections = 3

from stonesoup.initiator.simple import MultiMeasurementInitiator

initiator = MultiMeasurementInitiator( prior_state=s_prior_state, measurement_model=measurement_model, deleter=deleter, data_associator=NearestNeighbour(hypothesiser), updater=updater, min_points=min_detections )

from stonesoup.tracker.simple import MultiTargetMixtureTracker as MTT

tracker = MTT( initiator=initiator, deleter=deleter, detector=detection_sim, data_associator=NearestNeighbour(hypothesiser), updater=updater, )

groundtruth = set() detections = set() tracks = set() from stonesoup.metricgenerator.plotter import TwoDPlotter for time, ctracks in tracker: groundtruth.update(groundtruth_sim.groundtruth_paths) detections.update(detection_sim.detections) tracks.update(ctracks) plotter = TwoDPlotter(track_indices=[0, 2], gtruth_indices=[0, 2], detection_indices=[0, 2]) fig = plotter.plot_tracks_truth_detections(tracks, groundtruth, detections).value ax = fig.axes[0] ax.setxlim([-30, 30]) = ax.set_ylim([-30, 30])

sdhiscocks commented 2 years ago

From your code, I changed the clutter_spatial_density and used JPDA in MTT. Here's gist testing it.

adielstatman commented 2 years ago

Great. It works. Thank you!