Add skeleton for tracker, commented out, do not use

This commit is contained in:
30hours 2023-12-26 15:29:51 +00:00
parent 99f09eb5f8
commit 97b34ff3d8
11 changed files with 649 additions and 17 deletions

View file

@ -27,11 +27,13 @@ add_executable(blah2
${PROJECT_SOURCE_DIR}/process/detection/CfarDetector1D.cpp
${PROJECT_SOURCE_DIR}/process/detection/Centroid.cpp
${PROJECT_SOURCE_DIR}/process/detection/Interpolate.cpp
${PROJECT_SOURCE_DIR}/process/tracker/Tracker.cpp
${PROJECT_SOURCE_DIR}/process/spectrum/SpectrumAnalyser.cpp
${PROJECT_SOURCE_DIR}/process/meta/HammingNumber.cpp
${PROJECT_SOURCE_DIR}/data/IqData.cpp
${PROJECT_SOURCE_DIR}/data/Map.cpp
${PROJECT_SOURCE_DIR}/data/Detection.cpp
${PROJECT_SOURCE_DIR}/data/Track.cpp
${PROJECT_SOURCE_DIR}/data/meta/Timing.cpp
)
@ -74,6 +76,7 @@ include_directories("${PROJECT_SOURCE_DIR}/capture/rspduo/")
include_directories("${PROJECT_SOURCE_DIR}/process/ambiguity/")
include_directories("${PROJECT_SOURCE_DIR}/process/clutter/")
include_directories("${PROJECT_SOURCE_DIR}/process/detection/")
include_directories("${PROJECT_SOURCE_DIR}/process/tracker/")
include_directories("${PROJECT_SOURCE_DIR}/process/spectrum/")
include_directories("${PROJECT_SOURCE_DIR}/process/meta/")
include_directories("${PROJECT_SOURCE_DIR}/data/")

View file

