use kfilter::measurement::{LinearMeasurement, Measurement};
use kfilter::ukf::UKFLinearNoInput;
use kfilter::{KalmanFilter, KalmanPredict, KalmanUpdate};
use nalgebra::{Matrix2, SMatrix, SVector, Vector2};
fn main() {
println!("=== UKF Nonlinear Measurement Examples ===\n");
example_linear_measurement();
println!();
example_range_measurement();
println!();
example_range_bearing_measurement();
}
fn example_linear_measurement() {
println!("--- Example 1: Linear Measurement ---");
let mut ukf: UKFLinearNoInput<f64, 2, 5> = UKFLinearNoInput::new_linear(
Matrix2::new(1.0, 0.1, 0.0, 1.0), Matrix2::identity() * 0.01, Vector2::new(1.0, 0.5), Matrix2::identity() * 0.5, );
println!("Initial state: pos={:.3}, vel={:.3}", ukf.state()[0], ukf.state()[1]);
let h = Matrix2::new(
1.0, 0.0, 0.0, 0.0, );
let r = Matrix2::new(
0.1, 0.0, 0.0, 1e6, );
for step in 1..=5 {
ukf.predict().unwrap();
let true_position = ukf.state()[0];
let noisy_position = true_position + 0.05 * (step as f64 % 2.0 - 0.5);
let measurement = Vector2::new(noisy_position, 0.0);
let meas_model = LinearMeasurement::new(h, r, measurement);
ukf.update(&meas_model).unwrap();
println!(
"Step {}: pos={:.3}, vel={:.3}, meas={:.3}",
step,
ukf.state()[0],
ukf.state()[1],
noisy_position
);
}
}
struct RangeMeasurement {
measurement: Vector2<f64>,
covariance: Matrix2<f64>,
}
impl RangeMeasurement {
fn new(range: f64, noise_variance: f64) -> Self {
Self {
measurement: Vector2::new(range, 0.0),
covariance: Matrix2::new(noise_variance, 0.0, 0.0, 1e6),
}
}
}
impl Measurement<f64, 2, 2> for RangeMeasurement {
fn predict(&self, state: &SVector<f64, 2>) -> SVector<f64, 2> {
let range = (state[0].powi(2) + state[1].powi(2)).sqrt();
Vector2::new(range, 0.0)
}
fn measurement(&self) -> &SVector<f64, 2> {
&self.measurement
}
fn covariance(&self) -> &SMatrix<f64, 2, 2> {
&self.covariance
}
fn set_measurement(&mut self, z: SVector<f64, 2>) {
self.measurement = z;
}
}
fn example_range_measurement() {
println!("--- Example 2: Nonlinear Range Measurement ---");
let mut ukf: UKFLinearNoInput<f64, 2, 5> = UKFLinearNoInput::new_linear(
Matrix2::identity(), Matrix2::identity() * 0.01, Vector2::new(3.0, 4.0), Matrix2::identity() * 0.5, );
let initial_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
println!(
"Initial state: x={:.3}, y={:.3}, range={:.3}",
ukf.state()[0],
ukf.state()[1],
initial_range
);
for step in 1..=5 {
ukf.predict().unwrap();
let true_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
let noisy_range = true_range + 0.1 * ((step as f64).sin());
let meas_model = RangeMeasurement::new(noisy_range, 0.05);
ukf.update(&meas_model).unwrap();
let estimated_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
println!(
"Step {}: x={:.3}, y={:.3}, true_range={:.3}, meas={:.3}, est_range={:.3}",
step,
ukf.state()[0],
ukf.state()[1],
true_range,
noisy_range,
estimated_range
);
}
}
struct RangeBearingMeasurement {
measurement: Vector2<f64>,
covariance: Matrix2<f64>,
}
impl RangeBearingMeasurement {
fn new(range: f64, bearing: f64, range_noise: f64, bearing_noise: f64) -> Self {
Self {
measurement: Vector2::new(range, bearing),
covariance: Matrix2::new(range_noise, 0.0, 0.0, bearing_noise),
}
}
}
impl Measurement<f64, 2, 2> for RangeBearingMeasurement {
fn predict(&self, state: &SVector<f64, 2>) -> SVector<f64, 2> {
let range = (state[0].powi(2) + state[1].powi(2)).sqrt();
let bearing = state[1].atan2(state[0]);
Vector2::new(range, bearing)
}
fn measurement(&self) -> &SVector<f64, 2> {
&self.measurement
}
fn covariance(&self) -> &SMatrix<f64, 2, 2> {
&self.covariance
}
fn set_measurement(&mut self, z: SVector<f64, 2>) {
self.measurement = z;
}
}
fn example_range_bearing_measurement() {
println!("--- Example 3: Range and Bearing Measurement ---");
let mut ukf: UKFLinearNoInput<f64, 2, 5> = UKFLinearNoInput::new_linear(
Matrix2::new(1.0, 0.0, 0.0, 1.0), Matrix2::identity() * 0.01, Vector2::new(3.0, 4.0), Matrix2::identity() * 1.0, );
let initial_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
let initial_bearing = ukf.state()[1].atan2(ukf.state()[0]);
println!(
"Initial state: x={:.3}, y={:.3}, range={:.3}, bearing={:.3} rad ({:.1}°)",
ukf.state()[0],
ukf.state()[1],
initial_range,
initial_bearing,
initial_bearing.to_degrees()
);
for step in 1..=5 {
ukf.predict().unwrap();
let true_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
let true_bearing = ukf.state()[1].atan2(ukf.state()[0]);
let noisy_range = true_range + 0.1 * ((step as f64 * 0.5).sin());
let noisy_bearing = true_bearing + 0.05 * ((step as f64).cos());
let meas_model = RangeBearingMeasurement::new(
noisy_range,
noisy_bearing,
0.05, 0.03, );
ukf.update(&meas_model).unwrap();
let est_range = (ukf.state()[0].powi(2) + ukf.state()[1].powi(2)).sqrt();
let est_bearing = ukf.state()[1].atan2(ukf.state()[0]);
println!(
"Step {}: x={:.3}, y={:.3}, range={:.3}, bearing={:.2} rad ({:.0}°)",
step,
ukf.state()[0],
ukf.state()[1],
est_range,
est_bearing,
est_bearing.to_degrees()
);
}
}