### Extended Kalman Filter Example Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Demonstrates the setup and simulation loop for an Extended Kalman Filter with nonlinear prediction and correction steps. Requires `rand` and `rand_distr` crates for noise generation. ```rust const NUM_STATES: usize = 3; const NUM_OBSERVATIONS: usize = 1; fn example() { let builder = extended::builder::KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut measurement = builder.observations().build::(); // The time step of our simulation. const DELTA_T: f32 = 0.1; // Set up the initial state vector. filter.state_vector_mut().apply(|vec| { vec.set_row(0, 0.0); vec.set_row(1, 0.0); vec.set_row(2, 1.0); vec.set_row(3, 1.0); }); // Set up the initial estimate covariance as an identity matrix. filter.estimate_covariance_mut().make_identity(); // Set up the process noise covariance matrix as an identity matrix. measurement .measurement_noise_covariance_mut() .make_scalar(1.0); // Set up the measurement noise covariance. measurement.measurement_noise_covariance_mut().apply(|mat| { mat.set_value(1.0); // matrix is 1x1 }); // Simulate for step in 1..=100 { let time = step as f32 * DELTA_T; // Update the system transition Jacobian matrix. filter.state_transition_mut().apply(|mat| { mat.make_identity(); mat.set(0, 2, DELTA_T); mat.set(1, 3, DELTA_T); }); // Perform a nonlinear prediction step. filter.predict_nonlinear(|state, next| { // Simple constant velocity model. next[0] = state[0] + state[2] * DELTA_T; next[1] = state[1] + state[3] * DELTA_T; next[2] = state[2]; next[3] = state[3]; }); // Prepare a measurement. measurement.measurement_vector_mut().apply(|vec| { // Noise setup. let mut rng = rand::thread_rng(); let measurement_noise = Normal::new(0.0, 0.5).unwrap(); // Perform a noisy measurement of the (simulated) position. let z = (time.powi(2) + time.powi(2)).sqrt(); let noise = measurement_noise.sample(&mut rng); vec.set_value(z + noise); }); // Update the observation Jacobian. measurement.observation_matrix_mut().apply(|mat| { let x = filter.state_vector().get_row(0); let y = filter.state_vector().get_row(1); let norm = (x.powi(2) + y.powi(2)).sqrt(); let dx = x / norm; let dy = y / norm; mat.set_col(0, dx); mat.set_col(1, dy); mat.set_col(2, 0.0); mat.set_col(3, 0.0); }); // Apply nonlinear correction step. filter.correct_nonlinear(&mut measurement, |state, observation| { // Transform the state into an observation. let x = state.get_row(0); let y = state.get_row(1); let z = (x.powi(2) + y.powi(2)).sqrt(); observation.set_value(z); }); } } ``` -------------------------------- ### Run Fixed-Point Example Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Command to run the fixed-point example, which enables `I16F16` type support for fixed-point arithmetic, similar to the libfixkalman C library. Requires the `fixed` crate feature. ```shell cargo run --example fixed --features=fixed ``` -------------------------------- ### Run Gravity Constant Estimation Example Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Execute the gravity simulation example to estimate the Earth's gravitational constant. This requires the 'std' feature, and optionally 'libm' for floating-point math. ```shell cargo run --example gravity --features=std ``` ```shell cargo run --example gravity --features=std,libm ``` -------------------------------- ### Run Radar-2D Example Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Command to run the radar-2D example, which simulates radar measurements of a moving object using the Extended Kalman Filter. Requires the `std` feature. ```shell cargo run --example radar-2d --features=std ``` -------------------------------- ### Install cargo-fuzz Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Installs the cargo-fuzz tool, which is required for running fuzzing targets. This command should be run once. ```shell cargo +nightly install cargo-fuzz ``` -------------------------------- ### Unscented Kalman Filter (UKF) Builder API Source: https://context7.com/sunsided/minikalman-rs/llms.txt Demonstrates the creation and usage of an Unscented Kalman Filter using the builder API in Rust. This example shows how to configure the filter, process nonlinear motion models, and correct estimates with simulated measurements. ```APIDOC ## Unscented Kalman Filter (UKF) — Builder API `UnscentedKalman` uses `2N+1` sigma points instead of Jacobians to propagate estimates through nonlinear transformations. Use `unscented::builder::KalmanFilterBuilder` to create the filter and observation. ```rust use minikalman::prelude::*; use minikalman::unscented::builder::KalmanFilterBuilder; const NUM_STATES: usize = 4; // px, py, vx, vy const NUM_SIGMA: usize = 2 * NUM_STATES + 1; // 9 sigma points const NUM_OBSERVATIONS: usize = 2; // range and bearing const DELTA_T: f32 = 0.1; let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build::(); let mut measurement = builder.observations().build::(); // Initial state and covariances filter.state_vector_mut().apply(|x| { x[0] = 0.0; x[1] = 0.0; x[2] = 1.0; x[3] = 1.0; }); filter.estimate_covariance_mut().make_identity(); filter.direct_process_noise_mut().make_scalar(0.05); measurement.measurement_noise_covariance_mut().apply(|r| { r.set_at(0, 0, 0.3); // range noise r.set_at(1, 1, 0.1); // bearing noise }); for step in 1..=20 { let time = step as f32 * DELTA_T; // Propagate each sigma point through nonlinear motion model filter.predict_nonlinear(|s| { let px = s.as_matrix().get_at(0, 0); let py = s.as_matrix().get_at(1, 0); let vx = s.as_matrix().get_at(2, 0); let vy = s.as_matrix().get_at(3, 0); s.as_matrix_mut().set_at(0, 0, px + vx * DELTA_T); s.as_matrix_mut().set_at(1, 0, py + vy * DELTA_T); // velocities remain constant }); // Simulated measurements: range and bearing to a fixed beacon at (2, 2) let bx = 2.0f32; let by = 2.0f32; measurement.measurement_vector_mut().apply(|z| { let dx = time - bx; let dy = time * 0.5 - by; z[0] = (dx * dx + dy * dy).sqrt() + 0.05; // noisy range z[1] = dy.atan2(dx) + 0.02; // noisy bearing }); // Apply sigma-point based correction filter.correct_sigma_point(&mut measurement, |sigma_pred, observed| { for j in 0..NUM_SIGMA { let px = sigma_pred[j]; let py = sigma_pred[NUM_SIGMA + j]; let dx = px - bx; let dy = py - by; let norm = (dx * dx + dy * dy).sqrt().max(1e-6); observed[j] = norm; observed[NUM_SIGMA + j] = dy.atan2(dx); } }); } let state = filter.state_vector(); println!("UKF: px={:.2}, py={:.2}, vx={:.2}, vy={:.2}", state[0], state[1], state[2], state[3]); ``` ``` -------------------------------- ### Unscented Kalman Filter (UKF) Builder API Source: https://context7.com/sunsided/minikalman-rs/llms.txt Use `unscented::builder::KalmanFilterBuilder` to create an Unscented Kalman Filter for nonlinear systems. This example shows initialization, prediction, and correction steps with simulated measurements. ```rust use minikalman::prelude::*; use minikalman::unscented::builder::KalmanFilterBuilder; const NUM_STATES: usize = 4; // px, py, vx, vy const NUM_SIGMA: usize = 2 * NUM_STATES + 1; // 9 sigma points const NUM_OBSERVATIONS: usize = 2; // range and bearing const DELTA_T: f32 = 0.1; let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build::(); let mut measurement = builder.observations().build::(); // Initial state and covariances filter.state_vector_mut().apply(|x| { x[0] = 0.0; x[1] = 0.0; x[2] = 1.0; x[3] = 1.0; }); filter.estimate_covariance_mut().make_identity(); filter.direct_process_noise_mut().make_scalar(0.05); measurement.measurement_noise_covariance_mut().apply(|r| { r.set_at(0, 0, 0.3); // range noise r.set_at(1, 1, 0.1); // bearing noise }); for step in 1..=20 { let time = step as f32 * DELTA_T; // Propagate each sigma point through nonlinear motion model filter.predict_nonlinear(|s| { let px = s.as_matrix().get_at(0, 0); let py = s.as_matrix().get_at(1, 0); let vx = s.as_matrix().get_at(2, 0); let vy = s.as_matrix().get_at(3, 0); s.as_matrix_mut().set_at(0, 0, px + vx * DELTA_T); s.as_matrix_mut().set_at(1, 0, py + vy * DELTA_T); // velocities remain constant }); // Simulated measurements: range and bearing to a fixed beacon at (2, 2) let bx = 2.0f32; let by = 2.0f32; measurement.measurement_vector_mut().apply(|z| { let dx = time - bx; let dy = time * 0.5 - by; z[0] = (dx * dx + dy * dy).sqrt() + 0.05; // noisy range z[1] = dy.atan2(dx) + 0.02; // noisy bearing }); // Apply sigma-point based correction filter.correct_sigma_point(&mut measurement, |sigma_pred, observed| { for j in 0..NUM_SIGMA { let px = sigma_pred[j]; let py = sigma_pred[NUM_SIGMA + j]; let dx = px - bx; let dy = py - by; let norm = (dx * dx + dy * dy).sqrt().max(1e-6); observed[j] = norm; observed[NUM_SIGMA + j] = dy.atan2(dx); } }); } let state = filter.state_vector(); println!("UKF: px={:.2}, py={:.2}, vx={:.2}, vy={:.2}", state[0], state[1], state[2], state[3]); ``` -------------------------------- ### Get Symbol Context (Quick Reference) Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Use the `context` tool for a 360-degree view of a specific symbol. ```javascript gitnexus_context({name: "validateUser"}) ``` -------------------------------- ### Get Full Context of a Symbol Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Retrieve all callers, callees, and execution flows a specific symbol participates in. ```javascript gitnexus_context({name: "symbolName"}) ``` -------------------------------- ### Initialize Kalman Filter and Observation Builders Source: https://context7.com/sunsided/minikalman-rs/llms.txt Initialize `RegularKalmanBuilder` and `RegularObservationBuilder` using static buffers. Ensure all necessary matrix and vector buffers are correctly wired. ```rust let mut filter = RegularKalmanBuilder::new::( StateTransitionMatrixMutBuffer::from(unsafe { filter_A.as_mut_slice() }), StateVectorBuffer::from(unsafe { filter_x.as_mut_slice() }), EstimateCovarianceMatrixBuffer::from(unsafe { filter_P.as_mut_slice() }), DirectProcessNoiseCovarianceMatrixBuffer::from(unsafe { filter_Q.as_mut_slice() }), PredictedStateEstimateVectorBuffer::from(unsafe { filter_temp_x.as_mut_slice() }), TemporaryStateMatrixBuffer::from(unsafe { filter_temp_P.as_mut_slice() }), ); let mut observation = RegularObservationBuilder::new::( ObservationMatrixMutBuffer::from(unsafe { obs_H.as_mut_slice() }), MeasurementVectorBuffer::from(unsafe { obs_z.as_mut_slice() }), MeasurementNoiseCovarianceMatrixBuffer::from(unsafe { obs_R.as_mut_slice() }), InnovationVectorBuffer::from(unsafe { obs_y.as_mut_slice() }), InnovationCovarianceMatrixBuffer::from(unsafe { obs_S.as_mut_slice() }), KalmanGainMatrixBuffer::from(unsafe { obs_K.as_mut_slice() }), TemporaryResidualCovarianceInvertedMatrixBuffer::from(unsafe { obs_temp_S_inv.as_mut_slice() }), TemporaryHPMatrixBuffer::from(unsafe { obs_temp_HP.as_mut_slice() }), TemporaryPHTMatrixBuffer::from(unsafe { obs_temp_PHt.as_mut_slice() }), TemporaryKHPMatrixBuffer::from(unsafe { obs_temp_KHP.as_mut_slice() }), ); ``` -------------------------------- ### Configure and Run Kalman Filter Loop Source: https://context7.com/sunsided/minikalman-rs/llms.txt Configure the filter and observation matrices, then execute the predict and correct steps. This snippet demonstrates setting identity matrices and applying measurements. ```rust // Configure matrices, then run filter loop filter.state_transition_mut().apply(|a| a.make_identity()); filter.estimate_covariance_mut().apply(|p| p.make_identity()); observation.observation_matrix_mut().apply(|h| h.set_at(0, 0, 1.0)); observation.measurement_noise_covariance_mut().apply(|r| r.set_at(0, 0, 0.5)); filter.predict(); observation.measurement_vector_mut().apply(|z| z[0] = 42.0); filter.correct(&mut observation); ``` -------------------------------- ### Quick Reference for GitNexus Tools Source: https://github.com/sunsided/minikalman-rs/blob/main/CLAUDE.md A table summarizing the purpose and command syntax for common GitNexus tools, including query, context, impact, detect_changes, rename, and cypher. ```shell gitnexus_query({query: "auth validation"}) ``` ```shell gitnexus_context({name: "validateUser"}) ``` ```shell gitnexus_impact({target: "X", direction: "upstream"}) ``` ```shell gitnexus_detect_changes({scope: "staged"}) ``` ```shell gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true}) ``` ```shell gitnexus_cypher({query: "MATCH ..."}) ``` -------------------------------- ### Run All Tests (minikalman) Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Executes all tests for the minikalman crate with default features enabled. ```shell cargo test -p minikalman ``` -------------------------------- ### Run no_std Tests (minikalman) Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Runs tests for the minikalman crate with no_std compatibility, using 'libm' and 'alloc' features. ```shell cargo test -p minikalman --no-default-features --features libm,alloc ``` -------------------------------- ### Build and Configure Regular Kalman Filter Source: https://context7.com/sunsided/minikalman-rs/llms.txt Use KalmanFilterBuilder to create a heap-allocated regular Kalman filter. Configure state transition, control, observation matrices, and initial states. Suitable for non-embedded targets. ```rust use minikalman::prelude::*; use minikalman::regular::builder::KalmanFilterBuilder; const NUM_STATES: usize = 3; // position, velocity, acceleration const NUM_CONTROLS: usize = 1; // one control input (e.g., applied force) const NUM_OBSERVATIONS: usize = 1; // one sensor (e.g., position) fn main() { let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut control = builder.controls().build::(); let mut measurement = builder.observations().build::(); // State transition matrix A (constant velocity model with time step T=1) filter.state_transition_mut().apply(|a| { a.set_at(0, 0, 1.0); a.set_at(0, 1, 1.0); a.set_at(0, 2, 0.5); a.set_at(1, 0, 0.0); a.set_at(1, 1, 1.0); a.set_at(1, 2, 1.0); a.set_at(2, 0, 0.0); a.set_at(2, 1, 0.0); a.set_at(2, 2, 1.0); }); // Initial state: position=0, velocity=0, acceleration=6 (first guess) filter.state_vector_mut().apply(|x| { x[0] = 0.0; x[1] = 0.0; x[2] = 6.0; }); // Initial estimate covariance (uncertainty) filter.estimate_covariance_mut().apply(|p| p.make_identity()); // Observation matrix H: we only observe position (state[0]) measurement.observation_matrix_mut().apply(|h| { h.set_at(0, 0, 1.0); h.set_at(0, 1, 0.0); h.set_at(0, 2, 0.0); }); // Measurement noise covariance R measurement.measurement_noise_covariance_mut().apply(|r| { r.set_at(0, 0, 0.5); }); // Control matrix B control.control_matrix_mut().apply(|b| { b.set_at(0, 0, 0.0); b.set_at(1, 0, 0.0); b.set_at(2, 0, 1.0); }); control.process_noise_covariance_mut().make_identity(); let observations: [f32; 5] = [0.0, 4.905, 19.62, 44.145, 78.48]; for (t, &obs) in observations.iter().enumerate() { // 1. Predict next state filter.predict(); // 2. Apply control input (zero here) control.control_vector_mut().apply(|u| u[0] = 0.0); filter.control(&mut control); // 3. Set measurement and correct measurement.measurement_vector_mut().apply(|z| z[0] = obs); filter.correct(&mut measurement); // 4. Read corrected state let state = filter.state_vector(); println!("t={t}: pos={:.2}, vel={:.2}, acc={:.2}", state[0], state[1], state[2]); } // Expected final acceleration estimate converging toward ~9.81 m/s² } ``` -------------------------------- ### Find Code by Concept (Quick Reference) Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Use the `query` tool to find code related to a specific concept. ```javascript gitnexus_query({query: "auth validation"}) ``` -------------------------------- ### Run Property-Based Tests (minikalman) Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Executes property-based tests for the minikalman crate, requiring the 'std' feature. Use for testing matrix and filter implementations. ```shell cargo test -p minikalman --features std --test proptest_matrix ``` ```shell cargo test -p minikalman --features std --test proptest_filter ``` -------------------------------- ### EKF Implementation for Nonlinear Systems Source: https://context7.com/sunsided/minikalman-rs/llms.txt This snippet shows a full Extended Kalman Filter cycle for a nonlinear system. It includes initialization, state transition Jacobian updates, nonlinear prediction, observation Jacobian updates, simulated measurements, and nonlinear correction. Ensure Jacobians are manually updated for nonlinear models. ```rust use minikalman::prelude::*; use minikalman::extended::builder::KalmanFilterBuilder; const NUM_STATES: usize = 4; // x, y, vx, vy const NUM_OBSERVATIONS: usize = 1; const DELTA_T: f32 = 0.1; let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut measurement = builder.observations().build::(); // Initial state: position (0,0), velocity (1, 0.5) filter.state_vector_mut().apply(|x| { x[0] = 0.0; x[1] = 0.0; x[2] = 1.0; x[3] = 0.5; }); filter.estimate_covariance_mut().make_identity(); filter.direct_process_noise_mut().make_scalar(0.01); measurement.measurement_noise_covariance_mut().apply(|r| r.set_at(0, 0, 0.5)); for step in 0..50 { // Update Jacobian of state transition (constant velocity model: identity + dt on off-diag) filter.state_transition_mut().apply(|a| { a.make_identity(); a.set_at(0, 2, DELTA_T); a.set_at(1, 3, DELTA_T); }); // Nonlinear prediction: propagate state through f(x) filter.predict_nonlinear(|state, next| { next[0] = state[0] + state[2] * DELTA_T; next[1] = state[1] + state[3] * DELTA_T; next[2] = state[2]; next[3] = state[3]; }); // Update Jacobian of observation function h(x) = sqrt(x² + y²) measurement.observation_matrix_mut().apply(|h| { let x = filter.state_vector()[0]; let y = filter.state_vector()[1]; let norm = (x * x + y * y).sqrt().max(1e-6); h.set_at(0, 0, x / norm); h.set_at(0, 1, y / norm); h.set_at(0, 2, 0.0); h.set_at(0, 3, 0.0); }); // Simulated noisy range measurement let true_x = step as f32 * DELTA_T; let true_y = step as f32 * DELTA_T * 0.5; measurement.measurement_vector_mut().apply(|z| { z[0] = (true_x * true_x + true_y * true_y).sqrt() + 0.1; }); // Nonlinear correction: provide observation function h(x) filter.correct_nonlinear(&mut measurement, |state, obs| { let x = state[0]; let y = state[1]; obs[0] = (x * x + y * y).sqrt(); }); } let state = filter.state_vector(); println!("EKF final: x={:.2}, y={:.2}, vx={:.2}, vy={:.2}", state[0], state[1], state[2], state[3]); ``` -------------------------------- ### Run Fuzz Targets (minikalman) Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Executes individual fuzz targets for the minikalman crate. These targets require a nightly toolchain and are located in `crates/minikalman/fuzz/`. ```shell cd crates/minikalman/fuzz cargo +nightly fuzz run matrix_cholesky ``` ```shell cargo +nightly fuzz run matrix_mult ``` ```shell cargo +nightly fuzz run regular_filter ``` ```shell cargo +nightly fuzz run extended_filter -- -max_total_time=60 ``` -------------------------------- ### Fixed-Point Arithmetic (I16F16) Source: https://context7.com/sunsided/minikalman-rs/llms.txt Illustrates the use of fixed-point arithmetic with the `I16F16` type for Kalman filtering, enabling operation on microcontrollers without an FPU. The API remains identical to the floating-point version. ```APIDOC ## Fixed-Point Arithmetic (`I16F16`) When the `fixed` feature is enabled, the `I16F16` type (Q16.16) can replace `f32` everywhere, enabling the filter to run on FPU-less microcontrollers. The API is identical. ```rust use minikalman::prelude::*; // re-exports I16F16 under `fixed` feature use minikalman::regular::builder::KalmanFilterBuilder; const NUM_STATES: usize = 3; const NUM_OBSERVATIONS: usize = 1; // Swap f32 → I16F16; everything else is identical let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut measurement = builder.observations().build::(); filter.state_vector_mut().apply(|x| { x[0] = I16F16::ZERO; // position x[1] = I16F16::ZERO; // velocity x[2] = I16F16::from_num(6.0); // initial acceleration guess }); filter.state_transition_mut().apply(|a| { const T: I16F16 = I16F16::ONE; a.set_at(0, 0, I16F16::ONE); a.set_at(0, 1, T); a.set_at(0, 2, I16F16::from_num(0.5) * T * T); a.set_at(1, 1, I16F16::ONE); a.set_at(1, 2, T); a.set_at(2, 2, I16F16::ONE); }); filter.estimate_covariance_mut().apply(|p| { p.set_at(0, 0, I16F16::from_num(0.1)); p.set_at(1, 1, I16F16::ONE); p.set_at(2, 2, I16F16::ONE); }); measurement.observation_matrix_mut().apply(|h| { h.set_at(0, 0, I16F16::ONE); }); measurement.measurement_noise_covariance_mut().apply(|r| { r.set_at(0, 0, I16F16::from_num(0.5)); }); // Run the filter with Q16.16 fixed-point values let observations: [I16F16; 3] = [ I16F16::from_num(0.0), I16F16::from_num(4.905), I16F16::from_num(19.62), ]; for &z in &observations { filter.predict(); measurement.measurement_vector_mut().apply(|v| v[0] = z); filter.correct(&mut measurement); } // Acceleration estimate converges toward ~9.81 println!("g estimate: {}", filter.state_vector()[2]); ``` ``` -------------------------------- ### Check Staged Changes (Quick Reference) Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Use the `detect_changes` tool with the `staged` scope to check changes before committing. ```javascript gitnexus_detect_changes({scope: "staged"}) ``` -------------------------------- ### Cargo.toml Configuration for Mini Kalman Source: https://context7.com/sunsided/minikalman-rs/llms.txt Configure Mini Kalman dependencies in Cargo.toml, specifying features like 'std', 'fixed', or 'libm' for different build targets and capabilities. ```toml # Cargo.toml [dependencies] # Default: no_std + alloc + libm minikalman = "0.7" # std + fixed-point support minikalman = { version = "0.7", features = ["std", "fixed"] } # Fully no_std, no heap minikalman = { version = "0.7", default-features = false, features = ["libm"] } ``` -------------------------------- ### Build Kalman Filter with Allocations Source: https://github.com/sunsided/minikalman-rs/blob/main/README.md Use this builder when the 'alloc' or 'std' crate feature is enabled for heap-allocated buffers. It simplifies filter creation for non-embedded use cases. ```rust const NUM_STATES: usize = 3; const NUM_CONTROLS: usize = 2; const NUM_OBSERVATIONS: usize = 1; fn example() { let builder = regular::builder::KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut control = builder.controls().build::(); let mut measurement = builder.observations().build::(); // Set up the system dynamics, control matrices, observation matrices, ... // Filter! loop { // Update your control vector(s). control.control_vector_mut().apply(|u| { u[0] = 0.0; u[1] = 1.0; }); // Update your measurement vectors. measurement.measurement_vector_mut().apply(|z| { z[0] = 42.0; }); // Update prediction (without controls). filter.predict(); // Apply any controls to the prediction. filter.control(&mut control); // Apply any measurements. filter.correct(&mut measurement); // Access the state let state = filter.state_vector(); let covariance = filter.system_covariance(); } } ``` -------------------------------- ### Declare Static Buffers for Kalman Filter Matrices Source: https://context7.com/sunsided/minikalman-rs/llms.txt Use `impl_buffer_*!` macros to declare static arrays for Kalman filter matrices in a `no_std` environment. These are essential for bare-metal targets. ```rust #![allow(non_snake_case, non_upper_case_globals)] use minikalman::buffers::types::* use minikalman::prelude::* use minikalman::regular::{RegularKalmanBuilder, RegularObservationBuilder}; const NUM_STATES: usize = 3; const NUM_OBSERVATIONS: usize = 1; // Declare static buffers for filter matrices impl_buffer_x!(static mut filter_x, NUM_STATES, f32, 0.0); impl_buffer_A!(static mut filter_A, NUM_STATES, f32, 0.0); impl_buffer_P!(static mut filter_P, NUM_STATES, f32, 0.0); impl_buffer_Q_direct!(static mut filter_Q, NUM_STATES, f32, 0.0); impl_buffer_temp_x!(static mut filter_temp_x, NUM_STATES, f32, 0.0); impl_buffer_temp_P!(static mut filter_temp_P, NUM_STATES, f32, 0.0); // Declare static buffers for observation matrices impl_buffer_z!(static mut obs_z, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_H!(static mut obs_H, NUM_OBSERVATIONS, NUM_STATES, f32, 0.0); impl_buffer_R!(static mut obs_R, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_y!(static mut obs_y, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_S!(static mut obs_S, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_K!(static mut obs_K, NUM_STATES, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_temp_S_inv!(static mut obs_temp_S_inv, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_temp_HP!(static mut obs_temp_HP, NUM_OBSERVATIONS, NUM_STATES, f32, 0.0); impl_buffer_temp_PHt!(static mut obs_temp_PHt, NUM_STATES, NUM_OBSERVATIONS, f32, 0.0); impl_buffer_temp_KHP!(static mut obs_temp_KHP, NUM_STATES, f32, 0.0); ``` -------------------------------- ### Assess Impact Before Editing (Quick Reference) Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Use the `impact` tool to determine the blast radius of a potential edit. ```javascript gitnexus_impact({target: "X", direction: "upstream"}) ``` -------------------------------- ### Run Tests and Fuzzing with Cargo Source: https://context7.com/sunsided/minikalman-rs/llms.txt Execute tests and fuzzing routines using Cargo commands. Ensure the correct features and test targets are specified for different testing scenarios, including `no_std` and property-based tests. ```shell # Run all tests (default features: alloc + libm) cargo test -p minikalman # Run property-based matrix and filter tests (requires std) cargo test -p minikalman --features std --test proptest_matrix cargo test -p minikalman --features std --test proptest_filter # Run fully no_std (with alloc and libm only) cargo test -p minikalman --no-default-features --features libm,alloc # Run the gravity estimation example cargo run --example gravity --features=std # Run with fixed-point arithmetic cargo run --example fixed --features=fixed,std # Run 2D radar EKF example cargo run --example radar-2d --features=std # Run 2D radar UKF example using builder API cargo run --example radar-2d-ukf-builder --features=std # Fuzz testing (requires nightly + cargo-fuzz) cargo +nightly install cargo-fuzz cd crates/minikalman/fuzz cargo +nightly fuzz run regular_filter cargo +nightly fuzz run extended_filter -- -max_total_time=60 cargo +nightly fuzz run matrix_cholesky cargo +nightly fuzz run matrix_mult ``` -------------------------------- ### Debug Execution Flows Source: https://github.com/sunsided/minikalman-rs/blob/main/CLAUDE.md Use `gitnexus_query` to find execution flows related to an error or symptom, then `gitnexus_context` to examine suspect functions. For detailed tracing, use the provided `gitnexus://` resource. ```javascript gitnexus_query({query: ""}) ``` ```javascript gitnexus_context({name: ""}) ``` ```shell READ gitnexus://repo/kalman-rs/process/{processName} ``` -------------------------------- ### Apply Control Input to Kalman Filter (Rust) Source: https://context7.com/sunsided/minikalman-rs/llms.txt Use `filter.control()` to apply a control input `u` via the control matrix `B`. This updates the state and covariance: `x += B·u`. A `Control` object is created using `builder.controls().build()`. ```rust use minikalman::prelude::*; use minikalman::regular::builder::KalmanFilterBuilder; const NUM_STATES: usize = 3; const NUM_CONTROLS: usize = 1; const NUM_OBSERVATIONS: usize = 1; let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut control = builder.controls().build::(); let mut measurement = builder.observations().build::(); filter.state_transition_mut().apply(|a| { a.set_at(0, 0, 1.0); a.set_at(0, 1, 1.0); a.set_at(0, 2, 0.5); a.set_at(1, 1, 1.0); a.set_at(1, 2, 1.0); a.set_at(2, 2, 1.0); }); filter.estimate_covariance_mut().apply(|p| p.make_identity()); // B maps the scalar control u into the acceleration component control.control_matrix_mut().apply(|b| { b.set_at(0, 0, 0.0); b.set_at(1, 0, 0.0); b.set_at(2, 0, 1.0); }); control.process_noise_covariance_mut().apply(|q| q.make_scalar(0.01)); measurement.observation_matrix_mut().apply(|h| h.set_at(0, 0, 1.0)); measurement.measurement_noise_covariance_mut().apply(|r| r.set_at(0, 0, 1.0)); // Apply a braking deceleration command of -0.5 m/s² let deceleration = -0.5f32; control.control_vector_mut().apply(|u| u[0] = deceleration); filter.predict(); filter.control(&mut control); // x += B·u, updates state covariance too measurement.measurement_vector_mut().apply(|z| z[0] = 3.5); filter.correct(&mut measurement); println!("Position: {:.2}", filter.state_vector()[0]); println!("Velocity: {:.2}", filter.state_vector()[1]); ``` -------------------------------- ### Run Impact Analysis Before Editing Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Before modifying any symbol, run impact analysis to understand the blast radius and report risks. ```javascript gitnexus_impact({target: "symbolName", direction: "upstream"}) ``` -------------------------------- ### Fixed-Point Arithmetic (I16F16) Kalman Filter Source: https://context7.com/sunsided/minikalman-rs/llms.txt When the `fixed` feature is enabled, `I16F16` (Q16.16) can replace `f32` for running Kalman filters on FPU-less microcontrollers. The API remains identical. ```rust use minikalman::prelude::*; use minikalman::regular::builder::KalmanFilterBuilder; const NUM_STATES: usize = 3; const NUM_OBSERVATIONS: usize = 1; // Swap f32 → I16F16; everything else is identical let builder = KalmanFilterBuilder::::default(); let mut filter = builder.build(); let mut measurement = builder.observations().build::(); filter.state_vector_mut().apply(|x| { x[0] = I16F16::ZERO; // position x[1] = I16F16::ZERO; // velocity x[2] = I16F16::from_num(6.0); // initial acceleration guess }); filter.state_transition_mut().apply(|a| { const T: I16F16 = I16F16::ONE; a.set_at(0, 0, I16F16::ONE); a.set_at(0, 1, T); a.set_at(0, 2, I16F16::from_num(0.5) * T * T); a.set_at(1, 1, I16F16::ONE); a.set_at(1, 2, T); a.set_at(2, 2, I16F16::ONE); }); filter.estimate_covariance_mut().apply(|p| { p.set_at(0, 0, I16F16::from_num(0.1)); p.set_at(1, 1, I16F16::ONE); p.set_at(2, 2, I16F16::ONE); }); measurement.observation_matrix_mut().apply(|h| { h.set_at(0, 0, I16F16::ONE); }); measurement.measurement_noise_covariance_mut().apply(|r| { r.set_at(0, 0, I16F16::from_num(0.5)); }); // Run the filter with Q16.16 fixed-point values let observations: [I16F16; 3] = [ I16F16::from_num(0.0), I16F16::from_num(4.905), I16F16::from_num(19.62), ]; for &z in &observations { filter.predict(); measurement.measurement_vector_mut().apply(|v| v[0] = z); filter.correct(&mut measurement); } // Acceleration estimate converges toward ~9.81 println!("g estimate: {}", filter.state_vector()[2]); ``` -------------------------------- ### Analyze Codebase and Update Index Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Re-run analyze to update the GitNexus index after committing code changes. ```bash npx gitnexus analyze ``` -------------------------------- ### Cargo.toml Profile Configuration for STM32 Source: https://github.com/sunsided/minikalman-rs/blob/main/xbuild-tests/stm32/README.md This configuration is specific to embedded projects and moves standard Cargo.toml profile settings to the workspace configuration. It sets panic behavior to 'abort' and enables optimizations for release builds. ```toml [profile.dev] panic = "abort" [profile.release] panic = "abort" codegen-units = 1 # better optimizations debug = true # symbols are nice, and they don't increase the size on Flash lto = true # better optimizations ``` -------------------------------- ### Execute Custom Graph Queries Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Use the `cypher` tool for custom graph queries. ```javascript gitnexus_cypher({query: "MATCH ..."}) ``` -------------------------------- ### Check All Detected Changes Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md After refactoring, verify that only the expected files have been modified. ```javascript gitnexus_detect_changes({scope: "all"}) ``` -------------------------------- ### Compute Buffer Sizes with Macros Source: https://context7.com/sunsided/minikalman-rs/llms.txt Use these compile-time macros to determine the required element count for various Kalman filter buffers. This is useful for static array declarations or manual memory allocation in `no_std` environments. ```rust use minikalman::* const N: usize = 4; // states const M: usize = 2; // observations const C: usize = 1; // controls // Each macro returns the number of f32 elements required assert_eq!(size_buffer_A!(N), 16); // N×N state transition assert_eq!(size_buffer_P!(N), 16); // N×N estimate covariance assert_eq!(size_buffer_x!(N), 4); // N×1 state vector assert_eq!(size_buffer_Q_direct!(N), 16); // N×N process noise assert_eq!(size_buffer_Q_control!(C), 1); // C×C control noise assert_eq!(size_buffer_B!(N, C), 4); // N×C control matrix assert_eq!(size_buffer_u!(C), 1); // C×1 control vector assert_eq!(size_buffer_H!(M, N), 8); // M×N observation matrix assert_eq!(size_buffer_R!(M), 4); // M×M measurement noise assert_eq!(size_buffer_z!(M), 2); // M×1 measurement vector assert_eq!(size_buffer_y!(M), 2); // M×1 innovation vector assert_eq!(size_buffer_S!(M), 4); // M×M innovation covariance assert_eq!(size_buffer_K!(N, M), 8); // N×M Kalman gain assert_eq!(size_buffer_temp_x!(N), 4); // N×1 temp prediction assert_eq!(size_buffer_temp_P!(N), 16); // N×N temp covariance assert_eq!(size_buffer_temp_BQ!(N, C), 4); // N×C temp B×Q assert_eq!(size_buffer_temp_S_inv!(M), 4); // M×M temp S-inverse assert_eq!(size_buffer_temp_HP!(M, N), 8); // M×N temp H×P assert_eq!(size_buffer_temp_PHt!(N, M), 8); // N×M temp P×Hᵀ assert_eq!(size_buffer_temp_KHP!(N), 16); // N×N temp K×H×P // UKF sigma-point buffer sizes const NUM_SIGMA: usize = 2 * N + 1; assert_eq!(size_buffer_sigma_points!(N), N * NUM_SIGMA); // N×(2N+1) assert_eq!(size_buffer_sigma_weights!(N), NUM_SIGMA); // 2N+1 assert_eq!(size_buffer_sigma_observed!(M, N), M * NUM_SIGMA); // M×(2N+1) assert_eq!(size_buffer_cross_covariance!(N, M), N * M); // N×M ``` -------------------------------- ### Detect Changes Before Committing Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Verify that your changes only affect expected symbols and execution flows before committing. ```javascript gitnexus_detect_changes() ``` -------------------------------- ### Query Code by Concept Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Find execution flows related to a specific concept or symptom, returning process-grouped results ranked by relevance. ```javascript gitnexus_query({query: "concept"}) ``` -------------------------------- ### Analyze Impact Before Refactoring Source: https://github.com/sunsided/minikalman-rs/blob/main/CLAUDE.md Before extracting or splitting code, use `gitnexus_context` to understand all incoming/outgoing references and `gitnexus_impact` to identify external callers. This ensures a safe refactoring process. ```javascript gitnexus_context({name: "target"}) ``` ```javascript gitnexus_impact({target: "target", direction: "upstream"}) ``` -------------------------------- ### Detect Changes for Regressions Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Identify changes made to your branch compared to a base reference, useful for tracking regressions. ```javascript gitnexus_detect_changes({scope: "compare", base_ref: "main"}) ``` -------------------------------- ### Analyze Codebase with Embeddings Source: https://github.com/sunsided/minikalman-rs/blob/main/AGENTS.md Update the GitNexus index, preserving existing embeddings by adding the `--embeddings` flag. ```bash npx gitnexus analyze --embeddings ```