@ -12,6 +12,7 @@ const PORT = 3000;
const HOST = '0.0.0.0';
var map = '';
var detection = '';
var track = '';
var timestamp = '';
var timing = '';
var iqdata = '';
@ -37,6 +38,9 @@ app.get('/api/map', (req, res) => {
app.get('/api/detection', (req, res) => {
res.send(detection);
});
app.get('/api/tracker', (req, res) => {
res.send(track);
});
app.get('/api/timestamp', (req, res) => {
res.send(timestamp);
});
@ -108,6 +112,23 @@ const server_detection = net.createServer((socket)=>{
});
server_detection.listen(3002);
// tcp listener tracker
const server_tracker = net.createServer((socket)=>{
socket.write("Hello From Server!")
socket.on("data",(msg)=>{
data = data + msg.toString();
if (data.slice(-1) === "}")
{
track = data;
data = '';
}
});
socket.on("close",()=>{
console.log("Connection closed.");
})
});
server_tracker.listen(3003);
// tcp listener timestamp
const server_timestamp = net.createServer((socket)=>{
socket.write("Hello From Server!")

View file

@ -27,6 +27,13 @@ process:
minDelay: 5
minDoppler: 15
nCentroid: 10
tracker:
initiate:
M: 3
N: 5
maxAcc: 10
delete: 10
smooth: "none"
network:
ip: 0.0.0.0
@ -34,13 +41,24 @@ network:
api: 3000
map: 3001
detection: 3002
track: 3003
timestamp: 4000
timing: 4001
iqdata: 4002
truth:
asdb:
enabled: false
ip: 0.0.0.0
port: 30000
ais:
enabled: false
ip: 0.0.0.0
port: 30001
save:
iq: true
map: false
detection: false
timing: false
path: "/blah2/save/"
path: "/blah2/save/"

View file

@ -14,12 +14,12 @@ process:
overlap: 0
ambiguity:
delayMin: -10
delayMax: 300
dopplerMin: -250
dopplerMax: 250
delayMax: 400
dopplerMin: -200
dopplerMax: 200
clutter:
delayMin: -10
delayMax: 300
delayMax: 400
detection:
pfa: 0.00001
nGuard: 2
@ -27,6 +27,13 @@ process:
minDelay: 5
minDoppler: 15
nCentroid: 6
tracker:
initiate:
M: 3
N: 5
maxAcc: 10
delete: 10
smooth: "none"
network:
ip: 0.0.0.0
@ -34,13 +41,24 @@ network:
api: 3000
map: 3001
detection: 3002
track: 3003
timestamp: 4000
timing: 4001
iqdata: 4002
truth:
asdb:
enabled: false
ip: 0.0.0.0
port: 30000
ais:
enabled: false
ip: 0.0.0.0
port: 30001
save:
iq: true
map: false
detection: false
timing: false
path: "/blah2/save/"
path: "/blah2/save/"

View file

@ -10,9 +10,11 @@
#include <Ambiguity.h>
#include <WienerHopf.h>
#include <CfarDetector1D.h>
#include <Tracker.h>
#include <IqData.h>
#include <Map.h>
#include <Detection.h>
#include <Track.h>
#include <Centroid.h>
#include <Interpolate.h>
#include <Timing.h>
@ -89,11 +91,10 @@ int main(int argc, char **argv)
IqData *x = new IqData(nSamples);
IqData *y = new IqData(nSamples);
Map<std::complex<double>> *map;
Map<double> *mapdb;
std::string mapJson, detectionJson;
Detection *detection;
Detection *detection1;
Detection *detection2;
Track *track;
// setup fftw multithread
if (fftw_init_threads() == 0)
@ -104,10 +105,12 @@ int main(int argc, char **argv)
fftw_plan_with_nthreads(4);
// setup socket
uint16_t port_map, port_detection, port_timestamp, port_timing, port_iqdata;
uint16_t port_map, port_detection, port_timestamp,
port_timing, port_iqdata, port_track;
std::string ip;
tree["network"]["ports"]["map"] >> port_map;
tree["network"]["ports"]["detection"] >> port_detection;
tree["network"]["ports"]["track"] >> port_track;
tree["network"]["ports"]["timestamp"] >> port_timestamp;
tree["network"]["ports"]["timing"] >> port_timing;
tree["network"]["ports"]["iqdata"] >> port_iqdata;
@ -115,11 +118,13 @@ int main(int argc, char **argv)
asio::io_service io_service;
asio::ip::tcp::socket socket_map(io_service);
asio::ip::tcp::socket socket_detection(io_service);
asio::ip::tcp::socket socket_track(io_service);
asio::ip::tcp::socket socket_timestamp(io_service);
asio::ip::tcp::socket socket_timing(io_service);
asio::ip::tcp::socket socket_iqdata(io_service);
asio::ip::tcp::endpoint endpoint_map;
asio::ip::tcp::endpoint endpoint_detection;
asio::ip::tcp::endpoint endpoint_track;
asio::ip::tcp::endpoint endpoint_timestamp;
asio::ip::tcp::endpoint endpoint_timing;
asio::ip::tcp::endpoint endpoint_iqdata;
@ -127,6 +132,8 @@ int main(int argc, char **argv)
asio::ip::address::from_string(ip), port_map);
endpoint_detection = asio::ip::tcp::endpoint(
asio::ip::address::from_string(ip), port_detection);
endpoint_track = asio::ip::tcp::endpoint(
asio::ip::address::from_string(ip), port_track);
endpoint_timestamp = asio::ip::tcp::endpoint(
asio::ip::address::from_string(ip), port_timestamp);
endpoint_timing = asio::ip::tcp::endpoint(
@ -135,6 +142,7 @@ int main(int argc, char **argv)
asio::ip::address::from_string(ip), port_iqdata);
socket_map.connect(endpoint_map);
socket_detection.connect(endpoint_detection);
socket_track.connect(endpoint_track);
socket_timestamp.connect(endpoint_timestamp);
socket_timing.connect(endpoint_timing);
socket_iqdata.connect(endpoint_iqdata);
@ -175,6 +183,16 @@ int main(int argc, char **argv)
tree["process"]["detection"]["nCentroid"] >> nCentroid;
Centroid *centroid = new Centroid(nCentroid, nCentroid, 1/tCpi);
// setup process tracker
uint8_t m, n, nDelete;
double maxAcc;
std::string smooth;
tree["process"]["tracker"]["initiate"]["M"] >> m;
tree["process"]["tracker"]["initiate"]["N"] >> n;
tree["process"]["tracker"]["delete"] >> nDelete;
tree["process"]["tracker"]["initiate"]["maxAcc"] >> maxAcc;
Tracker *tracker = new Tracker(m, n, nDelete, tCpi, maxAcc);
// setup process spectrum analyser
double spectrumBandwidth = 2000;
SpectrumAnalyser *spectrumAnalyser = new SpectrumAnalyser(nSamples, spectrumBandwidth);
@ -204,8 +222,8 @@ int main(int argc, char **argv)
std::string jsonTiming;
std::vector<uint64_t> time;
// setup output signal
std::string jsonIqData;
// setup output json
std::string mapJson, detectionJson, jsonTracker, jsonIqData;
// run process
std::thread t2([&]{
@ -226,29 +244,33 @@ int main(int argc, char **argv)
buffer1->unlock();
buffer2->unlock();
timing_helper(timing_name, timing_time, time, "extract_buffer");
// spectrum
spectrumAnalyser->process(x);
timing_helper(timing_name, timing_time, time, "spectrum");
// clutter filter
if (!filter->process(x, y))
{
continue;
}
timing_helper(timing_name, timing_time, time, "clutter_filter");
// ambiguity process
map = ambiguity->process(x, y);
map->set_metrics();
timing_helper(timing_name, timing_time, time, "ambiguity_processing");
// detection process
detection1 = cfarDetector1D->process(map);
detection2 = centroid->process(detection1);
detection = interpolate->process(detection2, map);
timing_helper(timing_name, timing_time, time, "detector");
// tracker process
// track = tracker->process(detection, time[0]/1000);
// timing_helper(timing_name, timing_time, time, "tracker");
// output IqData meta data
jsonIqData = x->to_json(time[0]/1000);
for (int i = 0; i < (jsonIqData.size() + MTU - 1) / MTU; i++)
@ -269,7 +291,6 @@ int main(int argc, char **argv)
subdata = mapJson.substr(i * MTU, MTU);
socket_map.write_some(asio::buffer(subdata, subdata.size()), err);
}
// output detection data
detectionJson = detection->to_json(time[0]/1000);
detectionJson = detection->delay_bin_to_km(detectionJson, fs);
@ -281,7 +302,15 @@ int main(int argc, char **argv)
delete detection;
delete detection1;
delete detection2;
// output tracker data
// jsonTracker = track->to_json(time[0]/1000);
// for (int i = 0; i < (jsonTracker.size() + MTU - 1) / MTU; i++)
// {
// subdata = jsonTracker.substr(i * MTU, MTU);
// socket_track.write_some(asio::buffer(subdata, subdata.size()), err);
// }
// output radar data timer
timing_helper(timing_name, timing_time, time, "output_radar_data");

View file

@ -16,6 +16,13 @@ Detection::Detection(std::vector<double> _delay, std::vector<double> _doppler, s
snr = _snr;
}
Detection::Detection(double _delay, double _doppler, double _snr)
{
delay.push_back(_delay);
doppler.push_back(_doppler);
snr.push_back(_snr);
}
std::vector<double> Detection::get_delay()
{
return delay;

View file

@ -29,6 +29,12 @@ public:
/// @return The object.
Detection(std::vector<double> delay, std::vector<double> doppler, std::vector<double> snr);
/// @brief Constructor for single detection.
/// @param delay Detection in delay (bins).
/// @param doppler Detection in Doppler (Hz).
/// @return The object.
Detection(double delay, double doppler, double snr);
/// @brief Get detections in delay.
/// @return Detections in delay (bins).
std::vector<double> get_delay();
@ -46,6 +52,7 @@ public:
size_t get_nDetections();
/// @brief Generate JSON of the detections and metadata.
/// @param timestamp Current time (POSIX ms).
/// @return JSON string.
std::string to_json(uint64_t timestamp);

163
src/data/Track.cpp Normal file
View file

@ -0,0 +1,163 @@
#include "Track.h"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h"
const uint64_t Track::MAX_INDEX = 65535;
const std::string Track::STATE_ACTIVE = "ACTIVE";
const std::string Track::STATE_TENTATIVE = "TENTATIVE";
const std::string Track::STATE_COASTING = "COASTING";
// constructor
Track::Track()
{
iNext = 0;
}
Track::~Track()
{
}
std::string Track::uint2hex(uint64_t number)
{
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << std::uppercase << std::hex << number;
return oss.str();
}
void Track::set_state(uint64_t index, std::string _state)
{
state.at(index) = _state;
}
void Track::set_current(uint64_t index, Detection smoothed)
{
current.at(index) = smoothed;
associated.at(index).push_back(smoothed);
}
void Track::set_acceleration(uint64_t index, double _acceleration)
{
acceleration.at(index) = _acceleration;
}
void Track::set_nInactive(uint64_t index, uint64_t n)
{
nInactive.at(index) = n;
}
uint64_t Track::get_nActive()
{
uint64_t n = 0;
for (size_t i = 0; i < id.size(); i++)
{
if (state.at(i) == STATE_ACTIVE)
{
n++;
}
}
return n;
}
uint64_t Track::get_nTentative()
{
uint64_t n = 0;
for (size_t i = 0; i < id.size(); i++)
{
if (state.at(i) == STATE_TENTATIVE)
{
n++;
}
}
return n;
}
uint64_t Track::get_n()
{
return id.size();
}
Detection Track::get_current(uint64_t index)
{
return current.at(index);
}
double Track::get_acceleration(uint64_t index)
{
return acceleration.at(index);
}
std::string Track::get_state(uint64_t index)
{
return state.at(index);
}
uint64_t Track::get_nInactive(uint64_t index)
{
return nInactive.at(index);
}
uint64_t Track::add(Detection initial)
{
id.push_back(uint2hex(iNext));
state.push_back(STATE_TENTATIVE);
current.push_back(initial);
acceleration.push_back(0);
std::vector<Detection> _associated;
_associated.push_back(initial);
associated.push_back(_associated);
nInactive.push_back(0);
iNext++;
if (iNext >= MAX_INDEX)
{
iNext = 0;
}
return id.size()-1;
}
void Track::remove(uint64_t index)
{
id.erase(id.begin() + index);
state.erase(state.begin() + index);
current.erase(current.begin() + index);
acceleration.erase(acceleration.begin() + index);
associated.erase(associated.begin() + index);
}
std::string Track::to_json(uint64_t timestamp)
{
rapidjson::Document document;
document.SetObject();
rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
// store array for non-tentative tracks
rapidjson::Value arrayId(rapidjson::kArrayType);
rapidjson::Value value;
for (int i = 0; i < get_n(); i++)
{
if (state.at(i) != STATE_TENTATIVE)
{
value = rapidjson::StringRef(id.at(i).c_str());
arrayId.PushBack(value, allocator);
}
}
document.AddMember("timestamp", timestamp, allocator);
document.AddMember("n", get_n(), allocator);
document.AddMember("nActive", get_nActive(), allocator);
document.AddMember("nTentative", get_nTentative(), allocator);
document.AddMember("id", arrayId, allocator);
rapidjson::StringBuffer strbuf;
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
writer.SetMaxDecimalPlaces(2);
document.Accept(writer);
return strbuf.GetString();
}

154
src/data/Track.h Normal file
View file

@ -0,0 +1,154 @@
/// @file Track.h
/// @class Track
/// @brief A class to store track data.
/// @details The ID is 4 digit hexadecimal with 16^4 = 65536 combinations.
/// @details The state can be TENTATIVE, ACTIVE or COASTING.
/// @details Associated detections use null detections when no updates.
/// @author 30hours
#ifndef TRACK_H
#define TRACK_H
#include <Detection.h>
#include <stdint.h>
#include <vector>
#include <string>
#include <memory>
class Track
{
private:
/// @brief Track ID (4 digit alpha-numeric).
//std::unique_ptr<std::vector<std::string>> id;
std::vector<std::string> id;
/// @brief Current state (see VALID_STATE).
std::vector<std::string> state;
/// @brief Curent track position.
std::vector<Detection> current;
/// @brief Current acceleration (Hz/s).
std::vector<double> acceleration;
/// @brief Associated detections in track.
std::vector<std::vector<Detection>> associated;
/// @brief Number of updates the track has been tentative/coasting.
/// @details Forms criteria for track deletion.
std::vector<uint64_t> nInactive;
/// @brief Next valid track index.
uint64_t iNext;
/// @brief Maximum integer index to wrap around.
static const uint64_t MAX_INDEX;
/// @brief String for state ACTIVE.
static const std::string STATE_ACTIVE;
/// @brief String for state TENTATIVE.
static const std::string STATE_TENTATIVE;
/// @brief String for state COASTING.
static const std::string STATE_COASTING;
public:
/// @brief Constructor.
/// @return The object.
Track();
/// @brief Destructor.
/// @return Void.
~Track();
/// @brief Convert an unsigned int to hexadecimal.
/// @details Max number is 16^4 = 65536 before wrap around.
/// @param number Number to convert to hexadecimal.
/// @return hex Hexadecimal number.
std::string uint2hex(uint64_t number);
/// @brief Set the state of a track.
/// @param index Index of track to change.
/// @param state Updated state.
/// @return Void.
void set_state(uint64_t index, std::string state);
/// @brief Set the current track position.
/// @details Use to update smoothed current position.
/// @param index Index of track to change.
/// @param smoothed Updated state.
/// @return Void.
void set_current(uint64_t index, Detection smoothed);
/// @brief Set the current acceleration.
/// @param index Index of track to change.
/// @param acceleration Updated acceleration.
/// @return Void.
void set_acceleration(uint64_t index, double acceleration);
/// @brief Set the current inactivity.
/// @param index Index of track to change.
/// @param n Updated inactivity index.
/// @return Void.
void set_nInactive(uint64_t index, uint64_t n);
/// @brief Get number of active tracks.
/// @return Number of active tracks.
uint64_t get_nActive();
/// @brief Get number of tentative tracks.
/// @return Number of tentative tracks.
uint64_t get_nTentative();
/// @brief Get number of total tracks.
/// @return Number of total tracks.
uint64_t get_n();
/// @brief Get current track position for track index.
/// @return Current detection.
Detection get_current(uint64_t index);
/// @brief Get current acceleration for track index.
/// @return Current acceleration (Hz/s).
double get_acceleration(uint64_t index);
/// @brief Get current state for track index.
/// @return Current state.
std::string get_state(uint64_t index);
/// @brief Get number of updates track has been tentative/coasting.
/// @return Number of updates track has been tentative/coasting.
uint64_t get_nInactive(uint64_t index);
/// @brief Update an associated detection.
/// @param index Index of track to change.
/// @param update New associated detection.
/// @return Void.
void update(uint64_t index, Detection update);
/// @brief Add track to the track set.
/// @param initial Initial Detection.
/// @details ID is incremented automatically.
/// @details Initial state is always TENTATIVE.
/// @return Index of last track.
uint64_t add(Detection initial);
/// @brief Remove track based on index.
/// @param index Index of track to remove.
/// @return Void.
void remove(uint64_t index);
/// @brief Generate JSON of the map and metadata.
/// @param timestamp Current time (POSIX ms).
/// @return JSON string.
std::string to_json(uint64_t timestamp);
/// @brief Append the map to a save file.
/// @param json JSON string of map and metadata.
/// @param path Path of file to save.
/// @return True is save is successful.
bool save(std::string json, std::string path);
};
#endif

View file

@ -0,0 +1,135 @@
#include "Tracker.h"
#include <iostream>
// constructor
Tracker::Tracker(uint32_t _m, uint32_t _n, uint32_t _nDelete, double _cpi, double _maxAccInit)
{
m = _m;
n = _n;
nDelete = _nDelete;
cpi = _cpi;
maxAccInit = _maxAccInit;
timestamp = 0;
double resolutionAcc = 1 * (1/(cpi*cpi));
uint16_t nAcc = (int)maxAccInit/resolutionAcc;
for (int i = 0; i < 2*nAcc+1; i++)
{
accInit.push_back(resolutionAcc*(i-nAcc));
}
Track track{};
}
Tracker::~Tracker()
{
}
Track *Tracker::process(Detection *detection, uint64_t currentTime)
{
timestamp = currentTime;
doNotInitiate.clear();
for (size_t i = 0; i < detection->get_nDetections(); i++)
{
doNotInitiate.push_back(false);
}
if (track.get_n() > 0)
{
update(detection, timestamp);
}
initiate(detection);
return &track;
}
void Tracker::update(Detection *detection, uint64_t current)
{
std::vector<double> delay = detection->get_delay();
std::vector<double> doppler = detection->get_doppler();
std::vector<double> snr = detection->get_snr();
// init
double delayPredict, dopplerPredict;
double acc;
uint32_t nRemove = 0;
std::string state;
// get time between detections
double T = (double) current - timestamp;
// loop over each track
for (int i = 0; i < track.get_n(); i++)
{
// predict next position
Detection detectionCurrent = track.get_current(i);
double delayTrack = detectionCurrent.get_delay().front();
double dopplerTrack = detectionCurrent.get_doppler().front();
acc = track.get_acceleration(i);
delayPredict = delayTrack+(1/(2*3.14))*(dopplerTrack+0.5*acc*T*T);
dopplerPredict = dopplerTrack+acc*T;
Detection prediction(delayPredict, dopplerPredict, 0);
// loop over detections to associate
for (size_t j = 0; j < detection->get_nDetections(); j++)
{
// associate detections
if (delay[j] > delayPredict-1 &&
delay[j] < delayPredict+1 &&
doppler[j] > dopplerPredict-(2/cpi) &&
doppler[j] < dopplerPredict+(2/cpi))
{
Detection associated(delay[j], doppler[j], snr[j]);
track.set_current(i, associated);
state = "ACTIVE";
track.set_state(i, state);
track.set_acceleration(i, (doppler[j]-dopplerTrack)/T);
track.set_nInactive(i, 0);
doNotInitiate[j] = true;
break;
// todo: check for track promotion
}
}
// update state if no detections associated
track.set_current(i, prediction);
if (track.get_state(i) == "ACTIVE")
{
state = "COASTING";
track.set_state(i, state);
}
track.set_nInactive(i, track.get_nInactive(i)+1);
// remove if tentative or coasting too long
if (track.get_nInactive(i) > nDelete)
{
track.remove(i+nRemove);
nRemove++;
}
}
}
void Tracker::initiate(Detection *detection)
{
std::vector<double> delay = detection->get_delay();
std::vector<double> doppler = detection->get_doppler();
std::vector<double> snr = detection->get_snr();
uint64_t index;
// loop over new detections
for (size_t i = 0; i < detection->get_nDetections(); i++)
{
// skip if detection used in update
if (doNotInitiate.at(i))
{
continue;
}
// add tentative detection for each acc
for (size_t j = 0; j < accInit.size(); j++)
{
Detection detectionCurrent(delay[i], doppler[i], snr[i]);
index = track.add(detectionCurrent);
track.set_acceleration(index, accInit[j]);
}
}
}

View file

@ -0,0 +1,77 @@
/// @file Tracker.h
/// @class Tracker
/// @brief A class to implement a bistatic tracker.
/// @details Key functions are update, initiate, smooth and remove.
/// @details Update before initiate to avoid duplicate tracks.
/// @author 30hours
/// @todo Add smoothing capability.
/// @todo Fix units up.
#ifndef TRACKER_H
#define TRACKER_H
#include <Detection.h>
#include <Track.h>
#include <stdint.h>
class Tracker
{
private:
/// @brief Track initiation constant for M of N detections.
uint32_t m;
/// @brief Track initiation constant for M of N detections.
uint32_t n;
/// @brief Number of missed predictions to delete a tentative track.
uint32_t nDelete;
/// @brief True CPI time for acceleration resolution(s).
double cpi;
/// @brief Maximum acceleration to initiate track (Hz/s).
double maxAccInit;
/// @brief Acceleration values to initiate track (Hz/s).
std::vector<double> accInit;
/// @brief Index of detections already updated.
std::vector<bool> doNotInitiate;
/// @brief POSIX timestamp of last update (ms).
uint64_t timestamp;
/// @brief Track data.
Track track;
public:
/// @brief Constructor.
/// @param delayMin Minimum clutter filter delay (bins).
/// @param delayMax Maximum clutter filter delay (bins).
/// @param nSamples Number of samples per CPI.
/// @return The object.
Tracker(uint32_t m, uint32_t n, uint32_t nDelete, double cpi, double maxAccInit);
/// @brief Destructor.
/// @return Void.
~Tracker();
/// @brief Run through key functions of tracker.
/// @param detection Detection data for last CPI.
/// @param timestamp POSIX timestamp (ms).
/// @return Pointer to track data.
Track *process(Detection *detection, uint64_t timestamp);
/// @brief Update tracks by associating detections.
/// @param detection Detection data for last CPI.
/// @param timestamp POSIX timestamp (ms).
/// @return Void.
void update(Detection *detection, uint64_t timestamp);
/// @brief Initiate new tentative tracks from detections.
/// @param detection Detection data for last CPI.
/// @return Void.
void initiate(Detection *detection);
};
#endif