use ados_protocol::framebus::BoundingBox;
use super::scoring::center;
use super::TrackerConfig;
#[derive(Debug, Clone)]
pub(super) struct BoxKalman {
pub(super) pos: [f32; 4],
pub(super) vel: [f32; 4],
pub(super) p_pos: [f32; 4],
pub(super) p_vel: [f32; 4],
pub(super) p_pv: [f32; 4],
pub(super) measurement_noise: f32,
pub(super) process_noise: f32,
pub(super) max_velocity: f32,
}
impl BoxKalman {
pub(super) fn new(b: &BoundingBox, cfg: &TrackerConfig) -> Self {
let (cx, cy) = center(b);
Self {
pos: [cx, cy, b.width, b.height],
vel: [0.0; 4],
p_pos: [cfg.measurement_noise; 4],
p_vel: [1_000.0; 4],
p_pv: [0.0; 4],
measurement_noise: cfg.measurement_noise,
process_noise: cfg.process_noise,
max_velocity: cfg.max_velocity,
}
}
pub(super) fn predict(&mut self) {
let q = self.process_noise;
for i in 0..4 {
self.pos[i] += self.vel[i];
let pp = self.p_pos[i];
let pv = self.p_vel[i];
let ppv = self.p_pv[i];
self.p_pos[i] = pp + 2.0 * ppv + pv + q;
self.p_pv[i] = ppv + pv;
self.p_vel[i] = pv + q;
}
}
pub(super) fn update(&mut self, b: &BoundingBox) {
let (cx, cy) = center(b);
let meas = [cx, cy, b.width, b.height];
let r = self.measurement_noise;
let vmax = self.max_velocity;
for (i, &m) in meas.iter().enumerate() {
let s = self.p_pos[i] + r; let k_pos = self.p_pos[i] / s; let k_vel = self.p_pv[i] / s; let innov = m - self.pos[i];
self.pos[i] += k_pos * innov;
let new_vel = (self.vel[i] + k_vel * innov).clamp(-vmax, vmax);
self.vel[i] = new_vel;
let pp = self.p_pos[i];
let ppv = self.p_pv[i];
self.p_pos[i] = pp - k_pos * pp;
self.p_pv[i] = ppv - k_pos * ppv;
self.p_vel[i] -= k_vel * ppv;
}
}
pub(super) fn center_pos_std(&self) -> f32 {
let var = (self.p_pos[0] + self.p_pos[1]) * 0.5;
var.max(0.0).sqrt()
}
pub(super) fn bbox(&self) -> BoundingBox {
let w = self.pos[2].max(1.0);
let h = self.pos[3].max(1.0);
BoundingBox {
x: self.pos[0] - w / 2.0,
y: self.pos[1] - h / 2.0,
width: w,
height: h,
}
}
}