mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-21 16:12:01 +00:00
104 lines
2.4 KiB
C#
104 lines
2.4 KiB
C#
namespace splitter.algo;
|
|
|
|
public sealed class KalmanTracker
|
|
{
|
|
// State vector: [x, y, vx, vy]
|
|
private float[] _state = new float[4];
|
|
|
|
// Covariance matrix 4x4
|
|
private float[,] _p = new float[4, 4];
|
|
|
|
// Process noise (constant)
|
|
private const float _q = 1e-3f;
|
|
|
|
// Measurement noise (dynamic)
|
|
private float _r = 1e-1f;
|
|
|
|
public float CurrentNoise => _r;
|
|
|
|
// Identity matrix
|
|
private static readonly float[,] _i =
|
|
{
|
|
{1,0,0,0},
|
|
{0,1,0,0},
|
|
{0,0,1,0},
|
|
{0,0,0,1}
|
|
};
|
|
|
|
public Point2f? LastMeasurement { get; private set; }
|
|
|
|
public void Reset(Point2f initial)
|
|
{
|
|
_state[0] = initial.X;
|
|
_state[1] = initial.Y;
|
|
_state[2] = 0;
|
|
_state[3] = 0;
|
|
|
|
// Large initial uncertainty
|
|
for (var i = 0; i < 4; i++)
|
|
for (var j = 0; j < 4; j++)
|
|
_p[i, j] = (i == j) ? 1f : 0f;
|
|
}
|
|
|
|
public void SetMeasurementNoise(float r)
|
|
{
|
|
_r = r;
|
|
}
|
|
|
|
public Point2f Update(Point2f? measurement)
|
|
{
|
|
// --- PREDICTION ---
|
|
// State transition:
|
|
// x' = x + vx
|
|
// y' = y + vy
|
|
_state[0] += _state[2];
|
|
_state[1] += _state[3];
|
|
|
|
// Update covariance
|
|
AddProcessNoise();
|
|
|
|
if (measurement.HasValue)
|
|
{
|
|
// --- MEASUREMENT UPDATE ---
|
|
var z = measurement.Value;
|
|
|
|
// Innovation y = z - Hx
|
|
var yx = z.X - _state[0];
|
|
var yy = z.Y - _state[1];
|
|
|
|
// Innovation covariance S = P + R
|
|
var Sx = _p[0, 0] + _r;
|
|
var Sy = _p[1, 1] + _r;
|
|
|
|
// Kalman gain K = P / S
|
|
var Kx0 = _p[0, 0] / Sx;
|
|
var Kx1 = _p[1, 1] / Sy;
|
|
|
|
// Update state
|
|
_state[0] += Kx0 * yx;
|
|
_state[1] += Kx1 * yy;
|
|
|
|
// Velocity correction (helps reduce jitter)
|
|
_state[2] += 0.1f * Kx0 * yx;
|
|
_state[3] += 0.1f * Kx1 * yy;
|
|
|
|
// Update covariance: P = (I - K)P
|
|
_p[0, 0] *= (1 - Kx0);
|
|
_p[1, 1] *= (1 - Kx1);
|
|
}
|
|
|
|
LastMeasurement = measurement;
|
|
|
|
return new Point2f(_state[0], _state[1]);
|
|
}
|
|
|
|
private void AddProcessNoise()
|
|
{
|
|
// Add small noise to diagonal of covariance
|
|
_p[0, 0] += _q;
|
|
_p[1, 1] += _q;
|
|
_p[2, 2] += _q;
|
|
_p[3, 3] += _q;
|
|
}
|
|
}
|