Skip to content

Commit 10e35d3

Browse files
committed
fix: merge imports
2 parents 79b2994 + 92dae99 commit 10e35d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+17949
-40445
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
command: |
3939
. venv/bin/activate
4040
mkdir test-reports
41-
pytest --junitxml=test-reports/junit.xml --cov --cov-report=xml:test-reports/coverage.xml stonesoup
41+
pytest --junitxml=test-reports/junit.xml --cov --cov-report=xml:test-reports/coverage.xml --slow stonesoup
4242
- store_test_results:
4343
path: test-reports/junit.xml
4444
- store_artifacts:

docs/demos/OpenSky_Demo.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
# %%
2121
# Reading the CSV File
2222
# ---------------------
23-
# To read in our groundtruth data from a CSV file, we can use Stone Soup’s
23+
# To read in our groundtruth data from a
24+
# :download:`CSV file <../../demos/OpenSky_Plane_States.csv>`, we can use Stone Soup’s
2425
# :class:`~.CSVGroundTruthReader`. To convert our longitude and latitude data to Universal
2526
# Transverse Mercator (UTM) projection, we will use :class:`~.LongLatToUTMConverter`.
2627

@@ -329,7 +330,7 @@
329330
'properties':{
330331
'icon': 'marker',
331332
'iconstyle':{
332-
'iconUrl': '../_static/sphinx_gallery/Radar_dish.png',
333+
'iconUrl': 'https://stonesoup.rtfd.io/en/latest/_static/sphinx_gallery/Radar_dish.png',
333334
'iconSize': [24, 24],
334335
'fillOpacity': 1,
335336
'popupAnchor': [1, -17]},
@@ -492,7 +493,7 @@
492493
'properties':{
493494
'icon': 'marker',
494495
'iconstyle':{
495-
'iconUrl': f'../_static/sphinx_gallery/Plane_Headings/Plane_{angle}.png',
496+
'iconUrl': f'https://stonesoup.rtfd.io/en/latest/_static/sphinx_gallery/Plane_Headings/Plane_{angle}.png',
496497
'iconSize': [24, 24],
497498
'fillOpacity': 1,
498499
'popupAnchor': [1, -17],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#!/usr/bin/env python
2+
# coding: utf-8
3+
4+
"""
5+
========================================================
6+
General Multi Hypotheses tracking implementation example
7+
========================================================
8+
"""
9+
10+
# %%
11+
# The multi hypotheses tracking (MHT) algorithm is considered one of the best tracking algorithms,
12+
# consisting of creating a tree of potential tracks for
13+
# each target candidate (in a multi-target scenario) and pruning such hypotheses
14+
# in the data association phase. It is particularly efficient in maintaining trajectories of
15+
# multiple objects and handling uncertainties and ambiguities of tracks (e.g. presence of
16+
# clutter).
17+
#
18+
# MHT, by definition, has several algorithms that fall under this definition, which
19+
# include Global Nearest Neighbour (GNN,
20+
# :doc:`tutorial <../../auto_tutorials/06_DataAssociation-MultiTargetTutorial>`),
21+
# Joint Probabilistic Data association (JPDA,
22+
# :doc:`tutorial <../../auto_tutorials/08_JPDATutorial>`),
23+
# Multi-frame assignment (MFA [#]_, :doc:`example <MFA_example>`),
24+
# Multi Bernoulli filter and Probabilistic multi hypotheses tracking (PMHT).
25+
# Some of these algorithms are already implemented the Stone Soup.
26+
#
27+
# In this example we employ the multi-frame assignment data associator and
28+
# hypothesiser using their Stone Soup implementation.
29+
#
30+
# This example follows this structure:
31+
#
32+
# 1. Create ground truth and detections;
33+
# 2. Instantiate the tracking components and tracker;
34+
# 3. Run the tracker and visualise the results.
35+
#
36+
37+
# %%
38+
# General imports
39+
# ^^^^^^^^^^^^^^^
40+
import numpy as np
41+
from datetime import datetime, timedelta
42+
from itertools import tee
43+
44+
# %%
45+
# Stone Soup imports
46+
# ^^^^^^^^^^^^^^^^^^
47+
from stonesoup.types.array import StateVector, CovarianceMatrix
48+
from stonesoup.types.state import GaussianState
49+
from stonesoup.models.transition.linear import CombinedLinearGaussianTransitionModel, \
50+
ConstantVelocity
51+
from stonesoup.models.measurement.nonlinear import CartesianToBearingRange
52+
from stonesoup.simulator.simple import MultiTargetGroundTruthSimulator, SimpleDetectionSimulator
53+
54+
# Simulation parameters
55+
np.random.seed(1908) # fix a random seed
56+
start_time = datetime.now().replace(microsecond=0)
57+
simulation_steps = 50
58+
timestep_size = timedelta(seconds=2)
59+
prob_detection = 0.99
60+
initial_state_mean = StateVector([[10], [0], [10], [0]])
61+
initial_covariance = CovarianceMatrix(np.diag([30, 1, 40, 1]))
62+
63+
# clutter will be generated uniformly in this area around the targets
64+
clutter_area = np.array([[-1, 1], [-1, 1]])*150
65+
clutter_rate = 9
66+
surveillance_area = ((clutter_area[0, 1] - clutter_area[0, 0]) *
67+
(clutter_area[1, 1] - clutter_area[1, 0]))
68+
clutter_spatial_density = clutter_rate/surveillance_area
69+
70+
# %%
71+
# 1. Create ground truth and detections;
72+
# --------------------------------------
73+
# We have prepared all the general parameters for the simulation,
74+
# including the clutter spatial density. In this example we set
75+
# the birth rate and the death probability as zero, using only the knowledge of the
76+
# prior states to generate the tracks so the number of targets is fixed (3 in this case).
77+
#
78+
# We can instantiate the transition model of the targets and the measurement model.
79+
# In this example we employ a :class:`~.CartesianToBearingRange` non-linear measurement model.
80+
# Then, we pass all these details to a :class:`~.MultiTargetGroundTruthSimulator`
81+
# and use a :class:`~.SimpleDetectionSimulator`
82+
# to obtain the target ground truth, detections and clutter.
83+
#
84+
85+
# Create an initial state
86+
initial_state = GaussianState(state_vector=initial_state_mean,
87+
covar=initial_covariance,
88+
timestamp=start_time)
89+
90+
# Instantiate the transition model
91+
transition_model = CombinedLinearGaussianTransitionModel([ConstantVelocity(0.005),
92+
ConstantVelocity(0.005)])
93+
94+
# Define the measurement model
95+
measurement_model = CartesianToBearingRange(ndim_state=4,
96+
mapping=(0, 2),
97+
noise_covar=np.diag([np.radians(1), 5]))
98+
99+
# Instantiate the multi-target simulator
100+
ground_truth_simulator = MultiTargetGroundTruthSimulator(
101+
transition_model=transition_model,
102+
initial_state=initial_state,
103+
timestep=timestep_size,
104+
number_steps=simulation_steps,
105+
birth_rate=0, # no other targets more than the specified ones
106+
death_probability=0, # all targets will remain during the simulation
107+
preexisting_states=[[10, 1, 10, 1], [-10, -1, -10, -1], [-10, -1, 10, 1]])
108+
109+
# Create a detector
110+
detection_sim = SimpleDetectionSimulator(
111+
groundtruth=ground_truth_simulator,
112+
measurement_model=measurement_model,
113+
detection_probability=prob_detection,
114+
meas_range=clutter_area,
115+
clutter_rate=clutter_rate)
116+
117+
# Instantiate a set for detections/clutter and ground truths
118+
detections = set()
119+
ground_truth = set()
120+
timestamps = []
121+
122+
# Duplicate the detection simulator
123+
plot, tracking = tee(detection_sim, 2)
124+
125+
# Iterate in the detection simulator to generate the measurements
126+
for time, dets in plot:
127+
detections |= dets
128+
ground_truth |= ground_truth_simulator.groundtruth_paths
129+
timestamps.append(time)
130+
131+
# Visualise the detections and tracks
132+
from stonesoup.plotter import AnimatedPlotterly
133+
134+
plotter = AnimatedPlotterly(timestamps)
135+
plotter.plot_ground_truths(ground_truth, [0, 2])
136+
plotter.plot_measurements(detections, [0, 2])
137+
plotter.fig
138+
139+
# %%
140+
# 2. Instantiate the tracking components and tracker;
141+
# ---------------------------------------------------
142+
# We need to prepare the tracker and its components. In this example we consider an
143+
# Unscented Kalman filter since we are dealing with non-linear measurements.
144+
# We consider a :class:`~.UnscentedKalmanPredictor` and :class:`~.UnscentedKalmanUpdater`.
145+
#
146+
# As said previously, we consider a multi-frame assignment data associator
147+
# which wraps a :class:`~.PDAHypothesiser` probability hypothesiser into a
148+
# :class:`~.MFAHypothesiser` to work with the :class:`~.MFADataAssociator`.
149+
#
150+
# To instantiate the tracks we could use :class:`~.GaussianMixtureInitiator` which
151+
# uses a Gaussian Initiator (such as :class:`~.MultiMeasurementInitiator`) to
152+
# create GaussianMixture prior states, however, its current implementation
153+
# is intended for a GM-PHD filter making it troublesome to adapt for our needs.
154+
# Therefore, we consider :class:`~.TaggedWeightedGaussianState` to create the track priors,
155+
# which can be handled by MFA components, using the pre-existing states fed to the
156+
# multi-groundtruth simulator.
157+
# Such prior states are, then, wrapped in :class:`~.GaussianMixture` states.
158+
#
159+
# As it is now, there is not a tracker wrapper (as for the
160+
# :class:`~.MultiTargetMixtureTracker`) that can be applied directly when dealing with MFA,
161+
# so we need to specify the tracking loop explicitly.
162+
163+
# load tracker the components
164+
from stonesoup.predictor.kalman import UnscentedKalmanPredictor
165+
from stonesoup.updater.kalman import UnscentedKalmanUpdater
166+
167+
predictor = UnscentedKalmanPredictor(transition_model)
168+
updater = UnscentedKalmanUpdater(measurement_model)
169+
170+
# Data associator and hypothesiser
171+
from stonesoup.dataassociator.mfa import MFADataAssociator
172+
from stonesoup.hypothesiser.mfa import MFAHypothesiser
173+
from stonesoup.hypothesiser.probability import PDAHypothesiser
174+
175+
hypothesiser = PDAHypothesiser(predictor,
176+
updater,
177+
clutter_spatial_density,
178+
prob_gate=0.9999,
179+
prob_detect=prob_detection)
180+
181+
hypothesiser = MFAHypothesiser(hypothesiser)
182+
data_associator = MFADataAssociator(hypothesiser,
183+
slide_window=3)
184+
185+
# Prepare the priors
186+
from stonesoup.types.state import TaggedWeightedGaussianState
187+
from stonesoup.types.track import Track
188+
from stonesoup.types.mixture import GaussianMixture
189+
from stonesoup.types.numeric import Probability
190+
from stonesoup.types.update import GaussianMixtureUpdate
191+
192+
prior1 = GaussianMixture([TaggedWeightedGaussianState(
193+
StateVector([10, 1, 10, 1]),
194+
np.diag([10, 1, 10, 1]),
195+
timestamp=initial_state.timestamp,
196+
weight=Probability(1),
197+
tag=[])])
198+
199+
prior2 = GaussianMixture([TaggedWeightedGaussianState(
200+
StateVector([-10, -1, -10, -1]),
201+
np.diag([10, 1, 10, 1]),
202+
timestamp=initial_state.timestamp,
203+
weight=Probability(1),
204+
tag=[])])
205+
206+
prior3 = GaussianMixture([TaggedWeightedGaussianState(
207+
StateVector([-10, -1, 10, 1]),
208+
np.diag([10, 1, 10, 1]),
209+
timestamp=initial_state.timestamp,
210+
weight=Probability(1),
211+
tag=[])])
212+
213+
# instantiate the tracks
214+
tracks = {Track([prior1]),
215+
Track([prior2]),
216+
Track([prior3])}
217+
218+
# %%
219+
# 3. Run the tracker and visualise the results;
220+
# ---------------------------------------------
221+
# We are ready to loop over the detections in the
222+
# simulation and obtain the final tracks.
223+
224+
225+
for time, detection in tracking:
226+
association = data_associator.associate(tracks, detection, time)
227+
228+
for track, hypotheses in association.items():
229+
components = []
230+
for hypothesis in hypotheses:
231+
if not hypothesis:
232+
components.append(hypothesis.prediction)
233+
else:
234+
update = updater.update(hypothesis)
235+
components.append(update)
236+
track.append(GaussianMixtureUpdate(components=components,
237+
hypothesis=hypotheses))
238+
239+
tracks.add(track)
240+
241+
plotter.plot_tracks(tracks, [0, 2], track_label="Tracks", line=dict(color="Green"))
242+
plotter.fig
243+
244+
# %%
245+
# Conclusion
246+
# ----------
247+
# In this example we have presented how to set up a multi-hypotheses tracking
248+
# (MHT) simulation, by employing the existing components present in Stone Soup
249+
# and perform the tracking in a heavy cluttered multi-target scenario.
250+
251+
# %%
252+
# References
253+
# ----------
254+
# .. [#] Xia, Y., Granström, K., Svensson, L., García-Fernández, Á.F., and Williams, J.L.,
255+
# 2019. Multiscan Implementation of the Trajectory Poisson Multi-Bernoulli Mixture Filter.
256+
# J. Adv. Information Fusion, 14(2), pp. 213–235.

docs/examples/eot/README.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Extended Object Tracking
2+
------------------------

0 commit comments

Comments
 (0)